diff --git a/CHANGELOG.md b/CHANGELOG.md index 4122169a2..dad836697 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,27 @@ Moto Changelog ============== +4.0.6 +----- +Docker Digest for 4.0.6: + + General: + * Moto can now be seeded, which will make identifiers deterministic. + See http://docs.getmoto.org/en/latest/docs/configuration/recorder/index.html + * The format for access-key and role ids has been changed, and is now generated using the same algorithm that AWS uses + + Miscellaneous: + * AWSLambda:add_permission() now properly handles the PrincipalOrgID-param + * DynamoDB:update_item() now validates duplicate UpdateExpressions + * EC2 now exposes instance types in the correct availability zones for us-west-1 (us-west-1a and us-west-1b) + * EC2 has various improvements around the handling of RouteTableAssociations + * Glue:get_tables() now supports the Expression-parameter + * Organizations:create_organization() now uses a default value for FeatureSet=ALL + * RDS:describe_db_subnet_groups() now returns the DBSubnetGroupArn-attribute + * S3:upload_file() now supports the ExtraArgs: ChecksumAlgorithm-parameter + * SSM:list_commands() now returns the DeliveryTimedOutCount-attribute + + 4.0.5 ----- Docker Digest for 4.0.5: _sha256:d18f760f3498b212b0c8c205c9c28c2b41e8c7a108f44e1bd1d7ee86dfc37c03_ diff --git a/IMPLEMENTATION_COVERAGE.md b/IMPLEMENTATION_COVERAGE.md index ecbbce210..86d399ab8 100644 --- a/IMPLEMENTATION_COVERAGE.md +++ b/IMPLEMENTATION_COVERAGE.md @@ -2878,20 +2878,20 @@ 20% implemented - [X] batch_create_partition -- [X] batch_delete_connection +- [ ] batch_delete_connection - [X] batch_delete_partition - [X] batch_delete_table -- [X] batch_delete_table_version +- [ ] batch_delete_table_version - [ ] batch_get_blueprints - [ ] batch_get_crawlers - [ ] batch_get_custom_entity_types - [ ] batch_get_dev_endpoints - [ ] batch_get_jobs -- [ ] batch_get_partition +- [X] batch_get_partition - [ ] batch_get_triggers - [ ] batch_get_workflows - [ ] batch_stop_job_run -- [ ] batch_update_partition +- [X] batch_update_partition - [ ] cancel_ml_task_run - [ ] cancel_statement - [ ] check_schema_version_validity @@ -4625,7 +4625,7 @@ ## rds
-28% implemented +29% implemented - [ ] add_role_to_db_cluster - [ ] add_role_to_db_instance @@ -4646,7 +4646,7 @@ - [ ] create_db_cluster_parameter_group - [X] create_db_cluster_snapshot - [X] create_db_instance -- [ ] create_db_instance_read_replica +- [X] create_db_instance_read_replica - [X] create_db_parameter_group - [ ] create_db_proxy - [ ] create_db_proxy_endpoint diff --git a/docs/docs/services/glue.rst b/docs/docs/services/glue.rst index 287b0f91e..82616c72b 100644 --- a/docs/docs/services/glue.rst +++ b/docs/docs/services/glue.rst @@ -26,20 +26,20 @@ glue |start-h3| Implemented features for this service |end-h3| - [X] batch_create_partition -- [X] batch_delete_connection +- [ ] batch_delete_connection - [X] batch_delete_partition - [X] batch_delete_table -- [X] batch_delete_table_version +- [ ] batch_delete_table_version - [ ] batch_get_blueprints - [ ] batch_get_crawlers - [ ] batch_get_custom_entity_types - [ ] batch_get_dev_endpoints - [ ] batch_get_jobs -- [ ] batch_get_partition +- [X] batch_get_partition - [ ] batch_get_triggers - [ ] batch_get_workflows - [ ] batch_stop_job_run -- [ ] batch_update_partition +- [X] batch_update_partition - [ ] cancel_ml_task_run - [ ] cancel_statement - [ ] check_schema_version_validity diff --git a/docs/docs/services/rds.rst b/docs/docs/services/rds.rst index 807dc9f4d..332187286 100644 --- a/docs/docs/services/rds.rst +++ b/docs/docs/services/rds.rst @@ -44,7 +44,7 @@ rds - [ ] create_db_cluster_parameter_group - [X] create_db_cluster_snapshot - [X] create_db_instance -- [ ] create_db_instance_read_replica +- [X] create_db_instance_read_replica - [X] create_db_parameter_group - [ ] create_db_proxy - [ ] create_db_proxy_endpoint diff --git a/moto/glue/models.py b/moto/glue/models.py index 71158b89d..a16eb7021 100644 --- a/moto/glue/models.py +++ b/moto/glue/models.py @@ -605,6 +605,96 @@ class GlueBackend(BaseBackend): return response + def batch_delete_table(self, database_name, tables): + errors = [] + for table_name in tables: + try: + self.delete_table(database_name, table_name) + except TableNotFoundException: + errors.append( + { + "TableName": table_name, + "ErrorDetail": { + "ErrorCode": "EntityNotFoundException", + "ErrorMessage": "Table not found", + }, + } + ) + return errors + + def batch_get_partition(self, database_name, table_name, partitions_to_get): + table = self.get_table(database_name, table_name) + + partitions = [] + for values in partitions_to_get: + try: + p = table.get_partition(values=values["Values"]) + partitions.append(p.as_dict()) + except PartitionNotFoundException: + continue + return partitions + + def batch_create_partition(self, database_name, table_name, partition_input): + table = self.get_table(database_name, table_name) + + errors_output = [] + for part_input in partition_input: + try: + table.create_partition(part_input) + except PartitionAlreadyExistsException: + errors_output.append( + { + "PartitionValues": part_input["Values"], + "ErrorDetail": { + "ErrorCode": "AlreadyExistsException", + "ErrorMessage": "Partition already exists.", + }, + } + ) + return errors_output + + def batch_update_partition(self, database_name, table_name, entries): + table = self.get_table(database_name, table_name) + + errors_output = [] + for entry in entries: + part_to_update = entry["PartitionValueList"] + part_input = entry["PartitionInput"] + + try: + table.update_partition(part_to_update, part_input) + except PartitionNotFoundException: + errors_output.append( + { + "PartitionValueList": part_to_update, + "ErrorDetail": { + "ErrorCode": "EntityNotFoundException", + "ErrorMessage": "Partition not found.", + }, + } + ) + return errors_output + + def batch_delete_partition(self, database_name, table_name, parts): + table = self.get_table(database_name, table_name) + + errors_output = [] + for part_input in parts: + values = part_input.get("Values") + try: + table.delete_partition(values) + except PartitionNotFoundException: + errors_output.append( + { + "PartitionValues": values, + "ErrorDetail": { + "ErrorCode": "EntityNotFoundException", + "ErrorMessage": "Partition not found", + }, + } + ) + return errors_output + class FakeDatabase(BaseModel): def __init__(self, database_name, database_input): diff --git a/moto/glue/responses.py b/moto/glue/responses.py index ae99e8ada..e4eea8031 100644 --- a/moto/glue/responses.py +++ b/moto/glue/responses.py @@ -1,11 +1,6 @@ import json from moto.core.responses import BaseResponse -from .exceptions import ( - PartitionAlreadyExistsException, - PartitionNotFoundException, - TableNotFoundException, -) from .models import glue_backends @@ -119,20 +114,8 @@ class GlueResponse(BaseResponse): def batch_delete_table(self): database_name = self.parameters.get("DatabaseName") - errors = [] - for table_name in self.parameters.get("TablesToDelete"): - try: - self.glue_backend.delete_table(database_name, table_name) - except TableNotFoundException: - errors.append( - { - "TableName": table_name, - "ErrorDetail": { - "ErrorCode": "EntityNotFoundException", - "ErrorMessage": "Table not found", - }, - } - ) + tables = self.parameters.get("TablesToDelete") + errors = self.glue_backend.batch_delete_table(database_name, tables) out = {} if errors: @@ -166,15 +149,9 @@ class GlueResponse(BaseResponse): table_name = self.parameters.get("TableName") partitions_to_get = self.parameters.get("PartitionsToGet") - table = self.glue_backend.get_table(database_name, table_name) - - partitions = [] - for values in partitions_to_get: - try: - p = table.get_partition(values=values["Values"]) - partitions.append(p.as_dict()) - except PartitionNotFoundException: - continue + partitions = self.glue_backend.batch_get_partition( + database_name, table_name, partitions_to_get + ) return json.dumps({"Partitions": partitions}) @@ -191,22 +168,10 @@ class GlueResponse(BaseResponse): def batch_create_partition(self): database_name = self.parameters.get("DatabaseName") table_name = self.parameters.get("TableName") - table = self.glue_backend.get_table(database_name, table_name) - - errors_output = [] - for part_input in self.parameters.get("PartitionInputList"): - try: - table.create_partition(part_input) - except PartitionAlreadyExistsException: - errors_output.append( - { - "PartitionValues": part_input["Values"], - "ErrorDetail": { - "ErrorCode": "AlreadyExistsException", - "ErrorMessage": "Partition already exists.", - }, - } - ) + partition_input = self.parameters.get("PartitionInputList") + errors_output = self.glue_backend.batch_create_partition( + database_name, table_name, partition_input + ) out = {} if errors_output: @@ -228,25 +193,11 @@ class GlueResponse(BaseResponse): def batch_update_partition(self): database_name = self.parameters.get("DatabaseName") table_name = self.parameters.get("TableName") - table = self.glue_backend.get_table(database_name, table_name) + entries = self.parameters.get("Entries") - errors_output = [] - for entry in self.parameters.get("Entries"): - part_to_update = entry["PartitionValueList"] - part_input = entry["PartitionInput"] - - try: - table.update_partition(part_to_update, part_input) - except PartitionNotFoundException: - errors_output.append( - { - "PartitionValueList": part_to_update, - "ErrorDetail": { - "ErrorCode": "EntityNotFoundException", - "ErrorMessage": "Partition not found.", - }, - } - ) + errors_output = self.glue_backend.batch_update_partition( + database_name, table_name, entries + ) out = {} if errors_output: @@ -267,23 +218,11 @@ class GlueResponse(BaseResponse): def batch_delete_partition(self): database_name = self.parameters.get("DatabaseName") table_name = self.parameters.get("TableName") - table = self.glue_backend.get_table(database_name, table_name) + parts = self.parameters.get("PartitionsToDelete") - errors_output = [] - for part_input in self.parameters.get("PartitionsToDelete"): - values = part_input.get("Values") - try: - table.delete_partition(values) - except PartitionNotFoundException: - errors_output.append( - { - "PartitionValues": values, - "ErrorDetail": { - "ErrorCode": "EntityNotFoundException", - "ErrorMessage": "Partition not found", - }, - } - ) + errors_output = self.glue_backend.batch_delete_partition( + database_name, table_name, parts + ) out = {} if errors_output: