def setUpClass(cls): if not sys.warnoptions: import warnings warnings.simplefilter("ignore") cls.logger = ConsoleLogger() cls.task_runner = get_task_runner(TESTED_ACTION, KEEP_AND_USE_EXISTING_ACTION_STACK) cls.resource_stack = get_resource_stack( TESTED_ACTION, create_resource_stack_func=cls.create_resource_stack, use_existing=KEEP_AND_USE_EXISTING_RESOURCES_STACK, region_name=region()) assert (cls.resource_stack is not None) cls.ec2 = Ec2(region()) cls.volume_unencrypted = cls.resource_stack.stack_outputs[ "VolumeIdEncryptedUnencrypted"] cls.volume_encrypted_default = cls.resource_stack.stack_outputs[ "VolumeIdEncryptedDefault"] cls.volume_encrypted_custom = cls.resource_stack.stack_outputs[ "VolumeIdEncryptedCustom"] cls.custom_key_arn = cls.resource_stack.stack_outputs[ "EncryptionKeyArn"]
def setUpClass(cls): cls.ec2 = Ec2(region()) cls.elb = Elb(region()) cls.elbv2 = ElbV2(region()) cls.logger = ConsoleLogger() cls.resource_stack = get_resource_stack(TESTED_ACTION, create_resource_stack_func=cls.create_resource_stack, use_existing=KEEP_AND_USE_EXISTING_RESOURCES_STACK, region_name=region()) assert (cls.resource_stack is not None) cls.v1_elb_name = cls.resource_stack.stack_outputs["V1LoadBalancerName"] cls.v2_target_group_arn = cls.resource_stack.stack_outputs["V2TargetGroupArn"] cls.instance_profile = cls.resource_stack.stack_outputs["InstanceProfile"] # noinspection PyPep8,PyBroadException try: cls.ec2.ec2_service.get(services.ec2_service.KEY_PAIRS, KeyNames=[TESTED_ACTION], region=region()) cls.key_pair = TESTED_ACTION except: cls.key_pair = cls.ec2.ec2_client.create_key_pair(KeyName=TESTED_ACTION).get("KeyName") cls.ami_single_volume = cls.ec2.latest_aws_linux_image["ImageId"] cls.task_runner = get_task_runner(TESTED_ACTION, KEEP_AND_USE_EXISTING_ACTION_STACK)
def setUpClass(cls): if not sys.warnoptions: import warnings warnings.simplefilter("ignore") cls.logger = ConsoleLogger() cls.resource_stack = get_resource_stack( TESTED_ACTION, create_resource_stack_func=cls.create_resource_stack, use_existing=KEEP_AND_USE_EXISTING_RESOURCES_STACK, region_name=region()) assert (cls.resource_stack is not None) cls.instance_id = cls.resource_stack.stack_outputs["InstanceId0"] cls.root_volume = Ec2(region()).get_root_volume(cls.instance_id) cls.data_volumes = [ cls.resource_stack.stack_outputs["VolumeId0"], cls.resource_stack.stack_outputs["VolumeId1"] ] cls.task_runner = get_task_runner(TESTED_ACTION, KEEP_AND_USE_EXISTING_ACTION_STACK) cls.ec2 = Ec2(region())
def setUpClass(cls): if not sys.warnoptions: import warnings warnings.simplefilter("ignore") cls.logger = ConsoleLogger() cls.resource_stack = get_resource_stack( TESTED_ACTION, create_resource_stack_func=cls.create_resource_stack, use_existing=KEEP_AND_USE_EXISTING_RESOURCES_STACK, region_name=region()) assert (cls.resource_stack is not None) cls.instance_no_cpu_load = cls.resource_stack.stack_outputs[ "InstanceNoCPULoad"] cls.instance_cpu_load = cls.resource_stack.stack_outputs[ "InstanceCPULoad"] cls.task_runner = get_task_runner( TESTED_ACTION, KEEP_AND_USE_EXISTING_ACTION_STACK, interval="0/{} * * * ?".format(INTERVAL_MINUTES)) cls.ec2 = Ec2(region()) testing.tags.set_ec2_tag_to_delete( ec2_client=cls.ec2, resource_ids=[cls.instance_no_cpu_load, cls.instance_cpu_load]) cls.metrics_client = CloudwatchMetrics(region())
def setUpClass(cls): if not sys.warnoptions: import warnings warnings.simplefilter("ignore") cls.logger = ConsoleLogger() cls.resource_stack = get_resource_stack( TESTED_ACTION, create_resource_stack_func=cls.create_resource_stack, use_existing=KEEP_AND_USE_EXISTING_RESOURCES_STACK, region_name=region()) assert (cls.resource_stack is not None) cls.ec2 = Ec2(region()) cls.instance_id = cls.resource_stack.stack_outputs["InstanceId"] if KEEP_AND_USE_EXISTING_ACTION_STACK: cls.ec2.start_instance(cls.instance_id) testing.tags.set_ec2_tag_to_delete(ec2_client=cls.ec2, resource_ids=[cls.instance_id]) cls.task_runner = get_task_runner(TESTED_ACTION, KEEP_AND_USE_EXISTING_ACTION_STACK) tags = cls.ec2.get_instance_tags(cls.instance_id) cls.original_tags = { t: tags[t] for t in tags if not t.startswith("aws:") }
def test_copy_unencrypted_snapshot_same_region(self): test_method = inspect.stack()[0][3] self.cleanup_leftover_source_snapshots(test_method) self.logger.test("Creating source snapshot") source_snapshot_unencrypted = self.ec2.create_snapshot(self.volume_unencrypted, tags={ "copied-tag": "copied-value", "not-copied-tag": "not-copied-value", "Name": "Ec2CopySnapshot_{}".format(test_method), tasklist_tagname(TESTED_ACTION): test_method }, description="Snapshot for testing Ec2CopySnapshot : {}".format(test_method)) self.snapshots.append(source_snapshot_unencrypted["SnapshotId"]) testing.tags.set_ec2_tag_to_delete(self.ec2, [source_snapshot_unencrypted["SnapshotId"]]) parameters = { copy_snapshot.PARAM_DESTINATION_REGION: region(), copy_snapshot.PARAM_ACCOUNTS_VOLUME_CREATE_PERMISSIONS: ["123456789012"], copy_snapshot.PARAM_COPIED_SNAPSHOT_TAGS: "copied-tag", copy_snapshot.PARAM_SNAPSHOT_DESCRIPTION: "{{{}}}".format(copy_snapshot.TAG_PLACEHOLDER_SOURCE_DESCRIPTION), copy_snapshot.PARAM_SNAPSHOT_TAGS: testing.tags.common_placeholder_tags( test_delete=False, placeholders=[ copy_snapshot.TAG_PLACEHOLDER_SOURCE_REGION, copy_snapshot.TAG_PLACEHOLDER_SOURCE_SNAPSHOT_ID, copy_snapshot.TAG_PLACEHOLDER_SOURCE_VOLUME, copy_snapshot.TAG_PLACEHOLDER_OWNER_ACCOUNT]), copy_snapshot.PARAM_SOURCE_TAGS: testing.tags.common_placeholder_tags([ copy_snapshot.TAG_PLACEHOLDER_COPIED_SNAPSHOT_ID, copy_snapshot.TAG_PLACEHOLDER_COPIED_REGION ]), copy_snapshot.PARAM_COPIED_SNAPSHOTS: copy_snapshot.COPIED_OWNED_BY_ACCOUNT, copy_snapshot.PARAM_DELETE_AFTER_COPY: False, copy_snapshot.PARAM_ENCRYPTED: False } self.logger.test("Running task") self.task_runner.run(parameters, task_name=test_method, complete_check_polling_interval=10) self.assertTrue(self.task_runner.success(), "Task executed successfully") snapshot_copy_id = self.task_runner.results[0].result["copy-snapshot-id"] self.snapshots.append(snapshot_copy_id) self.logger.test("[X] Task completed") self.check_copy_snapshot(snapshot_copy_id, source_snapshot_unencrypted, region()) self.check_source_snapshot(source_snapshot_unencrypted["SnapshotId"], snapshot_copy_id, test_method, region()) assert (self.task_runner.max_concurrency == 5) assert (self.task_runner.concurrency_key == "ec2:CopySnapshot:{}:{}".format(self.task_runner.tested_account, self.task_runner.tested_region))
def test_copy_snapshot_encrypted_with_default_key(self): test_method = inspect.stack()[0][3] self.cleanup_leftover_source_snapshots(test_method) snapshot_unencrypted = self.ec2.create_snapshot(self.volume_unencrypted, tags={ "Name": "Ec2CopySnapshot_{}".format(test_method), tasklist_tagname(TESTED_ACTION): test_method }, description="Snapshot for testing Ec2CopySnapshot : {}".format(test_method)) assert (snapshot_unencrypted is not None) self.snapshots.append(snapshot_unencrypted["SnapshotId"]) parameters = { copy_snapshot.PARAM_DESTINATION_REGION: region(), copy_snapshot.PARAM_ENCRYPTED: True } self.logger.test("Running task") self.task_runner.run(parameters, task_name=test_method, complete_check_polling_interval=10) self.assertTrue(self.task_runner.success(), "Task executed successfully") snapshot_copy_id = self.task_runner.results[0].result["copy-snapshot-id"] self.snapshots.append(snapshot_copy_id) self.logger.test("[X] Task completed") self.logger.test("Checking snapshot copy") snapshot_copy = self.ec2.get_snapshot(snapshot_copy_id) self.assertIsNotNone(snapshot_copy, "Snapshot created") self.assertTrue(snapshot_copy["Encrypted"], "Snapshot is encrypted") self.assertEqual(snapshot_copy["KmsKeyId"], self.ec2.ebs_default_key_arn, "Default EBS encryption key is used") self.logger.test("[X] Snapshot created and encrypted")
def test_snapshot_not_longer_available(self): def delete_snapshot_after_select(tracker): for item in tracker.task_items: self.ec2.delete_snapshots(snapshot_ids=[item.get(handlers.TASK_TR_RESOURCES, {}).get("SnapshotId")]) test_method = inspect.stack()[0][3] self.cleanup_leftover_source_snapshots(test_method) self.logger.test("Creating source snapshot") source_snapshot = self.ec2.create_snapshot(self.volume_unencrypted, tags={ "Name": "Ec2CopySnapshot_{}".format(test_method), tasklist_tagname(TESTED_ACTION): test_method }, description="Snapshot for testing Ec2CopySnapshot : {}".format(test_method)) assert (source_snapshot is not None) self.snapshots.append(source_snapshot["SnapshotId"]) parameters = { copy_snapshot.PARAM_DESTINATION_REGION: region(), } self.logger.test("Running task to copy snapshot") self.task_runner.run(parameters, task_name=test_method, complete_check_polling_interval=10, run_after_select=delete_snapshot_after_select) self.logger.test("[X] Task completed") self.assertEqual(1, len(self.task_runner.results), "Snapshot not longer available") self.logger.test("[X] Snapshot was not longer available")
def test_snapshot_only_copied_once(self): test_method = inspect.stack()[0][3] self.cleanup_leftover_source_snapshots(test_method) self.logger.test("Creating source snapshot") source_snapshot = self.ec2.create_snapshot(self.volume_unencrypted, tags={ "Name": "Ec2CopySnapshot_{}".format(test_method), tasklist_tagname(TESTED_ACTION): test_method }, description="Snapshot for testing Ec2CopySnapshot : {}".format(test_method)) assert (source_snapshot is not None) self.snapshots.append(source_snapshot["SnapshotId"]) parameters = { copy_snapshot.PARAM_DESTINATION_REGION: region(), } self.logger.test("Running task to copy snapshot") self.task_runner.run(parameters, task_name=test_method, complete_check_polling_interval=10) self.assertTrue(self.task_runner.success(), "Task executed successfully") snapshot_copy_id = self.task_runner.results[0].result["copy-snapshot-id"] self.snapshots.append(snapshot_copy_id) self.logger.test("Running task again") self.task_runner.run(parameters, task_name=test_method, complete_check_polling_interval=10) self.logger.test("[X] Task completed") self.assertEqual(0, len(self.task_runner.results), "Snapshot already copied") self.logger.test("[X] Snapshot was not copied for second time")
def test_copy_snapshot_description(self): test_method = inspect.stack()[0][3] self.cleanup_leftover_source_snapshots(test_method) self.logger.test("Creating source snapshot") source_snapshot = self.ec2.create_snapshot(self.volume_unencrypted, tags={ "Name": "Ec2CopySnapshot_{}".format(test_method), tasklist_tagname(TESTED_ACTION): test_method }, description="Snapshot for testing Ec2CopySnapshot : {}".format(test_method)) self.snapshots.append(source_snapshot["SnapshotId"]) parameters = { copy_snapshot.PARAM_DESTINATION_REGION: region(), copy_snapshot.PARAM_COPIED_SNAPSHOTS: copy_snapshot.COPIED_OWNED_BY_ACCOUNT, copy_snapshot.PARAM_DELETE_AFTER_COPY: False, copy_snapshot.PARAM_ENCRYPTED: False } self.logger.test("Running task") self.task_runner.run(parameters, task_name=test_method, complete_check_polling_interval=10) self.assertTrue(self.task_runner.success(), "Task executed successfully") snapshot_copy_id = self.task_runner.results[0].result["copy-snapshot-id"] self.snapshots.append(snapshot_copy_id) self.logger.test("[X] Task completed") copied_snapshot = self.ec2.get_snapshot(snapshot_copy_id) self.assertEqual(source_snapshot.get("Description"), copied_snapshot.get("Description"), "Description copied as default") self.logger.test("[X]Source description copied")
def create_resource_stack(cls, resource_stack_name): try: cls.logger.test("Creating test resources stack {}", resource_stack_name) ami = Ec2(region()).latest_aws_linux_image["ImageId"] resource_stack = Stack(resource_stack_name, region=region()) resource_stack.create_stack(template_file=template_path(__file__, TEST_RESOURCES_TEMPLATE), iam_capability=True, params={ "InstanceAmi": ami, "InstanceType": "t2.micro", "TaskListTagName": tasklist_tagname(TESTED_ACTION), "TaskListTagValue": ",".join(cls.get_methods()) }) return resource_stack except Exception as ex: cls.logger.test("Error creating stack {}, {}", resource_stack_name, ex) return None
def test_copy_default_key_encrypted_snapshot_same_region(self): test_method = inspect.stack()[0][3] self.cleanup_leftover_source_snapshots(test_method) self.logger.test("Creating source snapshot") source_snapshot_encrypted_default = self.ec2.create_snapshot( self.volume_encrypted_default, tags={ "Name": "Ec2CopySnapshot_{}".format(test_method), tasklist_tagname(TESTED_ACTION): test_method }, description="Snapshot for testing Ec2CopySnapshot : {}".format( test_method)) self.snapshots.append(source_snapshot_encrypted_default["SnapshotId"]) parameters = {copy_snapshot.PARAM_DESTINATION_REGION: region()} self.logger.test("Running task") self.task_runner.run(parameters, task_name=test_method, complete_check_polling_interval=10) self.assertTrue(self.task_runner.success(), "Task executed successfully") snapshot_copy_id = self.task_runner.results[0].result[ "copy-snapshot-id"] self.snapshots.append(snapshot_copy_id) self.logger.test("[X] Task completed") self.logger.test("Checking snapshot copy") snapshot_copy = self.ec2.get_snapshot(snapshot_copy_id) self.assertIsNotNone(snapshot_copy, "Snapshot created")
def create_resource_stack(cls, resource_stack_name): try: cls.logger.test("Creating test resources stack {}", resource_stack_name) ami = Ec2(region()).latest_aws_linux_image["ImageId"] resource_stack = Stack(resource_stack_name, region=region()) resource_stack.create_stack(template_file=template_path(__file__, TEST_RESOURCES_TEMPLATE), timeout=1200, iam_capability=True, params={ "InstanceAmi": ami, "InstanceType": TEST_INSTANCE_TYPES[0] }) return resource_stack except Exception as ex: cls.logger.test("Error creating stack {}, {}", resource_stack_name, ex) return None
def create_resource_stack(cls, resource_stack_name): try: cls.logger.test("Creating test resources stack {}", resource_stack_name) resource_stack = Stack(resource_stack_name, region=region()) resource_stack.create_stack(template_file=template_path(__file__, TEST_RESOURCES_TEMPLATE), iam_capability=True, params={}) return resource_stack except Exception as ex: cls.logger.test("Error creating stack {}, {}", resource_stack_name, ex) return None
def create_resource_stack(cls, resource_stack_name): try: cls.logger.test("Creating test resources stack {}", resource_stack_name) role = cls.task_runner.action_stack.stack_resources[testing.OPS_AUTOMATOR_ROLE_NAME]["PhysicalResourceId"] resource_stack = Stack(resource_stack_name, region=region()) resource_stack.create_stack(template_file=template_path(__file__, TEST_RESOURCES_TEMPLATE), iam_capability=True, params={"TaskRole": role}) return resource_stack except Exception as ex: cls.logger.test("Error creating stack {}, {}", resource_stack_name, ex) return None
def setUpClass(cls): cls.logger = ConsoleLogger() cls.resource_stack = get_resource_stack( TESTED_ACTION, create_resource_stack_func=cls.create_resource_stack, use_existing=KEEP_AND_USE_EXISTING_RESOURCES_STACK, region_name=region()) assert (cls.resource_stack is not None) cls.dynamodb = DynamoDB(region=region()) cls.table_name = cls.resource_stack.stack_outputs["TableName"] cls.task_runner = get_task_runner(TESTED_ACTION, KEEP_AND_USE_EXISTING_ACTION_STACK) cls.logger.debug( "Waiting for continuous backups to become available for table {}", cls.table_name) assert (cls.dynamodb.wait_until_table_backups_available( cls.table_name))
def setUpClass(cls): cls.logger = ConsoleLogger() cls.resource_stack = get_resource_stack(TESTED_ACTION, create_resource_stack_func=cls.create_resource_stack, use_existing=KEEP_AND_USE_EXISTING_RESOURCES_STACK, region_name=region()) assert (cls.resource_stack is not None) cls.volume_id = cls.resource_stack.stack_outputs["VolumeId0"] cls.ec2 = Ec2(region()) cls.task_runner = get_task_runner(TESTED_ACTION, KEEP_AND_USE_EXISTING_ACTION_STACK)
def create_resource_stack(cls, resource_stack_name): try: cls.logger.test("Creating test resources stack {}", resource_stack_name) resource_stack = Stack(resource_stack_name, region=region()) default_vpc_id = cls.ec2.get_default_vpc() assert default_vpc_id is not None resource_stack.create_stack(template_file=template_path(__file__, TEST_RESOURCES_TEMPLATE), timeout=1200, iam_capability=True, params={ "VpcId": default_vpc_id["VpcId"], }) return resource_stack except Exception as ex: cls.logger.test("Error creating stack {}, {}", resource_stack_name, ex) return None
def check_snapshot(snap_id, source_volume_id): checked_snapshot = self.ec2.get_snapshot(snap_id) self.assertIsNotNone(checked_snapshot, "Snapshot does exist") self.logger.test("[X] Snapshot was created") snapshot_tags = checked_snapshot.get("Tags", {}) self.assertTrue(TagFilterExpression("InstanceTag=Instance0").is_match(snapshot_tags), "Instance tag copied") self.logger.test("[X] Instance tags copied") source_volume = self.ec2.get_volume(source_volume_id) assert (source_volume is not None) device = source_volume.get("Attachments", [{}])[0].get("Device", "") if source_volume_id in self.data_volumes: volume_tags = source_volume.get("Tags", {}) self.assertTrue( TagFilterExpression("VolumeTag={}".format(volume_tags.get("VolumeTag", ""))).is_match(snapshot_tags), "Volume tag copied") self.logger.test("[X] Volume tags copied") snapshot_placeholders = { create_snapshot_action.TAG_PLACEHOLDER_VOLUME_ID: source_volume_id, create_snapshot_action.TAG_PLACEHOLDER_INSTANCE_ID: self.instance_id, create_snapshot_action.TAG_PLACEHOLDER_DEVICE: device } self.assertTrue(testing.tags.verify_placeholder_tags(snapshot_tags, snapshot_placeholders), "All placeholder tags set on snapshot {}".format(snap_id)) self.logger.test("[X] Placeholder tags created") self.assertTrue(TagFilterExpression( "{}={}".format(actions.marker_snapshot_tag_source_source_volume_id(), source_volume_id)).is_match( snapshot_tags), "Source volume tag set") self.logger.test("[X] Source volume tags created") self.assertTrue(self.ec2.get_snapshot_create_volume_permission_users(snap_id) == ["123456789012"], "Create volume permissions set") self.logger.test("[X] Volume create permissions set") expected_name = "snapshot-{}-{}-{}".format(self.task_runner.action_stack_name, self.instance_id, source_volume_id) self.assertEqual(expected_name, snapshot_tags["Name"], "Name has been set") self.logger.test("[X] Snapshot name set") description = checked_snapshot.get("Description", "") self.assertTrue( all([p in description for p in [source_volume_id, self.instance_id, region(), self.task_runner.task_name]]), "Description is set") self.logger.test("[X] Snapshot description set")
def create_resource_stack(cls, resource_stack_name): try: cls.logger.test("Creating test resources stack {}", resource_stack_name) resource_stack = Stack(resource_stack_name, region=region()) resource_stack.create_stack(template_file=template_path( __file__, TEST_RESOURCES_TEMPLATE), iam_capability=False, params={ "IndexName": INDEX_NAME, "TaskListTagName": tasklist_tagname(TESTED_ACTION), "TaskListTagValue": "/".join(cls.get_methods()) }) return resource_stack except Exception as ex: cls.logger.test("Error creating stack {}, {}", resource_stack_name, ex) return None
def test_delete_by_retention_count(self): snapshots_to_create = 4 snapshots_to_keep = 2 test_method = inspect.stack()[0][3] self.cleanup_leftover_source_snapshots(test_method) for i in range(0, snapshots_to_create): snapshot = self.ec2.create_snapshot(self.volume_id, tags={ tasklist_tagname(TESTED_ACTION): test_method }, wait_to_complete=300) assert (snapshot is not None) self.created_snapshots.append(snapshot["SnapshotId"]) try: parameters = { delete_snapshot_action.PARAM_RETENTION_COUNT: snapshots_to_keep, delete_snapshot_action.PARAM_RETENTION_DAYS: 0 } test_method = inspect.stack()[0][3] self.logger.test("Running task") self.task_runner.run(parameters, task_name=test_method, debug=False) self.assertTrue(self.task_runner.success(expected_executed_tasks=1), "Task executed successfully") self.logger.test("[X] Task completed") self.deleted_snapshots = getattr(self.task_runner.results[0], "result", {})["deleted"][region()] self.assertEqual(sorted(self.created_snapshots[0:snapshots_to_create - snapshots_to_keep]), sorted(self.deleted_snapshots), "Expected snapshots deleted") self.logger.test("[X] {} oldest snapshots deleted out of {}", len(self.deleted_snapshots), len(self.created_snapshots)) remaining_snapshots = [s["SnapshotId"] for s in self.ec2.get_snapshots_for_volume(volume_id=self.volume_id)] self.assertEqual(sorted(self.created_snapshots[snapshots_to_create - snapshots_to_keep:]), sorted(remaining_snapshots), "Expected snapshots retained") self.logger.test("[X] {} latest snapshots retained out of {}", len(remaining_snapshots), len(self.created_snapshots)) finally: self.delete_volume_snapshots()
def test_delete_by_retention_count_with_copied_snapshot(self): test_method = inspect.stack()[0][3] self.cleanup_leftover_source_snapshots(test_method) self.logger.test("Creating (source) snapshot") snapshot_source = self.ec2.create_snapshot(self.volume_id, tags={ tasklist_tagname(TESTED_ACTION): test_method }, wait_to_complete=300) assert (snapshot_source is not None) self.created_snapshots.append(snapshot_source["SnapshotId"]) self.logger.test("Copying snapshot") snapshot_copy = self.ec2.copy_snapshot(snapshot_id=snapshot_source["SnapshotId"], destination_region=region(), tags={ tasklist_tagname(TESTED_ACTION): test_method }) assert (snapshot_copy is not None) self.created_snapshots.append(snapshot_copy["SnapshotId"]) set_snapshot_sources_tags(snapshot_id=snapshot_copy["SnapshotId"], source_volume_id=self.volume_id, source_snapshot_id=snapshot_source["SnapshotId"]) try: parameters = { delete_snapshot_action.PARAM_RETENTION_COUNT: 1, delete_snapshot_action.PARAM_RETENTION_DAYS: 0 } self.logger.test("Running task") self.task_runner.run(parameters, task_name=test_method) self.assertTrue(self.task_runner.success(expected_executed_tasks=1), "Task executed successfully") self.logger.test("[X] Task completed") self.deleted_snapshots = getattr(self.task_runner.results[0], "result", {})["deleted"][region()] self.logger.test("Checking deleted snapshot") self.assertEqual(1, len(self.deleted_snapshots), "Deleted single snapshot") self.assertEqual(self.deleted_snapshots[0], snapshot_source["SnapshotId"], "Oldest (source) snapshot deleted") self.logger.test("[X] Source snapshot deleted ") remaining_snapshot = self.ec2.get_snapshot(snapshot_copy["SnapshotId"]) self.assertIsNotNone(remaining_snapshot, "Copied snapshot still exists") self.logger.test("[X] Copied snapshot still exists") finally: self.delete_volume_snapshots()