From d03891e80577be85a49b61cfa686222516d753e9 Mon Sep 17 00:00:00 2001 From: Bert Blommers Date: Sun, 19 Jun 2022 13:43:57 +0000 Subject: [PATCH] Prep Release 3.1.14 (#5242) --- CHANGELOG.md | 45 ++++ IMPLEMENTATION_COVERAGE.md | 76 +++--- docs/docs/services/cognito-idp.rst | 9 +- docs/docs/services/eks.rst | 12 + docs/docs/services/greengrass.rst | 48 ++-- docs/docs/services/guardduty.rst | 4 + docs/docs/services/route53.rst | 8 +- docs/requirements.txt | 1 + moto/cognitoidp/models.py | 7 + moto/route53/models.py | 4 +- moto/route53/responses.py | 4 +- scripts/implementation_coverage.py | 2 +- tests/test_route53/test_route53.py | 236 ++---------------- ..._boto3.py => test_route53_healthchecks.py} | 97 ++++++- tests/test_route53/test_route53_vpcs.py | 236 ++++++++++++++++++ 15 files changed, 497 insertions(+), 292 deletions(-) rename tests/test_route53/{test_route53_boto3.py => test_route53_healthchecks.py} (69%) create mode 100644 tests/test_route53/test_route53_vpcs.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 099cf063b56..6008ceaf5f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,51 @@ Moto Changelog ============== +3.1.14 +----- +Docker Digest for 3.1.14: + + New Methods: + * Greengrass: + * create_function_definition() + * create_resource_definition() + * create_function_definition_version() + * create_resource_definition_version() + * create_subscription_definition() + * create_subscription_definition_version() + * delete_function_definition() + * delete_resource_definition() + * delete_subscription_definition() + * get_function_definition() + * get_function_definition_version() + * get_resource_definition() + * get_resource_definition_version() + * get_subscription_definition() + * get_subscription_definition_version() + * list_function_definitions() + * list_function_definition_versions() + * list_resource_definitions() + * list_resource_definition_versions() + * list_subscription_definitions() + * list_subscription_definition_versions() + * update_function_definition() + * update_resource_definition() + * update_subscription_definition() + * EKS: + * list_tags_for_resources() + * tag_resource() + * untag_resource() + * Route53: + * associate_vpc() + * disassociate_vpc_from_hosted_zone() + * update_health_check() + * update_hosted_zone_comment() + + Miscellaneous: + * APIGateway:put_integration() now supports the requestParameters-parameter + * EC2:create_route() now validates whether a route already exists + + 3.1.13 ----- Docker Digest for 3.1.13: _sha256:d7f6c779c79f03b686747ae26b52bdca26fd81a50c6a41a8a6cba50c96982abf_ diff --git a/IMPLEMENTATION_COVERAGE.md b/IMPLEMENTATION_COVERAGE.md index 5c2a07ca2d2..b1d02ff9bbc 100644 --- a/IMPLEMENTATION_COVERAGE.md +++ b/IMPLEMENTATION_COVERAGE.md @@ -2114,7 +2114,7 @@ ## eks
-35% implemented +44% implemented - [ ] associate_encryption_config - [ ] associate_identity_provider_config @@ -2140,11 +2140,11 @@ - [X] list_fargate_profiles - [ ] list_identity_provider_configs - [X] list_nodegroups -- [ ] list_tags_for_resource +- [X] list_tags_for_resource - [ ] list_updates - [ ] register_cluster -- [ ] tag_resource -- [ ] untag_resource +- [X] tag_resource +- [X] untag_resource - [ ] update_addon - [ ] update_cluster_config - [ ] update_cluster_version @@ -2867,7 +2867,7 @@ ## greengrass
-17% implemented +43% implemented - [ ] associate_role_to_group - [ ] associate_service_role_to_account @@ -2878,26 +2878,26 @@ - [ ] create_deployment - [X] create_device_definition - [X] create_device_definition_version -- [ ] create_function_definition -- [ ] create_function_definition_version +- [X] create_function_definition +- [X] create_function_definition_version - [ ] create_group - [ ] create_group_certificate_authority - [ ] create_group_version - [ ] create_logger_definition - [ ] create_logger_definition_version -- [ ] create_resource_definition -- [ ] create_resource_definition_version +- [X] create_resource_definition +- [X] create_resource_definition_version - [ ] create_software_update_job -- [ ] create_subscription_definition -- [ ] create_subscription_definition_version +- [X] create_subscription_definition +- [X] create_subscription_definition_version - [ ] delete_connector_definition - [X] delete_core_definition - [X] delete_device_definition -- [ ] delete_function_definition +- [X] delete_function_definition - [ ] delete_group - [ ] delete_logger_definition -- [ ] delete_resource_definition -- [ ] delete_subscription_definition +- [X] delete_resource_definition +- [X] delete_subscription_definition - [ ] disassociate_role_from_group - [ ] disassociate_service_role_from_account - [ ] get_associated_role @@ -2910,19 +2910,19 @@ - [ ] get_deployment_status - [X] get_device_definition - [X] get_device_definition_version -- [ ] get_function_definition -- [ ] get_function_definition_version +- [X] get_function_definition +- [X] get_function_definition_version - [ ] get_group - [ ] get_group_certificate_authority - [ ] get_group_certificate_configuration - [ ] get_group_version - [ ] get_logger_definition - [ ] get_logger_definition_version -- [ ] get_resource_definition -- [ ] get_resource_definition_version +- [X] get_resource_definition +- [X] get_resource_definition_version - [ ] get_service_role_for_account -- [ ] get_subscription_definition -- [ ] get_subscription_definition_version +- [X] get_subscription_definition +- [X] get_subscription_definition_version - [ ] get_thing_runtime_configuration - [ ] list_bulk_deployment_detailed_reports - [ ] list_bulk_deployments @@ -2933,17 +2933,17 @@ - [ ] list_deployments - [X] list_device_definition_versions - [X] list_device_definitions -- [ ] list_function_definition_versions -- [ ] list_function_definitions +- [X] list_function_definition_versions +- [X] list_function_definitions - [ ] list_group_certificate_authorities - [ ] list_group_versions - [ ] list_groups - [ ] list_logger_definition_versions - [ ] list_logger_definitions -- [ ] list_resource_definition_versions -- [ ] list_resource_definitions -- [ ] list_subscription_definition_versions -- [ ] list_subscription_definitions +- [X] list_resource_definition_versions +- [X] list_resource_definitions +- [X] list_subscription_definition_versions +- [X] list_subscription_definitions - [ ] list_tags_for_resource - [ ] reset_deployments - [ ] start_bulk_deployment @@ -2954,19 +2954,20 @@ - [ ] update_connector_definition - [X] update_core_definition - [X] update_device_definition -- [ ] update_function_definition +- [X] update_function_definition - [ ] update_group - [ ] update_group_certificate_configuration - [ ] update_logger_definition -- [ ] update_resource_definition -- [ ] update_subscription_definition +- [X] update_resource_definition +- [X] update_subscription_definition - [ ] update_thing_runtime_configuration
## guardduty
-18% implemented +17% implemented +- [ ] accept_administrator_invitation - [ ] accept_invitation - [ ] archive_findings - [X] create_detector @@ -2987,9 +2988,11 @@ - [ ] describe_organization_configuration - [ ] describe_publishing_destination - [ ] disable_organization_admin_account +- [ ] disassociate_from_administrator_account - [ ] disassociate_from_master_account - [ ] disassociate_members - [X] enable_organization_admin_account +- [ ] get_administrator_account - [X] get_detector - [X] get_filter - [ ] get_findings @@ -2999,6 +3002,7 @@ - [ ] get_master_account - [ ] get_member_detectors - [ ] get_members +- [ ] get_remaining_free_trial_days - [ ] get_threat_intel_set - [ ] get_usage_statistics - [ ] invite_members @@ -4733,10 +4737,10 @@ ## route53
-34% implemented +40% implemented - [ ] activate_key_signing_key -- [ ] associate_vpc_with_hosted_zone +- [X] associate_vpc_with_hosted_zone - [ ] change_cidr_collection - [X] change_resource_record_sets - [X] change_tags_for_resource @@ -4761,7 +4765,7 @@ - [ ] delete_traffic_policy_instance - [ ] delete_vpc_association_authorization - [ ] disable_hosted_zone_dnssec -- [ ] disassociate_vpc_from_hosted_zone +- [X] disassociate_vpc_from_hosted_zone - [ ] enable_hosted_zone_dnssec - [ ] get_account_limit - [ ] get_change @@ -4801,8 +4805,8 @@ - [ ] list_traffic_policy_versions - [ ] list_vpc_association_authorizations - [ ] test_dns_answer -- [ ] update_health_check -- [ ] update_hosted_zone_comment +- [X] update_health_check +- [X] update_hosted_zone_comment - [ ] update_traffic_policy_comment - [ ] update_traffic_policy_instance
@@ -5998,6 +6002,7 @@ - compute-optimizer - connect - connect-contact-lens +- connectcampaigns - connectparticipant - cur - customer-profiles @@ -6110,6 +6115,7 @@ - qldb-session - rbin - rds-data +- redshiftserverless - resiliencehub - robomaker - route53-recovery-cluster diff --git a/docs/docs/services/cognito-idp.rst b/docs/docs/services/cognito-idp.rst index 3065ea66418..6e63a2af81a 100644 --- a/docs/docs/services/cognito-idp.rst +++ b/docs/docs/services/cognito-idp.rst @@ -12,6 +12,8 @@ cognito-idp =========== +.. autoclass:: moto.cognitoidp.models.CognitoIdpBackend + |start-h3| Example usage |end-h3| .. sourcecode:: python @@ -145,10 +147,3 @@ cognito-idp - [ ] verify_user_attribute - -|start-h3| Stable Cognito User Pool Id |end-h3| - -In some cases, you need to have reproducible IDs for the user pool. -For example, a single initialization before the start of integration tests. - -This behavior can be enabled by passing the environment variable: MOTO_COGNITO_IDP_USER_POOL_ID_STRATEGY=HASH. diff --git a/docs/docs/services/eks.rst b/docs/docs/services/eks.rst index 00fad92b5ee..1a4a993209e 100644 --- a/docs/docs/services/eks.rst +++ b/docs/docs/services/eks.rst @@ -50,10 +50,22 @@ eks - [ ] list_identity_provider_configs - [X] list_nodegroups - [X] list_tags_for_resource + + This function currently will list tags on an EKS cluster only. It does not list tags from a managed node group + + - [ ] list_updates - [ ] register_cluster - [X] tag_resource + + This function currently will tag an EKS cluster only. It does not tag a managed node group + + - [X] untag_resource + + This function currently will remove tags on an EKS cluster only. It does not remove tags from a managed node group + + - [ ] update_addon - [ ] update_cluster_config - [ ] update_cluster_version diff --git a/docs/docs/services/greengrass.rst b/docs/docs/services/greengrass.rst index 315fdc543d5..d27ddab3b4a 100644 --- a/docs/docs/services/greengrass.rst +++ b/docs/docs/services/greengrass.rst @@ -34,26 +34,26 @@ greengrass - [ ] create_deployment - [X] create_device_definition - [X] create_device_definition_version -- [ ] create_function_definition -- [ ] create_function_definition_version +- [X] create_function_definition +- [X] create_function_definition_version - [ ] create_group - [ ] create_group_certificate_authority - [ ] create_group_version - [ ] create_logger_definition - [ ] create_logger_definition_version -- [ ] create_resource_definition -- [ ] create_resource_definition_version +- [X] create_resource_definition +- [X] create_resource_definition_version - [ ] create_software_update_job -- [ ] create_subscription_definition -- [ ] create_subscription_definition_version +- [X] create_subscription_definition +- [X] create_subscription_definition_version - [ ] delete_connector_definition - [X] delete_core_definition - [X] delete_device_definition -- [ ] delete_function_definition +- [X] delete_function_definition - [ ] delete_group - [ ] delete_logger_definition -- [ ] delete_resource_definition -- [ ] delete_subscription_definition +- [X] delete_resource_definition +- [X] delete_subscription_definition - [ ] disassociate_role_from_group - [ ] disassociate_service_role_from_account - [ ] get_associated_role @@ -66,19 +66,19 @@ greengrass - [ ] get_deployment_status - [X] get_device_definition - [X] get_device_definition_version -- [ ] get_function_definition -- [ ] get_function_definition_version +- [X] get_function_definition +- [X] get_function_definition_version - [ ] get_group - [ ] get_group_certificate_authority - [ ] get_group_certificate_configuration - [ ] get_group_version - [ ] get_logger_definition - [ ] get_logger_definition_version -- [ ] get_resource_definition -- [ ] get_resource_definition_version +- [X] get_resource_definition +- [X] get_resource_definition_version - [ ] get_service_role_for_account -- [ ] get_subscription_definition -- [ ] get_subscription_definition_version +- [X] get_subscription_definition +- [X] get_subscription_definition_version - [ ] get_thing_runtime_configuration - [ ] list_bulk_deployment_detailed_reports - [ ] list_bulk_deployments @@ -89,17 +89,17 @@ greengrass - [ ] list_deployments - [X] list_device_definition_versions - [X] list_device_definitions -- [ ] list_function_definition_versions -- [ ] list_function_definitions +- [X] list_function_definition_versions +- [X] list_function_definitions - [ ] list_group_certificate_authorities - [ ] list_group_versions - [ ] list_groups - [ ] list_logger_definition_versions - [ ] list_logger_definitions -- [ ] list_resource_definition_versions -- [ ] list_resource_definitions -- [ ] list_subscription_definition_versions -- [ ] list_subscription_definitions +- [X] list_resource_definition_versions +- [X] list_resource_definitions +- [X] list_subscription_definition_versions +- [X] list_subscription_definitions - [ ] list_tags_for_resource - [ ] reset_deployments - [ ] start_bulk_deployment @@ -110,11 +110,11 @@ greengrass - [ ] update_connector_definition - [X] update_core_definition - [X] update_device_definition -- [ ] update_function_definition +- [X] update_function_definition - [ ] update_group - [ ] update_group_certificate_configuration - [ ] update_logger_definition -- [ ] update_resource_definition -- [ ] update_subscription_definition +- [X] update_resource_definition +- [X] update_subscription_definition - [ ] update_thing_runtime_configuration diff --git a/docs/docs/services/guardduty.rst b/docs/docs/services/guardduty.rst index 143acf6a054..3bb95e38aa5 100644 --- a/docs/docs/services/guardduty.rst +++ b/docs/docs/services/guardduty.rst @@ -25,6 +25,7 @@ guardduty |start-h3| Implemented features for this service |end-h3| +- [ ] accept_administrator_invitation - [ ] accept_invitation - [ ] archive_findings - [X] create_detector @@ -45,9 +46,11 @@ guardduty - [ ] describe_organization_configuration - [ ] describe_publishing_destination - [ ] disable_organization_admin_account +- [ ] disassociate_from_administrator_account - [ ] disassociate_from_master_account - [ ] disassociate_members - [X] enable_organization_admin_account +- [ ] get_administrator_account - [X] get_detector - [X] get_filter - [ ] get_findings @@ -57,6 +60,7 @@ guardduty - [ ] get_master_account - [ ] get_member_detectors - [ ] get_members +- [ ] get_remaining_free_trial_days - [ ] get_threat_intel_set - [ ] get_usage_statistics - [ ] invite_members diff --git a/docs/docs/services/route53.rst b/docs/docs/services/route53.rst index d00b7bf9762..148621fd2dd 100644 --- a/docs/docs/services/route53.rst +++ b/docs/docs/services/route53.rst @@ -26,7 +26,7 @@ route53 |start-h3| Implemented features for this service |end-h3| - [ ] activate_key_signing_key -- [ ] associate_vpc_with_hosted_zone +- [X] associate_vpc_with_hosted_zone - [ ] change_cidr_collection - [X] change_resource_record_sets - [X] change_tags_for_resource @@ -55,7 +55,7 @@ route53 - [ ] delete_traffic_policy_instance - [ ] delete_vpc_association_authorization - [ ] disable_hosted_zone_dnssec -- [ ] disassociate_vpc_from_hosted_zone +- [X] disassociate_vpc_from_hosted_zone - [ ] enable_hosted_zone_dnssec - [ ] get_account_limit - [ ] get_change @@ -111,8 +111,8 @@ route53 - [ ] list_traffic_policy_versions - [ ] list_vpc_association_authorizations - [ ] test_dns_answer -- [ ] update_health_check -- [ ] update_hosted_zone_comment +- [X] update_health_check +- [X] update_hosted_zone_comment - [ ] update_traffic_policy_comment - [ ] update_traffic_policy_instance diff --git a/docs/requirements.txt b/docs/requirements.txt index a12d5bd7f3c..df387da4d4a 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -6,3 +6,4 @@ readthedocs-sphinx-search==0.1.1 docker openapi_spec_validator PyYAML>=5.1 +python-jose[cryptography]>=3.1.0,<4.0.0 diff --git a/moto/cognitoidp/models.py b/moto/cognitoidp/models.py index 276effb5d24..87f8239705a 100644 --- a/moto/cognitoidp/models.py +++ b/moto/cognitoidp/models.py @@ -831,6 +831,13 @@ def to_json(self): class CognitoIdpBackend(BaseBackend): + """ + In some cases, you need to have reproducible IDs for the user pool. + For example, a single initialization before the start of integration tests. + + This behavior can be enabled by passing the environment variable: MOTO_COGNITO_IDP_USER_POOL_ID_STRATEGY=HASH. + """ + def __init__(self, region_name, account_id): super().__init__(region_name, account_id) self.user_pools = OrderedDict() diff --git a/moto/route53/models.py b/moto/route53/models.py index 8e6be240987..db713cbe985 100644 --- a/moto/route53/models.py +++ b/moto/route53/models.py @@ -470,14 +470,14 @@ def get_dnssec(self, zone_id): # check if hosted zone exists self.get_hosted_zone(zone_id) - def associate_vpc(self, zone_id, vpcid, vpcregion): + def associate_vpc_with_hosted_zone(self, zone_id, vpcid, vpcregion): zone = self.get_hosted_zone(zone_id) if not zone.private_zone: raise PublicZoneVPCAssociation() zone.add_vpc(vpcid, vpcregion) return zone - def disassociate_vpc(self, zone_id, vpcid): + def disassociate_vpc_from_hosted_zone(self, zone_id, vpcid): zone = self.get_hosted_zone(zone_id) if len(zone.vpcs) <= 1: raise LastVPCAssociation() diff --git a/moto/route53/responses.py b/moto/route53/responses.py index 86ea8302c61..01ca96431d1 100644 --- a/moto/route53/responses.py +++ b/moto/route53/responses.py @@ -151,7 +151,7 @@ def associate_vpc_response(self, request, full_url, headers): vpcid = vpc.get("VPCId", None) vpcregion = vpc.get("VPCRegion", None) - route53_backend.associate_vpc(zoneid, vpcid, vpcregion) + route53_backend.associate_vpc_with_hosted_zone(zoneid, vpcid, vpcregion) template = Template(ASSOCIATE_VPC_RESPONSE) return 200, headers, template.render(comment=comment) @@ -169,7 +169,7 @@ def disassociate_vpc_response(self, request, full_url, headers): vpc = elements.get("DisassociateVPCFromHostedZoneRequest", {}).get("VPC", {}) vpcid = vpc.get("VPCId", None) - route53_backend.disassociate_vpc(zoneid, vpcid) + route53_backend.disassociate_vpc_from_hosted_zone(zoneid, vpcid) template = Template(DISASSOCIATE_VPC_RESPONSE) return 200, headers, template.render(comment=comment) diff --git a/scripts/implementation_coverage.py b/scripts/implementation_coverage.py index 389972cb8bd..2a3080d9bca 100755 --- a/scripts/implementation_coverage.py +++ b/scripts/implementation_coverage.py @@ -261,7 +261,7 @@ def test_{coverage[service_name]['name'][5:]}_behaviour: file.write(" ...\n") file.write("\n\n") file.write(".. sourcecode:: python\n\n") - file.write(" @mock_all\n") + file.write(" @mock_all()\n") file.write(" def test_all_supported_services_at_the_same_time():\n") file.write(" ...\n") file.write("\n") diff --git a/tests/test_route53/test_route53.py b/tests/test_route53/test_route53.py index 6a17b9ed057..749264be63d 100644 --- a/tests/test_route53/test_route53.py +++ b/tests/test_route53/test_route53.py @@ -161,6 +161,20 @@ def test_get_unknown_hosted_zone(): err["Message"].should.equal("No hosted zone found with ID: unknown") +@mock_route53 +def test_update_hosted_zone_comment(): + conn = boto3.client("route53", region_name="us-east-1") + response = conn.create_hosted_zone( + Name="testdns.aws.com.", CallerReference=str(hash("foo")) + ) + zone_id = response["HostedZone"]["Id"].split("/")[-1] + + conn.update_hosted_zone_comment(Id=zone_id, Comment="yolo") + + resp = conn.get_hosted_zone(Id=zone_id)["HostedZone"] + resp["Config"].should.have.key("Comment").equals("yolo") + + @mock_route53 def test_list_resource_record_set_unknown_zone(): conn = boto3.client("route53", region_name="us-east-1") @@ -188,90 +202,6 @@ def test_list_resource_record_set_unknown_type(): err["Message"].should.equal("Bad Request") -@mock_route53 -def test_create_health_check(): - conn = boto3.client("route53", region_name="us-east-1") - - check = conn.create_health_check( - CallerReference="?", - HealthCheckConfig={ - "IPAddress": "10.0.0.25", - "Port": 80, - "Type": "HTTP", - "ResourcePath": "/", - "FullyQualifiedDomainName": "example.com", - "SearchString": "a good response", - "RequestInterval": 10, - "FailureThreshold": 2, - }, - )["HealthCheck"] - check.should.have.key("Id").match("[a-z0-9-]+") - check.should.have.key("CallerReference") - check.should.have.key("HealthCheckConfig") - check["HealthCheckConfig"].should.have.key("IPAddress").equal("10.0.0.25") - check["HealthCheckConfig"].should.have.key("Port").equal(80) - check["HealthCheckConfig"].should.have.key("Type").equal("HTTP") - check["HealthCheckConfig"].should.have.key("ResourcePath").equal("/") - check["HealthCheckConfig"].should.have.key("FullyQualifiedDomainName").equal( - "example.com" - ) - check["HealthCheckConfig"].should.have.key("SearchString").equal("a good response") - check["HealthCheckConfig"].should.have.key("RequestInterval").equal(10) - check["HealthCheckConfig"].should.have.key("FailureThreshold").equal(2) - check.should.have.key("HealthCheckVersion").equal(1) - - -@mock_route53 -def test_list_health_checks(): - conn = boto3.client("route53", region_name="us-east-1") - - conn.list_health_checks()["HealthChecks"].should.have.length_of(0) - - check = conn.create_health_check( - CallerReference="?", - HealthCheckConfig={ - "IPAddress": "10.0.0.25", - "Port": 80, - "Type": "HTTP", - "ResourcePath": "/", - "FullyQualifiedDomainName": "example.com", - "SearchString": "a good response", - "RequestInterval": 10, - "FailureThreshold": 2, - }, - )["HealthCheck"] - - checks = conn.list_health_checks()["HealthChecks"] - checks.should.have.length_of(1) - checks.should.contain(check) - - -@mock_route53 -def test_delete_health_checks(): - conn = boto3.client("route53", region_name="us-east-1") - - conn.list_health_checks()["HealthChecks"].should.have.length_of(0) - - check = conn.create_health_check( - CallerReference="?", - HealthCheckConfig={ - "IPAddress": "10.0.0.25", - "Port": 80, - "Type": "HTTP", - "ResourcePath": "/", - "FullyQualifiedDomainName": "example.com", - "SearchString": "a good response", - "RequestInterval": 10, - "FailureThreshold": 2, - }, - )["HealthCheck"] - - conn.delete_health_check(HealthCheckId=check["Id"]) - - checks = conn.list_health_checks()["HealthChecks"] - checks.should.have.length_of(0) - - @mock_route53 def test_use_health_check_in_resource_record_set(): conn = boto3.client("route53", region_name="us-east-1") @@ -457,70 +387,6 @@ def test_deleting_latency_route(): cnames[1]["Region"].should.equal("us-west-1") -@mock_ec2 -@mock_route53 -def test_hosted_zone_private_zone_preserved(): - # Create mock VPC so we can get a VPC ID - region = "us-east-1" - ec2c = boto3.client("ec2", region_name=region) - vpc_id = ec2c.create_vpc(CidrBlock="10.1.0.0/16").get("Vpc").get("VpcId") - - # Create hosted_zone as a Private VPC Hosted Zone - conn = boto3.client("route53", region_name=region) - new_zone = conn.create_hosted_zone( - Name="testdns.aws.com.", - CallerReference=str(hash("foo")), - HostedZoneConfig=dict(PrivateZone=True, Comment="Test"), - VPC={"VPCRegion": region, "VPCId": vpc_id}, - ) - - zone_id = new_zone["HostedZone"]["Id"].split("/")[-1] - hosted_zone = conn.get_hosted_zone(Id=zone_id) - hosted_zone["HostedZone"]["Config"]["PrivateZone"].should.equal(True) - hosted_zone.should.have.key("VPCs") - hosted_zone["VPCs"].should.have.length_of(1) - hosted_zone["VPCs"][0].should.have.key("VPCId") - hosted_zone["VPCs"][0].should.have.key("VPCRegion") - hosted_zone["VPCs"][0]["VPCId"].should_not.equal(None) - hosted_zone["VPCs"][0]["VPCRegion"].should_not.equal(None) - hosted_zone["VPCs"][0]["VPCId"].should.be.equal(vpc_id) - hosted_zone["VPCs"][0]["VPCRegion"].should.be.equal(region) - - hosted_zones = conn.list_hosted_zones() - hosted_zones["HostedZones"][0]["Config"]["PrivateZone"].should.equal(True) - - hosted_zones = conn.list_hosted_zones_by_name(DNSName="testdns.aws.com.") - hosted_zones["HostedZones"].should.have.length_of(1) - hosted_zones["HostedZones"][0]["Config"]["PrivateZone"].should.equal(True) - - # create_hosted_zone statements with PrivateZone=True, - # but without a _valid_ vpc-id should NOT fail. - zone2_name = "testdns2.aws.com." - no_vpc_zone = conn.create_hosted_zone( - Name=zone2_name, - CallerReference=str(hash("foo")), - HostedZoneConfig=dict(PrivateZone=True, Comment="Test without VPC"), - ) - - zone_id = no_vpc_zone["HostedZone"]["Id"].split("/")[-1] - hosted_zone = conn.get_hosted_zone(Id=zone_id) - hosted_zone["HostedZone"]["Config"]["PrivateZone"].should.equal(True) - hosted_zone.should.have.key("VPCs") - hosted_zone["VPCs"].should.have.length_of(0) - - hosted_zones = conn.list_hosted_zones() - hosted_zones["HostedZones"].should.have.length_of(2) - hosted_zones["HostedZones"][0]["Config"]["PrivateZone"].should.equal(True) - hosted_zones["HostedZones"][1]["Config"]["PrivateZone"].should.equal(True) - - hosted_zones = conn.list_hosted_zones_by_name(DNSName=zone2_name) - hosted_zones["HostedZones"].should.have.length_of(1) - hosted_zones["HostedZones"][0]["Config"]["PrivateZone"].should.equal(True) - hosted_zones["HostedZones"][0]["Name"].should.equal(zone2_name) - - return - - @mock_route53 def test_list_or_change_tags_for_resource_request(): conn = boto3.client("route53", region_name="us-east-1") @@ -737,69 +603,6 @@ def test_list_hosted_zones_by_dns_name(): zones["HostedZones"][3]["Name"].should.equal("test.a.org.") -@mock_ec2 -@mock_route53 -def test_list_hosted_zones_by_vpc(): - # Create mock VPC so we can get a VPC ID - ec2c = boto3.client("ec2", region_name="us-east-1") - vpc_id = ec2c.create_vpc(CidrBlock="10.1.0.0/16").get("Vpc").get("VpcId") - region = "us-east-1" - - conn = boto3.client("route53", region_name=region) - zone_b = conn.create_hosted_zone( - Name="test.b.com.", - CallerReference=str(hash("foo")), - HostedZoneConfig=dict(PrivateZone=True, Comment="test com"), - VPC={"VPCRegion": region, "VPCId": vpc_id}, - ) - zone_id = zone_b["HostedZone"]["Id"].split("/")[2] - response = conn.list_hosted_zones_by_vpc(VPCId=vpc_id, VPCRegion=region) - response.should.have.key("ResponseMetadata") - response.should.have.key("HostedZoneSummaries") - response["HostedZoneSummaries"].should.have.length_of(1) - response["HostedZoneSummaries"][0].should.have.key("HostedZoneId") - retured_zone = response["HostedZoneSummaries"][0] - retured_zone["HostedZoneId"].should.equal(zone_id) - retured_zone["Name"].should.equal(zone_b["HostedZone"]["Name"]) - - -@mock_ec2 -@mock_route53 -def test_list_hosted_zones_by_vpc_with_multiple_vpcs(): - # Create mock VPC so we can get a VPC ID - ec2c = boto3.client("ec2", region_name="us-east-1") - vpc_id = ec2c.create_vpc(CidrBlock="10.1.0.0/16").get("Vpc").get("VpcId") - region = "us-east-1" - - # Create 3 Zones associate with the VPC. - zones = {} - conn = boto3.client("route53", region_name=region) - for zone in ["a", "b", "c"]: - zone_name = f"test.{zone}.com." - zones[zone] = conn.create_hosted_zone( - Name=zone_name, - CallerReference=str(hash("foo")), - HostedZoneConfig=dict(PrivateZone=True, Comment=f"test {zone} com"), - VPC={"VPCRegion": region, "VPCId": vpc_id}, - ) - - # List the zones associated with this vpc - response = conn.list_hosted_zones_by_vpc(VPCId=vpc_id, VPCRegion=region) - response.should.have.key("ResponseMetadata") - response.should.have.key("HostedZoneSummaries") - response["HostedZoneSummaries"].should.have.length_of(3) - - # Loop through all zone summaries and verify they match what was created - for summary in response["HostedZoneSummaries"]: - # use the zone name as the index - index = summary["Name"].split(".")[1] - zone_id = zones[index]["HostedZone"]["Id"].split("/")[2] - summary.should.have.key("HostedZoneId") - summary["HostedZoneId"].should.equal(zone_id) - summary.should.have.key("Name") - summary["Name"].should.equal(zones[index]["HostedZone"]["Name"]) - - @mock_route53 def test_change_resource_record_sets_crud_valid(): conn = boto3.client("route53", region_name="us-east-1") @@ -1568,3 +1371,14 @@ def test_list_resource_recordset_pagination(): response.should.have.key("MaxItems").equals("300") response.shouldnt.have.key("NextRecordName") response.shouldnt.have.key("NextRecordType") + + +@mock_route53 +def test_get_dns_sec(): + client = boto3.client("route53", region_name="us-east-1") + + hosted_zone_id = client.create_hosted_zone( + Name="testdns.aws.com.", CallerReference=str(hash("foo")) + )["HostedZone"]["Id"] + dns_sec = client.get_dnssec(HostedZoneId=hosted_zone_id) + dns_sec.should.have.key("Status").equals({"ServeSignature": "NOT_SIGNING"}) diff --git a/tests/test_route53/test_route53_boto3.py b/tests/test_route53/test_route53_healthchecks.py similarity index 69% rename from tests/test_route53/test_route53_boto3.py rename to tests/test_route53/test_route53_healthchecks.py index 5db1618d12e..c6e3f6cde4c 100644 --- a/tests/test_route53/test_route53_boto3.py +++ b/tests/test_route53/test_route53_healthchecks.py @@ -59,6 +59,7 @@ def test_create_health_check_with_additional_options(): "Type": "HTTP", "ResourcePath": "/", "FullyQualifiedDomainName": "example.com", + "SearchString": "a good response", "RequestInterval": 10, "FailureThreshold": 2, "MeasureLatency": True, @@ -73,9 +74,11 @@ def test_create_health_check_with_additional_options(): check.should.have.key("CallerReference").being.equal( "test-route53-health-HealthCheck-asdf" ) + check.should.have.key("HealthCheckVersion").equal(1) check.should.have.key("HealthCheckConfig") # config = check["HealthCheckConfig"] + check["HealthCheckConfig"].should.have.key("SearchString").equal("a good response") config.should.have.key("MeasureLatency").being.equal(True) config.should.have.key("Inverted").being.equal(True) config.should.have.key("Disabled").being.equal(True) @@ -203,11 +206,93 @@ def test_get_unknown_health_check(): @mock_route53 -def test_get_dns_sec(): +def test_list_health_checks(): + conn = boto3.client("route53", region_name="us-east-1") + + conn.list_health_checks()["HealthChecks"].should.have.length_of(0) + + check = conn.create_health_check( + CallerReference="?", + HealthCheckConfig={ + "IPAddress": "10.0.0.25", + "Port": 80, + "Type": "HTTP", + "ResourcePath": "/", + "FullyQualifiedDomainName": "example.com", + "SearchString": "a good response", + "RequestInterval": 10, + "FailureThreshold": 2, + }, + )["HealthCheck"] + + checks = conn.list_health_checks()["HealthChecks"] + checks.should.have.length_of(1) + checks.should.contain(check) + + +@mock_route53 +def test_delete_health_checks(): + conn = boto3.client("route53", region_name="us-east-1") + + conn.list_health_checks()["HealthChecks"].should.have.length_of(0) + + check = conn.create_health_check( + CallerReference="?", + HealthCheckConfig={ + "IPAddress": "10.0.0.25", + "Port": 80, + "Type": "HTTP", + "ResourcePath": "/", + "FullyQualifiedDomainName": "example.com", + "SearchString": "a good response", + "RequestInterval": 10, + "FailureThreshold": 2, + }, + )["HealthCheck"] + + conn.delete_health_check(HealthCheckId=check["Id"]) + + checks = conn.list_health_checks()["HealthChecks"] + checks.should.have.length_of(0) + + +@mock_route53 +def test_update_health_check(): client = boto3.client("route53", region_name="us-east-1") - hosted_zone_id = client.create_hosted_zone( - Name="testdns.aws.com.", CallerReference=str(hash("foo")) - )["HostedZone"]["Id"] - dns_sec = client.get_dnssec(HostedZoneId=hosted_zone_id) - dns_sec.should.have.key("Status").equals({"ServeSignature": "NOT_SIGNING"}) + hc_id = client.create_health_check( + CallerReference="callref", + HealthCheckConfig={ + "Type": "CALCULATED", + "Inverted": False, + "Disabled": False, + "HealthThreshold": 1, + }, + )["HealthCheck"]["Id"] + + client.update_health_check( + HealthCheckId=hc_id, + IPAddress="0.0.0.0", + Port=80, + ResourcePath="rp", + FullyQualifiedDomainName="example.com", + SearchString="search", + FailureThreshold=123, + Inverted=False, + Disabled=False, + HealthThreshold=13, + ChildHealthChecks=["child"], + Regions=["us-east-1", "us-east-2", "us-west-1"], + ) + + config = client.get_health_check(HealthCheckId=hc_id)["HealthCheck"][ + "HealthCheckConfig" + ] + config.should.have.key("Type").equals("CALCULATED") + config.should.have.key("ResourcePath").equals("rp") + config.should.have.key("FullyQualifiedDomainName").equals("example.com") + config.should.have.key("SearchString").equals("search") + config.should.have.key("Inverted").equals(False) + config.should.have.key("Disabled").equals(False) + config.should.have.key("ChildHealthChecks").equals(["child"]) + config.should.have.key("Regions").equals(["us-east-1", "us-east-2", "us-west-1"]) diff --git a/tests/test_route53/test_route53_vpcs.py b/tests/test_route53/test_route53_vpcs.py new file mode 100644 index 00000000000..e892888c454 --- /dev/null +++ b/tests/test_route53/test_route53_vpcs.py @@ -0,0 +1,236 @@ +import boto3 +import sure # noqa # pylint: disable=unused-import +import pytest + +from botocore.exceptions import ClientError +from moto import mock_ec2, mock_route53 + + +@mock_ec2 +@mock_route53 +def test_hosted_zone_private_zone_preserved(): + # Create mock VPC so we can get a VPC ID + region = "us-east-1" + ec2c = boto3.client("ec2", region_name=region) + vpc_id = ec2c.create_vpc(CidrBlock="10.1.0.0/16").get("Vpc").get("VpcId") + + # Create hosted_zone as a Private VPC Hosted Zone + conn = boto3.client("route53", region_name=region) + new_zone = conn.create_hosted_zone( + Name="testdns.aws.com.", + CallerReference=str(hash("foo")), + HostedZoneConfig=dict(PrivateZone=True, Comment="Test"), + VPC={"VPCRegion": region, "VPCId": vpc_id}, + ) + + zone_id = new_zone["HostedZone"]["Id"].split("/")[-1] + hosted_zone = conn.get_hosted_zone(Id=zone_id) + hosted_zone["HostedZone"]["Config"]["PrivateZone"].should.equal(True) + hosted_zone.should.have.key("VPCs") + hosted_zone["VPCs"].should.have.length_of(1) + hosted_zone["VPCs"][0].should.have.key("VPCId") + hosted_zone["VPCs"][0].should.have.key("VPCRegion") + hosted_zone["VPCs"][0]["VPCId"].should.be.equal(vpc_id) + hosted_zone["VPCs"][0]["VPCRegion"].should.be.equal(region) + + hosted_zones = conn.list_hosted_zones() + hosted_zones["HostedZones"][0]["Config"]["PrivateZone"].should.equal(True) + + hosted_zones = conn.list_hosted_zones_by_name(DNSName="testdns.aws.com.") + hosted_zones["HostedZones"].should.have.length_of(1) + hosted_zones["HostedZones"][0]["Config"]["PrivateZone"].should.equal(True) + + # create_hosted_zone statements with PrivateZone=True, + # but without a _valid_ vpc-id should NOT fail. + zone2_name = "testdns2.aws.com." + no_vpc_zone = conn.create_hosted_zone( + Name=zone2_name, + CallerReference=str(hash("foo")), + HostedZoneConfig=dict(PrivateZone=True, Comment="Test without VPC"), + ) + + zone_id = no_vpc_zone["HostedZone"]["Id"].split("/")[-1] + hosted_zone = conn.get_hosted_zone(Id=zone_id) + hosted_zone["HostedZone"]["Config"]["PrivateZone"].should.equal(True) + hosted_zone.should.have.key("VPCs") + hosted_zone["VPCs"].should.have.length_of(0) + + hosted_zones = conn.list_hosted_zones() + hosted_zones["HostedZones"].should.have.length_of(2) + hosted_zones["HostedZones"][0]["Config"]["PrivateZone"].should.equal(True) + hosted_zones["HostedZones"][1]["Config"]["PrivateZone"].should.equal(True) + + hosted_zones = conn.list_hosted_zones_by_name(DNSName=zone2_name) + hosted_zones["HostedZones"].should.have.length_of(1) + hosted_zones["HostedZones"][0]["Config"]["PrivateZone"].should.equal(True) + hosted_zones["HostedZones"][0]["Name"].should.equal(zone2_name) + + +@mock_ec2 +@mock_route53 +def test_list_hosted_zones_by_vpc_with_multiple_vpcs(): + # Create mock VPC so we can get a VPC ID + ec2c = boto3.client("ec2", region_name="us-east-1") + vpc_id = ec2c.create_vpc(CidrBlock="10.1.0.0/16").get("Vpc").get("VpcId") + region = "us-east-1" + + # Create 3 Zones associate with the VPC. + zones = {} + conn = boto3.client("route53", region_name=region) + for zone in ["a", "b", "c"]: + zone_name = f"test.{zone}.com." + zones[zone] = conn.create_hosted_zone( + Name=zone_name, + CallerReference=str(hash("foo")), + HostedZoneConfig=dict(PrivateZone=True, Comment=f"test {zone} com"), + VPC={"VPCRegion": region, "VPCId": vpc_id}, + ) + + # List the zones associated with this vpc + response = conn.list_hosted_zones_by_vpc(VPCId=vpc_id, VPCRegion=region) + response.should.have.key("ResponseMetadata") + response.should.have.key("HostedZoneSummaries") + response["HostedZoneSummaries"].should.have.length_of(3) + + # Loop through all zone summaries and verify they match what was created + for summary in response["HostedZoneSummaries"]: + # use the zone name as the index + index = summary["Name"].split(".")[1] + zone_id = zones[index]["HostedZone"]["Id"].split("/")[2] + summary.should.have.key("HostedZoneId") + summary["HostedZoneId"].should.equal(zone_id) + summary.should.have.key("Name") + summary["Name"].should.equal(zones[index]["HostedZone"]["Name"]) + + +@mock_ec2 +@mock_route53 +def test_list_hosted_zones_by_vpc(): + # Create mock VPC so we can get a VPC ID + ec2c = boto3.client("ec2", region_name="us-east-1") + vpc_id = ec2c.create_vpc(CidrBlock="10.1.0.0/16").get("Vpc").get("VpcId") + region = "us-east-1" + + conn = boto3.client("route53", region_name=region) + zone_b = conn.create_hosted_zone( + Name="test.b.com.", + CallerReference=str(hash("foo")), + HostedZoneConfig=dict(PrivateZone=True, Comment="test com"), + VPC={"VPCRegion": region, "VPCId": vpc_id}, + ) + zone_id = zone_b["HostedZone"]["Id"].split("/")[2] + + response = conn.list_hosted_zones_by_vpc(VPCId=vpc_id, VPCRegion=region) + response.should.have.key("ResponseMetadata") + response.should.have.key("HostedZoneSummaries") + response["HostedZoneSummaries"].should.have.length_of(1) + response["HostedZoneSummaries"][0].should.have.key("HostedZoneId") + retured_zone = response["HostedZoneSummaries"][0] + retured_zone["HostedZoneId"].should.equal(zone_id) + retured_zone["Name"].should.equal(zone_b["HostedZone"]["Name"]) + + +@mock_ec2 +@mock_route53 +def test_route53_associate_vpc(): + ec2c = boto3.client("ec2", region_name="us-east-1") + vpc_id = ec2c.create_vpc(CidrBlock="10.1.0.0/16")["Vpc"]["VpcId"] + conn = boto3.client("route53", region_name="us-east-1") + zone = conn.create_hosted_zone( + Name="test.b.com.", + CallerReference=str(hash("foo")), + HostedZoneConfig=dict(PrivateZone=True, Comment=""), + ) + zone_id = zone["HostedZone"]["Id"].split("/")[2] + + resp = conn.associate_vpc_with_hosted_zone( + HostedZoneId=zone_id, + VPC={"VPCId": vpc_id, "VPCRegion": "us-east-1"}, + Comment="yolo", + ) + resp.should.have.key("ChangeInfo") + resp["ChangeInfo"].should.have.key("Comment").equals("yolo") + + +@mock_ec2 +@mock_route53 +def test_route53_associate_vpc_with_public_Zone(): + ec2c = boto3.client("ec2", region_name="us-east-1") + vpc_id = ec2c.create_vpc(CidrBlock="10.1.0.0/16")["Vpc"]["VpcId"] + conn = boto3.client("route53", region_name="us-east-1") + zone = conn.create_hosted_zone( + Name="test.b.com.", + CallerReference=str(hash("foo")), + ) + zone_id = zone["HostedZone"]["Id"].split("/")[2] + + with pytest.raises(ClientError) as exc: + conn.associate_vpc_with_hosted_zone( + HostedZoneId=zone_id, + VPC={"VPCId": vpc_id, "VPCRegion": "us-east-1"}, + Comment="yolo", + ) + err = exc.value.response["Error"] + err["Code"].should.equal("PublicZoneVPCAssociation") + err["Message"].should.equal( + "You're trying to associate a VPC with a public hosted zone. Amazon Route 53 doesn't support associating a VPC with a public hosted zone." + ) + + +@mock_ec2 +@mock_route53 +def test_route53_associate_and_disassociate_vpc(): + ec2c = boto3.client("ec2", region_name="us-east-1") + vpc_id1 = ec2c.create_vpc(CidrBlock="10.1.0.0/16").get("Vpc").get("VpcId") + vpc_id2 = ec2c.create_vpc(CidrBlock="10.1.0.1/16").get("Vpc").get("VpcId") + region = "us-east-1" + + conn = boto3.client("route53", region_name=region) + zone = conn.create_hosted_zone( + Name="test.b.com.", + CallerReference=str(hash("foo")), + HostedZoneConfig=dict(PrivateZone=True, Comment="test com"), + VPC={"VPCRegion": region, "VPCId": vpc_id1}, + ) + zone_id = zone["HostedZone"]["Id"].split("/")[2] + + conn.associate_vpc_with_hosted_zone( + HostedZoneId=zone_id, + VPC={"VPCId": vpc_id2, "VPCRegion": region}, + ) + + zone_vpcs = conn.get_hosted_zone(Id=zone_id)["VPCs"] + zone_vpcs.should.have.length_of(2) + zone_vpcs.should.contain({"VPCRegion": region, "VPCId": vpc_id1}) + zone_vpcs.should.contain({"VPCRegion": region, "VPCId": vpc_id2}) + + conn.disassociate_vpc_from_hosted_zone(HostedZoneId=zone_id, VPC={"VPCId": vpc_id1}) + + zone_vpcs = conn.get_hosted_zone(Id=zone_id)["VPCs"] + zone_vpcs.should.have.length_of(1) + zone_vpcs.should.contain({"VPCRegion": region, "VPCId": vpc_id2}) + + +@mock_ec2 +@mock_route53 +def test_route53_disassociate_last_vpc(): + ec2c = boto3.client("ec2", region_name="us-east-1") + vpc_id = ec2c.create_vpc(CidrBlock="10.1.0.0/16")["Vpc"]["VpcId"] + conn = boto3.client("route53", region_name="us-east-1") + zone = conn.create_hosted_zone( + Name="test.b.com.", + CallerReference=str(hash("foo")), + HostedZoneConfig=dict(PrivateZone=True, Comment="test com"), + VPC={"VPCRegion": "us-east-1", "VPCId": vpc_id}, + ) + zone_id = zone["HostedZone"]["Id"].split("/")[2] + + with pytest.raises(ClientError) as exc: + conn.disassociate_vpc_from_hosted_zone( + HostedZoneId=zone_id, VPC={"VPCId": vpc_id} + ) + err = exc.value.response["Error"] + err["Code"].should.equal("LastVPCAssociation") + err["Message"].should.equal( + "The VPC that you're trying to disassociate from the private hosted zone is the last VPC that is associated with the hosted zone. Amazon Route 53 doesn't support disassociating the last VPC from a hosted zone." + )