@@ -203,26 +203,45 @@ def update(
203203 kwargs = {"Tags" : table_tags } if table_tags else {}
204204
205205 table_name = _get_table_name (online_config , config , table_instance )
206+ # Check if table already exists before attempting to create
207+ # This is required for environments where IAM roles don't have
208+ # dynamodb:CreateTable permissions (e.g., Terraform-managed tables)
209+ table_exists = False
206210 try :
207- dynamodb_resource .create_table (
208- TableName = table_name ,
209- KeySchema = [{"AttributeName" : "entity_id" , "KeyType" : "HASH" }],
210- AttributeDefinitions = [
211- {"AttributeName" : "entity_id" , "AttributeType" : "S" }
212- ],
213- BillingMode = "PAY_PER_REQUEST" ,
214- ** kwargs ,
211+ dynamodb_client .describe_table (TableName = table_name )
212+ table_exists = True
213+ do_tag_updates [table_name ] = True
214+ logger .info (
215+ f"DynamoDB table { table_name } already exists, skipping creation"
215216 )
216-
217217 except ClientError as ce :
218- do_tag_updates [table_name ] = True
219-
220- # If the table creation fails with ResourceInUseException,
221- # it means the table already exists or is being created.
222- # Otherwise, re-raise the exception
223- if ce .response ["Error" ]["Code" ] != "ResourceInUseException" :
218+ if ce .response ["Error" ]["Code" ] != "ResourceNotFoundException" :
219+ # If it's not a "table not found" error, re-raise
224220 raise
225221
222+ # Only attempt to create table if it doesn't exist
223+ if not table_exists :
224+ try :
225+ dynamodb_resource .create_table (
226+ TableName = table_name ,
227+ KeySchema = [{"AttributeName" : "entity_id" , "KeyType" : "HASH" }],
228+ AttributeDefinitions = [
229+ {"AttributeName" : "entity_id" , "AttributeType" : "S" }
230+ ],
231+ BillingMode = "PAY_PER_REQUEST" ,
232+ ** kwargs ,
233+ )
234+ logger .info (f"Created DynamoDB table { table_name } " )
235+
236+ except ClientError as ce :
237+ do_tag_updates [table_name ] = True
238+
239+ # If the table creation fails with ResourceInUseException,
240+ # it means the table already exists or is being created.
241+ # Otherwise, re-raise the exception
242+ if ce .response ["Error" ]["Code" ] != "ResourceInUseException" :
243+ raise
244+
226245 for table_instance in tables_to_keep :
227246 table_name = _get_table_name (online_config , config , table_instance )
228247 dynamodb_client .get_waiter ("table_exists" ).wait (TableName = table_name )
@@ -712,13 +731,22 @@ def _delete_table_idempotent(
712731 table .delete ()
713732 logger .info (f"Dynamo table { table_name } was deleted" )
714733 except ClientError as ce :
734+ error_code = ce .response ["Error" ]["Code" ]
735+
715736 # If the table deletion fails with ResourceNotFoundException,
716737 # it means the table has already been deleted.
717- # Otherwise, re-raise the exception
718- if ce .response ["Error" ]["Code" ] != "ResourceNotFoundException" :
719- raise
720- else :
738+ if error_code == "ResourceNotFoundException" :
721739 logger .warning (f"Trying to delete table that doesn't exist: { table_name } " )
740+ # If it fails with AccessDeniedException, the IAM role doesn't have
741+ # dynamodb:DeleteTable permission (e.g., Terraform-managed tables)
742+ elif error_code == "AccessDeniedException" :
743+ logger .warning (
744+ f"Unable to delete table { table_name } due to insufficient permissions. "
745+ f"The table may need to be deleted manually or via your infrastructure management tool (e.g., Terraform)."
746+ )
747+ else :
748+ # Some other error, re-raise
749+ raise
722750
723751
724752def _to_resource_write_item (config , entity_key , features , timestamp ):
0 commit comments