diff --git a/CHANGELOG.md b/CHANGELOG.md index ae68f5684ace..312483e41070 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,75 @@ Moto Changelog ============== +4.1.7 +----- +Docker Digest for 4.1.7: + + New Services: + * LakeFormation: + * batch_grant_permissions() + * batch_revoke_permissions() + * create_lf_tag() + * delete_lf_tag() + * deregister_resource() + * describe_resource() + * get_data_lake_settings() + * get_lf_tag() + * grant_permissions() + * list_data_cells_filter() + * list_lf_tags() + * list_permissions() + * list_resources() + * put_data_lake_settings() + * register_resource() + * revoke_permissions() + * RDS Data: + * execute_statement() + * Scheduler: + * create_schedule() + * create_schedule_group() + * delete_schedule() + * delete_schedule_group() + * get_schedule() + * get_schedule_group() + * list_schedule_groups() + * list_schedules() + * list_tags_for_resource() + * tag_resource() + * untag_resource() + * update_schedule() + + New Methods: + * Config: + * delete_retention_configuration() + * describe_retention_configurations() + * put_retention_configuration() + * EC2: + * get_launch_template_data() + * RDS: + * create_db_cluster_parameter_group() + * create_global_cluster() + * delete_db_cluster_parameter_group() + * delete_global_cluster() + * describe_db_cluster_parameter_groups() + * describe_db_cluster_parameters() + * describe_db_subnet_groups() + * describe_global_clusters() + * promote_read_replica_db_cluster() + * remove_from_global_cluster() + + Miscellaneous: + * APIGateway now allows semicolons in paths + * CloudFormation now supports Fn::ToJsonString + * DynamoDB: update_item() now supports number-sets in the AttributeUpdates-parameter + * DynamoDB: query() - The KeyConditionExpression now allows enclosing the sort key condition in brackets + * EC2: assign_private_ip_addresses() now supports the PrivateIpAddresses-argument + * ECR: put_image() now supports the imageManifestMediaType parameter + * ECS: run_task() now validates the provided launch-type + * Logs: put_subscription_filter() now supports KinesisStream destinations + * RDS: describe_db_clusters() now supports filtering by db-cluster-id and engine + * S3: head_object() now returns the AcceptRanges header + * SQS: Improvements in the deduplication-logic 4.1.6 ----- @@ -30,6 +99,7 @@ Docker Digest for 4.1.6: _sha256:36122dca33cb8f70d84734d1a0a6a5931f7a533fab3c58e delete_rule(), describe_rule(), disable_rule(), enable_rule(), list_rule_names_by_target(), list_rules(), list_targets_by_rule() * RDS: describe_db_clusters() now accepts an ARN as identifier * RDS: describe_db_snapshots() now returns the TagList-attribute + * RDS: describe_db_clusters() now returns the parameters KmsKeyId, NetworkType, DBSubnetGroupName, ScalingConfiguration * S3: get_object() now returns the AcceptRanges header * S3: head_bucket() now returns the region-header * SecretsManager now supports partial ARN's diff --git a/CLOUDFORMATION_COVERAGE.md b/CLOUDFORMATION_COVERAGE.md index 44f33f1c8dde..f74dc3052f61 100644 --- a/CLOUDFORMATION_COVERAGE.md +++ b/CLOUDFORMATION_COVERAGE.md @@ -1,3 +1,8 @@ +## Supported CloudFormation resources + +A list of all resources that can be created via CloudFormation. +Please let us know if you'd like support for a resource not yet listed here. + - AWS::ApiGateway::Deployment: - [x] create implemented - [ ] update implemented diff --git a/Makefile b/Makefile index fb85b99b2562..f9f3d8c6a51a 100644 --- a/Makefile +++ b/Makefile @@ -60,7 +60,7 @@ implementation_coverage: git commit IMPLEMENTATION_COVERAGE.md -m "Updating implementation coverage" || true cloudformation_coverage: - ./scripts/cloudformation_coverage.py > CLOUDFORMATION_COVERAGE.md + ./scripts/cloudformation_coverage.py git commit CLOUDFORMATION_COVERAGE.md -m "Updating CloudFormation coverage" || true coverage: implementation_coverage cloudformation_coverage diff --git a/docs/docs/services/cf.rst b/docs/docs/services/cf.rst new file mode 100644 index 000000000000..57ff415b69f3 --- /dev/null +++ b/docs/docs/services/cf.rst @@ -0,0 +1,193 @@ +.. _cloudformation_resources: + +================================== +Supported CloudFormation resources +================================== + + +A list of all resources that can be created via CloudFormation. +Please let us know if you'd like support for a resource not yet listed here. + +.. table:: + + +---------------------------------------+--------+--------+--------+-----------------------------------+ + | | Create | Update | Delete | Fn::GetAtt | + +=======================================+========+========+========+===================================+ + |AWS::ApiGateway::Deployment | x | | | - [ ] DeploymentId | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::ApiGateway::Method | x | | | | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::ApiGateway::Resource | x | | | - [ ] ResourceId | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::AutoScaling::AutoScalingGroup | x | x | x | - [ ] LaunchConfigurationName | + +---------------------------------------+--------+--------+--------+ - [ ] LaunchTemplateSpecification | + | | | | | - [ ] MixedInstancesPolicy | + +---------------------------------------+--------+--------+--------+ - [ ] PlacementGroup | + | | | | | - [ ] VPCZoneIdentifier | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::AutoScaling::LaunchConfiguration | x | x | x | | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::AutoScaling::ScheduledAction | x | | | - [ ] ScheduledActionName | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::Batch::ComputeEnvironment | x | | | - [ ] ComputeEnvironmentArn | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::Batch::JobDefinition | x | | | | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::Batch::JobQueue | x | | | - [ ] JobQueueArn | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::CloudFormation::Stack | x | x | x | | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::DataPipeline::Pipeline | x | | | | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::DynamoDB::Table | x | | x | - [x] Arn | + +---------------------------------------+--------+--------+--------+ - [x] StreamArn | + | | | | | | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::EC2::Instance | x | | x | - [x] AvailabilityZone | + +---------------------------------------+--------+--------+--------+ - [x] PrivateDnsName | + | | | | | - [x] PrivateIp | + +---------------------------------------+--------+--------+--------+ - [x] PublicDnsName | + | | | | | - [x] PublicIp | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::EC2::InternetGateway | x | | | - [ ] InternetGatewayId | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::EC2::LaunchTemplate | x | x | x | - [ ] LatestVersionNumber | + +---------------------------------------+--------+--------+--------+ - [ ] DefaultVersionNumber | + | | | | | | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::EC2::NatGateway | x | | | - [ ] NatGatewayId | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::EC2::NetworkInterface | x | | | - [x] SecondaryPrivateIpAddresses | + +---------------------------------------+--------+--------+--------+ - [x] PrimaryPrivateIpAddress | + | | | | | - [ ] Id | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::EC2::Route | x | | | | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::EC2::RouteTable | x | | | - [ ] RouteTableId | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::EC2::SecurityGroup | x | x | x | - [x] GroupId | + +---------------------------------------+--------+--------+--------+ - [ ] VpcId | + | | | | | | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::EC2::SecurityGroupIngress | x | | | | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::EC2::Subnet | x | | x | - [ ] VpcId | + +---------------------------------------+--------+--------+--------+ - [ ] NetworkAclAssociationId | + | | | | | - [ ] OutpostArn | + +---------------------------------------+--------+--------+--------+ - [x] AvailabilityZone | + | | | | | - [ ] SubnetId | + +---------------------------------------+--------+--------+--------+ - [ ] Ipv6CidrBlocks | + | | | | | | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::EC2::SubnetRouteTableAssociation | x | | | - [ ] Id | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::EC2::TransitGateway | x | | | - [ ] Id | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::EC2::VPC | x | | x | - [ ] VpcId | + +---------------------------------------+--------+--------+--------+ - [ ] CidrBlockAssociations | + | | | | | - [ ] CidrBlock | + +---------------------------------------+--------+--------+--------+ - [ ] DefaultNetworkAcl | + | | | | | - [ ] Ipv6CidrBlocks | + +---------------------------------------+--------+--------+--------+ - [ ] DefaultSecurityGroup | + | | | | | | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::EC2::VPCGatewayAttachment | x | | | | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::EC2::VPCPeeringConnection | x | | | - [ ] Id | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::EC2::Volume | x | | | - [ ] VolumeId | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::EC2::VolumeAttachment | x | | | | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::ECR::Repository | x | x | | - [x] RepositoryUri | + +---------------------------------------+--------+--------+--------+ - [x] Arn | + | | | | | | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::ECS::Cluster | x | x | | - [x] Arn | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::ECS::Service | x | x | | - [ ] ServiceArn | + +---------------------------------------+--------+--------+--------+ - [x] Name | + | | | | | | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::ECS::TaskDefinition | x | x | | - [ ] TaskDefinitionArn | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::EFS::FileSystem | x | x | x | - [ ] FileSystemId | + +---------------------------------------+--------+--------+--------+ - [ ] Arn | + | | | | | | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::EFS::MountTarget | x | x | x | - [ ] IpAddress | + +---------------------------------------+--------+--------+--------+ - [ ] Id | + | | | | | | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::Events::Archive | x | x | | - [x] Arn | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::Events::EventBus | x | x | x | - [x] Policy | + +---------------------------------------+--------+--------+--------+ - [x] Arn | + | | | | | - [x] Name | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::Events::Rule | x | x | x | - [x] Arn | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::IAM::AccessKey | x | x | x | - [x] SecretAccessKey | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::IAM::InstanceProfile | x | | x | - [x] Arn | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::IAM::ManagedPolicy | x | | | | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::IAM::Policy | | | | | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::IAM::Role | x | | x | - [x] Arn | + +---------------------------------------+--------+--------+--------+ - [ ] RoleId | + | | | | | | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::IAM::User | x | x | x | - [x] Arn | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::KMS::Key | x | | | - [ ] KeyId | + +---------------------------------------+--------+--------+--------+ - [x] Arn | + | | | | | | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::Kinesis::Stream | x | x | x | - [x] Arn | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::Logs::LogGroup | x | | | - [x] Arn | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::RDS::DBParameterGroup | x | | | - [ ] DBParameterGroupName | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::Redshift::Cluster | x | | | - [x] Endpoint.Address | + +---------------------------------------+--------+--------+--------+ - [x] Endpoint.Port | + | | | | | - [ ] Id | + +---------------------------------------+--------+--------+--------+ - [ ] DeferMaintenanceIdentifier | + | | | | | | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::Route53::HealthCheck | x | | | - [ ] HealthCheckId | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::Route53::RecordSet | x | x | x | | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::Route53::RecordSetGroup | x | | | | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::S3::Bucket | x | x | x | - [x] Arn | + +---------------------------------------+--------+--------+--------+ - [x] DomainName | + | | | | | - [x] DualStackDomainName | + +---------------------------------------+--------+--------+--------+ - [x] RegionalDomainName | + | | | | | - [x] WebsiteURL | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::SNS::Topic | x | x | x | - [ ] TopicArn | + +---------------------------------------+--------+--------+--------+ - [x] TopicName | + | | | | | | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::SQS::Queue | x | x | x | - [x] Arn | + +---------------------------------------+--------+--------+--------+ - [x] QueueName | + | | | | | - [ ] QueueUrl | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::SSM::Parameter | x | x | x | - [ ] Type | + +---------------------------------------+--------+--------+--------+ - [ ] Value | + | | | | | | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::SageMaker::Endpoint | x | x | x | - [x] EndpointName | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::SageMaker::EndpointConfig | x | x | x | - [x] EndpointConfigName | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::SageMaker::Model | x | x | x | - [x] ModelName | + +---------------------------------------+--------+--------+--------+-----------------------------------+ + |AWS::StepFunctions::StateMachine | x | x | x | - [ ] StateMachineRevisionId | + +---------------------------------------+--------+--------+--------+ - [ ] Arn | + | | | | | - [x] Name | + +---------------------------------------+--------+--------+--------+-----------------------------------+ diff --git a/docs/index.rst b/docs/index.rst index 0ba6134a9747..cbf9cd485309 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -49,6 +49,7 @@ Additional Resources :caption: Implemented Services docs/services/index + docs/services/cf docs/services/patching_other_services .. toctree:: diff --git a/moto/ec2/responses/launch_templates.py b/moto/ec2/responses/launch_templates.py index ac9dfe18d27e..58eb05ddd546 100644 --- a/moto/ec2/responses/launch_templates.py +++ b/moto/ec2/responses/launch_templates.py @@ -266,7 +266,7 @@ def get_launch_template_data(self) -> str: return template.render(i=instance) -GET_LAUNCH_TEMPLATE_DATA_RESPONSE = """ +GET_LAUNCH_TEMPLATE_DATA_RESPONSE = """ 801986a5-0ee2-46bd-be02-abcde1234567 diff --git a/scripts/cloudformation_coverage.py b/scripts/cloudformation_coverage.py index cb00dace5bab..e3a823d360c4 100755 --- a/scripts/cloudformation_coverage.py +++ b/scripts/cloudformation_coverage.py @@ -1,8 +1,7 @@ #!/usr/bin/env python -import importlib -import json -import mock +from unittest.mock import patch import requests +import os import moto @@ -10,6 +9,9 @@ moto.mock_all() +script_dir = os.path.dirname(os.path.abspath(__file__)) + + def check(condition): if bool(condition): return "x" @@ -17,6 +19,10 @@ def check(condition): return " " +def utf_checkbox(condition): + return "☑" if bool(condition) else " " + + def is_implemented(model, method_name): # method_name in model.__dict__ will be True if the method # exists on the model and False if it's only inherited from @@ -73,7 +79,7 @@ def missing_attrs(self): for attr in self.expected_attrs: try: # TODO: Change the actual abstract method to return False - with mock.patch( + with patch( "moto.core.common_models.CloudFormationModel.has_cfn_attr", return_value=False, ): @@ -96,16 +102,86 @@ def deletable(self): return is_implemented(self.moto_model, "delete_from_cloudformation_json") +def write_main_document(supported): + implementation_coverage_file = "{}/../CLOUDFORMATION_COVERAGE.md".format(script_dir) + try: + os.remove(implementation_coverage_file) + except OSError: + pass + + print("Writing to {}".format(implementation_coverage_file)) + with open(implementation_coverage_file, "w+") as file: + file.write("## Supported CloudFormation resources") + file.write("\n\n") + file.write("A list of all resources that can be created via CloudFormation. \n") + file.write("Please let us know if you'd like support for a resource not yet listed here.") + file.write("\n\n") + + for checklist in supported: + file.write(str(checklist)) + file.write("\n") + + +def write_documentation(supported): + docs_file = "{}/../docs/docs/services/cf.rst".format(script_dir) + try: + os.remove(docs_file) + except OSError: + pass + + print("Writing to {}".format(docs_file)) + with open(docs_file, "w+") as file: + file.write(f".. _cloudformation_resources:\n") + file.write("\n") + file.write("==================================\n") + file.write("Supported CloudFormation resources\n") + file.write("==================================\n") + file.write("\n\n") + file.write("A list of all resources that can be created via CloudFormation. \n") + file.write("Please let us know if you'd like support for a resource not yet listed here.") + file.write("\n\n") + + max_resource_name_length = max([len(cf.resource_name) for cf in supported]) + 2 + max_fn_att_length = 35 + + file.write(".. table:: \n\n") + file.write(f" +{('-'*max_resource_name_length)}+--------+--------+--------+{('-' * max_fn_att_length)}+\n") + file.write(f" |{(' '*max_resource_name_length)}| Create | Update | Delete | {('Fn::GetAtt'.ljust(max_fn_att_length-2))} |\n") + file.write(f" +{('='*max_resource_name_length)}+========+========+========+{('=' * max_fn_att_length)}+\n") + + for checklist in supported: + attrs = [f" - [{check(att not in checklist.missing_attrs)}] {att}" for att in checklist.expected_attrs] + first_attr = attrs[0] if attrs else "" + file.write(" |") + file.write(checklist.resource_name.ljust(max_resource_name_length)) + file.write("|") + file.write(f" {check(checklist.creatable)} ") + file.write("|") + file.write(f" {check(checklist.updatable)} ") + file.write("|") + file.write(f" {check(checklist.deletable)} ") + file.write(f"|{first_attr.ljust(max_fn_att_length)}|") + file.write("\n") + for index, attr in enumerate(attrs[1:]): + if index % 2 == 0: + file.write( + f" +{('-' * max_resource_name_length)}+--------+--------+--------+{attr.ljust(max_fn_att_length)}|\n") + else: + file.write( + f" |{(' ' * max_resource_name_length)}| | | |{attr.ljust(max_fn_att_length)}|\n") + if len(attrs) > 1 and len(attrs) % 2 == 0: + file.write(f" |{(' ' * max_resource_name_length)}| | | |{(' ' * max_fn_att_length)}|\n") + file.write(f" +{('-'*max_resource_name_length)}+--------+--------+--------+{('-' * max_fn_att_length)}+\n") + + if __name__ == "__main__": # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-resource-specification.html cfn_spec = requests.get( "https://dnwj8swjjbsbt.cloudfront.net/latest/gzip/CloudFormationResourceSpecification.json" ).json() - for resource_name, schema in sorted(cfn_spec["ResourceTypes"].items()): - checklist = CloudFormationChecklist(resource_name, schema) - # Only print checklists for models that implement CloudFormationModel; - # otherwise the checklist is very long and mostly empty because there - # are so many niche AWS services and resources that moto doesn't - # implement yet. - if checklist.moto_model: - print(checklist) + # Only collect checklists for models that implement CloudFormationModel; + # otherwise the checklist is very long and mostly empty because there + # are so many niche AWS services and resources that moto doesn't implement yet. + supported = [CloudFormationChecklist(resource_name, schema) for resource_name, schema in sorted(cfn_spec["ResourceTypes"].items()) if CloudFormationChecklist(resource_name, schema).moto_model] + #write_main_document(supported) + write_documentation(supported)