def test_document(): """Verify correct deployment and use of document.""" ssm_doc = ssm_testing.SSMTester(ssm_client=ssm_client, doc_filename=os.path.join( DOC_DIR, 'Documents', 'aws-DeleteCloudFormation.json'), doc_name=SSM_DOC_NAME, doc_type='Automation') test_cf_stack = ssm_testing.CFNTester( cfn_client=cfn_client, template_filename=os.path.join(DOC_DIR, 'Tests', 'CloudFormationTemplates', 'TwoInstances.yml'), stack_name=INSTANCE_CFN_STACK_NAME) automation_role = ssm_doc.get_automation_role(sts_client, iam_client, SERVICE_ROLE_NAME) LOGGER.info('Starting instances for testing') stack = test_cf_stack.create_stack([{ 'ParameterKey': 'AMI', 'ParameterValue': AMI_ID }, { 'ParameterKey': 'INSTANCETYPE', 'ParameterValue': INSTANCE_TYPE }]) try: LOGGER.info('Creating automation document') assert ssm_doc.create_document() == 'Active', ('Document not ' 'created ' 'successfully') execution = ssm_doc.execute_automation( params={ 'StackNameOrId': [INSTANCE_CFN_STACK_NAME], 'AutomationAssumeRole': [automation_role] }) LOGGER.info( 'Verifying automation executions have concluded successfully') assert ssm_doc.automation_execution_status( ssm_client, execution) == 'Success', 'Stack not deleted correctly' LOGGER.info('Verifying stack is deleted') # deleted stacks require the Stack ID, not the name, as the param to describe_stacks stack_desc = cfn_client.describe_stacks(StackName=stack['StackId']) stack_status = stack_desc['Stacks'][0]['StackStatus'] assert stack_status == 'DELETE_COMPLETE', \ 'Stack deletion failed with status: ' + stack_status finally: ssm_doc.destroy()
def testdocument(): """Verify correct deployment and use of document.""" cfn_client = boto3.client('cloudformation', region_name=REGION) ec2_client = boto3.client('ec2', region_name=REGION) ssm_client = boto3.client('ssm', region_name=REGION) ssm_doc = ssm_testing.SSMTester( ssm_client=ssm_client, doc_filename=os.path.join(DOC_DIR, 'Documents', 'aws-RestartEC2Instance.json'), doc_name=SSM_DOC_NAME, doc_type='Automation' ) test_cf_stack = ssm_testing.CFNTester( cfn_client=cfn_client, template_filename=os.path.join(DOC_DIR, 'Tests', 'CloudFormationTemplates', 'TwoInstances.yml'), stack_name=INSTANCE_CFN_STACKNAME ) automation_role = ssm_doc.get_automation_role( boto3.client('sts', region_name=REGION), boto3.client('iam', region_name=REGION), SERVICE_ROLE_NAME ) LOGGER.info('Starting instances for testing') test_cf_stack.create_stack([ { 'ParameterKey': 'AMI', 'ParameterValue': AMIID }, { 'ParameterKey': 'INSTANCETYPE', 'ParameterValue': INSTANCE_TYPE } ]) try: LOGGER.info('Creating automation document') assert ssm_doc.create_document() == 'Active', ('Document not ' 'created ' 'successfully') LOGGER.info('Running automation to restart multiple instances ' '(using defined role)') instances_1_2 = [test_cf_stack.stack_outputs['Instance0Id'], test_cf_stack.stack_outputs['Instance1Id']] execution = ssm_doc.execute_automation( params={'InstanceId': instances_1_2, 'AutomationAssumeRole': [automation_role]}) LOGGER.info('Verifying automation executions have concluded successfully') assert ssm_doc.automation_execution_status( ssm_client, execution ) == 'Success', 'Instances not restarted successfully' LOGGER.info('Verifying all instances are running') describe_res = ec2_client.describe_instance_status( InstanceIds=instances_1_2, IncludeAllInstances=True ) assert all(d['InstanceState']['Name'] == 'running' for d in describe_res['InstanceStatuses']) is True, ( # noqa pylint: disable=line-too-long 'Instances not started') finally: test_cf_stack.delete_stack() ssm_doc.destroy()
def test_update_document(self): cfn_client = boto3.client('cloudformation', region_name=REGION) ssm_client = boto3.client('ssm', region_name=REGION) ssm_doc = ssm_testing.SSMTester(ssm_client=ssm_client, doc_filename=os.path.join( DOC_DIR, 'Documents/aws-DeleteImage.json'), doc_name=SSM_DOC_NAME, doc_type='Automation') test_cf_stack = ssm_testing.CFNTester( cfn_client=cfn_client, template_filename=os.path.abspath( os.path.join( DOC_DIR, "Tests/CloudFormationTemplates/TestTemplate.yml")), stack_name=TEST_CFN_STACK_NAME) LOGGER.info('Creating Test Stack') LOGGER.info('AMI:' + LINUX_AMI_ID) LOGGER.info('Instance Type:' + LINUX_INSTANCE_TYPE) test_cf_stack.create_stack([{ 'ParameterKey': 'AMI', 'ParameterValue': LINUX_AMI_ID }, { 'ParameterKey': 'INSTANCETYPE', 'ParameterValue': LINUX_INSTANCE_TYPE }, { 'ParameterKey': 'UserARN', 'ParameterValue': sts_client.get_caller_identity().get('Arn') }]) LOGGER.info('Test Stack has been created') # Verify role exists role_arn = test_cf_stack.stack_outputs['AutomationAssumeRoleARN'] verify_role_created(role_arn) # Create Amazon Machine Image (AMI) of the Amazon EC2 Instance instance_id = test_cf_stack.stack_outputs['InstanceId'] imageName = instance_id ec2client = boto3.client('ec2') ec2_resource = boto3.resource('ec2') instance = ec2_resource.Instance(instance_id) image = instance.create_image(Name=imageName) # Test Amazon Machine Image (AMI) and associated Snapshot exist describeImage = ec2client.describe_images( Filters=[{ 'Name': 'name', 'Values': [imageName], }]) ImageId = describeImage['Images'][0]['ImageId'] waiter = ec2client.get_waiter('image_available') waiter.wait(ImageIds=[ImageId]) imageData = ec2_resource.Image(ImageId) SnapshotId = imageData.block_device_mappings[0]['Ebs']['SnapshotId'] waiter = ec2client.get_waiter('snapshot_completed') waiter.wait(SnapshotIds=[SnapshotId]) time.sleep(60) try: LOGGER.info("Creating automation document") self.assertEqual(ssm_doc.create_document(), 'Active') instance_id = test_cf_stack.stack_outputs['InstanceId'] execution = ssm_doc.execute_automation(params={ 'ImageId': [ImageId], 'AutomationAssumeRole': [role_arn] }) self.assertEqual( ssm_doc.automation_execution_status(ssm_client, execution, False), 'Success') LOGGER.info('Delete Amazon Machine Image has been initiated') ec2_resource = boto3.resource('ec2') ec2client = boto3.client('ec2') instance = ec2_resource.Instance(instance_id) # Test Amazon Machine Image exist image_response = ec2client.describe_images(Filters=[ { 'Name': 'image-id', 'Values': [ ImageId, ] }, ]) images = image_response['Images'] self.assertEqual(len(images), 0) # Test Amazon Machine Snapshot associated to Amazon Machine Image exist snapshot_response = ec2client.describe_snapshots( Filters=[{ 'Name': 'snapshot-id', 'Values': [SnapshotId] }]) finally: try: ssm_doc.destroy() except Exception: pass test_cf_stack.delete_stack()
def test_update_document(self): LOGGER.info("TESTING Automation Document DISABLE Case") cfn_client = boto3.client('cloudformation', region_name=REGION) ssm_client = boto3.client('ssm', region_name=REGION) ssm_doc = ssm_testing.SSMTester( ssm_client=ssm_client, doc_filename=os.path.join( DOC_DIR, 'Output/aws-ConfigureCloudWatchOnEC2Instance.json'), doc_name=SSM_DOC_NAME, doc_type='Automation') test_cf_stack = ssm_testing.CFNTester( cfn_client=cfn_client, template_filename=os.path.join( DOC_DIR, 'Tests/CloudFormationTemplates/TestTemplate.yml'), stack_name=TEST_CFN_STACK_NAME) LOGGER.info('Creating Test Stack') test_cf_stack.create_stack([{ 'ParameterKey': 'UserARN', 'ParameterValue': sts_client.get_caller_identity().get('Arn') }, { 'ParameterKey': 'AMI', 'ParameterValue': AMIID }, { 'ParameterKey': 'INSTANCETYPE', 'ParameterValue': INSTANCETYPE }]) LOGGER.info('Test Stack has been created') LOGGER.info(test_cf_stack) # Verify role exists role_arn = test_cf_stack.stack_outputs['AutomationAssumeRoleARN'] verify_role_created(role_arn) LOGGER.info('Creating automation document') self.assertEqual(ssm_doc.create_document(), 'Active') ec2_instance_id = test_cf_stack.stack_outputs['InstanceId'] LOGGER.info('EC-2 instance spun up, id = ' + ec2_instance_id) try: LOGGER.info('Running the Automation-Document now!') execution = ssm_doc.execute_automation( params={ 'InstanceId': [ec2_instance_id], 'status': [MONITOR_STATE], 'AutomationAssumeRole': [role_arn] }) self.assertEqual( ssm_doc.automation_execution_status(ssm_client, execution, False), 'Success') LOGGER.info('Automation-Execution was successful!') end_state = verify_monitorstate_changed(ec2_instance_id) LOGGER.info('test subject host Monitoring state is ' + end_state) self.assertEqual( end_state, REQUIRED_ENDSTATE, "The EC-2 instance monitoring failed to change to disabled") LOGGER.info('End of Disable Case Test') finally: try: ssm_doc.destroy() except Exception: pass test_cf_stack.delete_stack()
def test_update_document(self): cfn_client = boto3.client('cloudformation', region_name=REGION) ssm_client = boto3.client('ssm', region_name=REGION) ssm_doc = ssm_testing.SSMTester( ssm_client=ssm_client, doc_filename=os.path.join(DOC_DIR, 'Output/aws-StopRDSInstance.json'), doc_name=SSM_DOC_NAME, doc_type='Automation' ) test_cf_stack = ssm_testing.CFNTester( cfn_client=cfn_client, template_filename=os.path.abspath(os.path.join( DOC_DIR, "Tests/CloudFormationTemplates/TestTemplate.yml")), stack_name=TEST_CFN_STACK_NAME ) LOGGER.info('Creating Test Stack') test_cf_stack.create_stack([ { 'ParameterKey': 'UserARN', 'ParameterValue': sts_client.get_caller_identity().get('Arn') } ]) LOGGER.info('Test Stack has been created') # Verify role exists role_arn = test_cf_stack.stack_outputs['AutomationAssumeRoleARN'] verify_role_created(role_arn) LOGGER.info("Creating automation document") self.assertEqual(ssm_doc.create_document(), 'Active') db_instance_id = test_cf_stack.stack_outputs['DBInstanceId'] try: execution = ssm_doc.execute_automation( params={'DBInstanceIdentifier': [db_instance_id], 'DBSnapshotIdentifier': ['{db-instance-id}-stopped'], 'OverwriteExistingSnapshot': ["True"], 'StoppedInstanceTags': [ 'Key=StopExecutionId,Value={execution-id};' 'Key=StopSnapshot,Value={db-snapshot-id};' 'Key=StopDateTime,Value={iso-date};' 'Key=StopDate,Value={iso-date};' 'Key=StopTime,Value={iso-time}'], 'SnapshotTags': [ 'Key=StopExecutionId,Value={execution-id};' 'Key=StopDBInstanceId,Value={db-instance-id};' 'Key=StopDateTime,Value={iso-date};' 'Key=StopDate,Value={iso-date};' 'Key=StopTime,Value={iso-time}'] }) self.assertEqual(ssm_doc.automation_execution_status(ssm_client, execution, False), 'Success') self.assertTrue(DocumentTest.verify_database_stopped(db_instance_id)) LOGGER.info("Instance {} was stopped".format(db_instance_id)) snapshot_id = "{}-stopped".format(db_instance_id) self.assertTrue(DocumentTest.verify_snapshot_exists(snapshot_id)) account = sts_client.get_caller_identity().get("Account") db_arn = "arn:aws:rds:{}:{}:db:{}".format(REGION, account, db_instance_id) self.assertTrue(self.verify_tags_are_set(db_arn, [ "StopExecutionId", "StopSnapshot", "StopDateTime", "StopDate", "StopTime"])) LOGGER.info("All expected tags are set for stopped instance") snapshot_arn = "arn:aws:rds:{}:{}:snapshot:{}-stopped".format(REGION, account, db_instance_id) self.assertTrue(self.verify_tags_are_set(snapshot_arn, [ "StopExecutionId", "StopDBInstanceId", "StopDateTime", "StopDate", "StopTime"])) LOGGER.info("All expected tags are set created snapshot") DocumentTest.delete_snapshot(snapshot_id) finally: try: ssm_doc.destroy() except Exception: pass test_cf_stack.delete_stack()
def test_document(): """Verify correct deployment and use of document.""" ssm_doc = ssm_testing.SSMTester( ssm_client=ssm_client, doc_filename=os.path.join( DOC_DIR, 'Documents', 'aws-DeleteCloudFormationWithApproval.json'), doc_name=SSM_DOC_NAME, doc_type='Automation') test_cf_stack = ssm_testing.CFNTester( cfn_client=cfn_client, template_filename=os.path.join(DOC_DIR, 'Tests', 'CloudFormationTemplates', 'TwoInstances.yml'), stack_name=INSTANCE_CFN_STACK_NAME) automation_role = ssm_doc.get_automation_role(sts_client, iam_client, SERVICE_ROLE_NAME) LOGGER.info('Starting instances for testing') stack = test_cf_stack.create_stack([{ 'ParameterKey': 'AMI', 'ParameterValue': AMI_ID }, { 'ParameterKey': 'INSTANCETYPE', 'ParameterValue': INSTANCE_TYPE }]) try: LOGGER.info('Creating automation document') assert ssm_doc.create_document( ) == 'Active', 'Document not created successfully' user_arn = sts_client.get_caller_identity()['Arn'] sns_topic_arn = test_cf_stack.stack_outputs['SNSTopicArn'] LOGGER.info("User ARN for approval: " + user_arn) LOGGER.info("SNS Topic ARN for approval: " + sns_topic_arn) execution = ssm_doc.execute_automation( params={ 'StackNameOrId': [INSTANCE_CFN_STACK_NAME], 'AutomationAssumeRole': [automation_role], 'Approvers': [user_arn], 'SNSTopicArn': [sns_topic_arn] }) # since this automation requires approval to continue, the correct status at this point should be 'Waiting' assert ssm_doc.automation_execution_status(ssm_client, execution, False) == 'Waiting', \ 'Automation not waiting for approval' LOGGER.info('Approving continuation of execution') ssm_client.send_automation_signal(AutomationExecutionId=execution, SignalType='Approve') LOGGER.info( 'Verifying automation executions have concluded successfully') assert ssm_doc.automation_execution_status( ssm_client, execution) == 'Success', 'Stack not deleted correctly' LOGGER.info('Verifying stack is deleted') # deleted stacks require the Stack ID, not the name, as the param to describe_stacks stack_desc = cfn_client.describe_stacks(StackName=stack['StackId']) stack_status = stack_desc['Stacks'][0]['StackStatus'] assert stack_desc['Stacks'][0]['StackStatus'] == 'DELETE_COMPLETE', \ 'Stack deletion failed with status: ' + stack_status finally: ssm_doc.destroy()
def test_update_document(self): cfn_client = boto3.client('cloudformation', region_name=REGION) ssm_client = boto3.client('ssm', region_name=REGION) ssm_doc = ssm_testing.SSMTester(ssm_client=ssm_client, doc_filename=os.path.join( DOC_DIR, 'Output/aws-CopySnapshot.json'), doc_name=SSM_DOC_NAME, doc_type='Automation') LOGGER.info("Creating automation document") self.assertEqual(ssm_doc.create_document(), 'Active') test_cf_stack = ssm_testing.CFNTester( cfn_client=cfn_client, template_filename=os.path.abspath( os.path.join( DOC_DIR, "Tests/CloudFormationTemplates/TestTemplate.yml")), stack_name=TEST_CFN_STACK_NAME) LOGGER.info('Creating Test Stack') test_cf_stack.create_stack([{ 'ParameterKey': 'UserARN', 'ParameterValue': sts_client.get_caller_identity().get('Arn') }]) LOGGER.info('Test Stack has been created') # Verify role exists role_arn = test_cf_stack.stack_outputs['AutomationAssumeRoleARN'] verify_role_created(role_arn) # Now create the snapshot LOGGER.info('Creating test snapshot') volume_id = test_cf_stack.stack_outputs['VolumeId'] snapshot = create_snapshot(volume_id) try: description = "Copied from " + snapshot.snapshot_id execution = ssm_doc.execute_automation( params={ 'SnapshotId': [snapshot.snapshot_id], 'SourceRegion': [REGION], 'Description': [description], 'AutomationAssumeRole': [role_arn] }) self.assertEqual( ssm_doc.automation_execution_status(ssm_client, execution, False), 'Success') LOGGER.info('Now verifying the copied snapshot') response = ssm_client.get_automation_execution( AutomationExecutionId=execution) str_payload = response['AutomationExecution']['Outputs'][ 'copySnapshot.Payload'][0] payload = json.loads(str_payload) new_snapshot_id = payload['SnapshotId'] snapshot_response = ec2_client.describe_snapshots( SnapshotIds=[new_snapshot_id]) # Test instance exists in volume self.assertEqual(len(snapshot_response['Snapshots']), 1) LOGGER.info('new snapshot is verified, now cleaning up') delete_snapshot(new_snapshot_id) finally: try: ssm_doc.destroy() except Exception: pass delete_snapshot(snapshot.snapshot_id) test_cf_stack.delete_stack()
def test_update_document(self): cfn_client = boto3.client('cloudformation', region_name=REGION) ssm_client = boto3.client('ssm', region_name=REGION) ssm_doc = ssm_testing.SSMTester(ssm_client=ssm_client, doc_filename=os.path.join( DOC_DIR, 'Output/aws-DetachEBSVolume.json'), doc_name=SSM_DOC_NAME, doc_type='Automation') test_cf_stack = ssm_testing.CFNTester( cfn_client=cfn_client, template_filename=os.path.abspath( os.path.join( DOC_DIR, "Tests/CloudFormationTemplates/TestTemplate.yml")), stack_name=TEST_CFN_STACK_NAME) LOGGER.info('Creating Test Stack') test_cf_stack.create_stack([{ 'ParameterKey': 'AMI', 'ParameterValue': LINUX_AMI_ID }, { 'ParameterKey': 'INSTANCETYPE', 'ParameterValue': LINUX_INSTANCE_TYPE }, { 'ParameterKey': 'DEVICE', 'ParameterValue': DEVICE_NAME }, { 'ParameterKey': 'UserARN', 'ParameterValue': sts_client.get_caller_identity().get('Arn') }]) LOGGER.info('Test Stack has been created') # Verify role exists role_arn = test_cf_stack.stack_outputs['AutomationAssumeRoleARN'] verify_role_created(role_arn) # Verify instance started instance_id = test_cf_stack.stack_outputs['InstanceId'] verify_instance_started(instance_id) LOGGER.info('Mounting Volume') # print instance_id mount_response = mount_volume(ssm_client, instance_id, DEVICE_NAME) # print(mount_response) self.assertEqual(mount_response['Status'], 'Success') try: LOGGER.info("Creating automation document") self.assertEqual(ssm_doc.create_document(), 'Active') volume_id = test_cf_stack.stack_outputs['VolumeId'] execution = ssm_doc.execute_automation(params={ 'VolumeId': [volume_id], 'AutomationAssumeRole': [role_arn] }) self.assertEqual( ssm_doc.automation_execution_status(ssm_client, execution, False), 'Failed') LOGGER.info('Volume is still attached, now verifying') ec2 = boto3.resource('ec2') volume = ec2.Volume(volume_id) # Test instance exists in volume self.assertEqual(len(volume.attachments), 1) LOGGER.info('Unmounting volume...') unmount_volume(ssm_client, instance_id, DEVICE_NAME) time.sleep(10) volume.reload() LOGGER.info('Verifying is detached') self.assertEqual(len(volume.attachments), 0) LOGGER.info('Test Successful') finally: try: ssm_doc.destroy() except Exception: pass try: unmount_volume(ssm_client, instance_id, DEVICE_NAME) except Exception: pass test_cf_stack.delete_stack()
def test_document(): cfn_client = boto3.client('cloudformation', region_name=REGION) ssm_client = boto3.client('ssm', region_name=REGION) available_subnets = vpcUtil.find_default_subnets() # ensure the account being used has a default VPC. assert len(available_subnets) > 0, "No default subnet available for testing" ssm_doc = ssm_testing.SSMTester( ssm_client=ssm_client, doc_filename=os.path.join( DOC_DIR, 'Documents/aws-PatchWindowsInASG.json'), doc_name=SSM_DOC_NAME, doc_type='Automation' ) test_cf_stack = ssm_testing.CFNTester( cfn_client=cfn_client, template_filename=os.path.abspath(os.path.join( DOC_DIR, 'Tests/CloudFormationTemplates/ASG.yml')), stack_name=CFN_STACK_NAME ) automation_role = ssm_doc.get_automation_role( boto3.client('sts', region_name=REGION), boto3.client('iam', region_name=REGION), SERVICE_ROLE_NAME ) LOGGER.info('Creating AutoScaling Group for testing') stack_param = { 'AMI': AMI_ID, 'Subnets': available_subnets[0].id, 'InstanceType': INSTANCE_TYPE } test_cf_stack.create_stack([ {'ParameterKey': key, 'ParameterValue': value} for key, value in stack_param.iteritems()]) try: asg_name = test_cf_stack.stack_outputs["ASGName"] LOGGER.info("Creating automation document") assert ssm_doc.create_document() == 'Active', 'Document not created successfully' LOGGER.info("Waiting for an instance to become ready...") working_instance = asg_wait_for_running_instance(asg_name, 1)[0] LOGGER.info("Checking for AutoPatchInstanceInASG tag on instance.") check_tag_exist(working_instance, 'AutoPatchInstanceInASG', False) LOGGER.info("Executing SSM automation document to update instance on {}".format(working_instance)) execution = ssm_doc.execute_automation( params={'InstanceId': [working_instance], 'AutomationAssumeRole': [automation_role]}) # Collect tag change and asg instance lifecycle change. tag_changes = [None] asg_status_changes = [] asg_status_ignores = ["EnteringStandby", "Pending"] # Status callback to collect any necessary data def status_callback(_): collect_tag_change(working_instance, "AutoPatchInstanceInASG", tag_changes), collect_asg_status_change(asg_name, working_instance, asg_status_ignores, asg_status_changes) # Wait for SSM to finish while collecting value change (callback). result = ssm_doc.automation_execution_status(ssm_client, execution, status_callback=status_callback) # Verify tag change. LOGGER.info(tag_changes) expected_tag_change = [ None, "InProgress", "Completed" ] assert tag_changes == expected_tag_change, 'Tag did not follow sequence.' # Verify instance status change. LOGGER.info(asg_status_changes) expected_status_change_sequence = [ "InService", "Standby", "InService" ] is_status_change_expected = asg_status_changes == expected_status_change_sequence assert is_status_change_expected, 'ASG instant lifecycle did not match expected.' LOGGER.info('Verifying automation executions have concluded successfully') assert result == 'Success', 'Document did not complete' finally: test_cf_stack.delete_stack() ssm_doc.destroy()
def test_update_document(self): cfn_client = boto3.client('cloudformation', region_name=REGION) ssm_client = boto3.client('ssm', region_name=REGION) ssm_doc = ssm_testing.SSMTester( ssm_client=ssm_client, doc_filename=os.path.join( DOC_DIR, 'Output/aws-UpdateCloudFormationTemplate.json'), doc_name=SSM_DOC_NAME, doc_type='Automation') test_cf_stack = ssm_testing.CFNTester( cfn_client=cfn_client, template_filename=os.path.abspath( os.path.join( DOC_DIR, "Tests/CloudFormationTemplates/TestTemplate.yml")), stack_name=TEST_CFN_STACK_NAME) test_cf_stack.create_stack([]) try: user_arn = sts_client.get_caller_identity().get('Arn') cleanup_role() admin_role = create_role(user_arn)["Role"]["Arn"] cleanup_bucket() LOGGER.info("Creating automation document") self.assertEqual(ssm_doc.create_document(), 'Active') role_info = iam_client.get_role_policy( RoleName=test_cf_stack.stack_outputs["RoleName"], PolicyName='test-policy-name') self.assertEqual( len(role_info["PolicyDocument"]["Statement"]["Action"]), 1) LOGGER.info("Creating test S3 bucket") s3_client.create_bucket( Bucket=TEST_S3_BUCKET, CreateBucketConfiguration={"LocationConstraint": "us-west-2"}) s3_client.upload_file( os.path.abspath( os.path.join( DOC_DIR, "Tests/CloudFormationTemplates/TestUpdateTemplate.yml") ), TEST_S3_BUCKET, 'TestUpdateTemplate.yml') update_template = "http://s3-us-west-2.amazonaws.com/{}/TestUpdateTemplate.yml".format( TEST_S3_BUCKET) execution = ssm_doc.execute_automation( params={ 'StackNameOrId': [TEST_CFN_STACK_NAME], 'TemplateUrl': [update_template], 'LambdaAssumeRole': [admin_role], 'AutomationAssumeRole': [admin_role] }) result = ssm_doc.automation_execution_status(ssm_client, execution) while test_cf_stack.is_stack_in_status( 'CREATE_IN_PROGRESS') is True: LOGGER.info( 'Waiting 5 seconds before checking again for document update' ) time.sleep(5) self.assertEqual(result, "Success") role_info = iam_client.get_role_policy( RoleName=test_cf_stack.stack_outputs["RoleName"], PolicyName='test-policy-name') self.assertEqual( len(role_info["PolicyDocument"]["Statement"]["Action"]), 3) finally: try: ssm_doc.destroy() except Exception: pass test_cf_stack.delete_stack() cleanup_bucket() cleanup_role()
def test_update_document(self): cfn_client = boto3.client('cloudformation', region_name=REGION) ssm_client = boto3.client('ssm', region_name=REGION) ssm_doc = ssm_testing.SSMTester(ssm_client=ssm_client, doc_filename=os.path.join( DOC_DIR, 'Output/aws-StopRdsInstance.json'), doc_name=SSM_DOC_NAME, doc_type='Automation') test_cf_stack = ssm_testing.CFNTester( cfn_client=cfn_client, template_filename=os.path.join( DOC_DIR, 'Tests/CloudFormationTemplates/TestTemplate.yml'), stack_name=TEST_CFN_STACK_NAME) LOGGER.info('Creating Test Stack') test_cf_stack.create_stack([{ 'ParameterKey': 'UserARN', 'ParameterValue': sts_client.get_caller_identity().get('Arn') }, { 'ParameterKey': 'DBInstanceClass', 'ParameterValue': TEST_DB_CLASS }, { 'ParameterKey': 'AllocatedStorage', 'ParameterValue': TEST_DB_ALLOCATED_STORAGE }, { 'ParameterKey': 'Engine', 'ParameterValue': TEST_DB_ENGINE }, { 'ParameterKey': 'MasterUsername', 'ParameterValue': TEST_DB_MASTER_USERNAME }, { 'ParameterKey': 'MasterUserPassword', 'ParameterValue': TEST_DB_MASTER_USER_PASSWORD }]) LOGGER.info('Test Stack has been created') # Verify role exists role_arn = test_cf_stack.stack_outputs['AutomationAssumeRoleARN'] verify_role_created(role_arn) # Start an Rds instance for us to stop LOGGER.info('Creating automation document') self.assertEqual(ssm_doc.create_document(), 'Active') db_instance_id = test_cf_stack.stack_outputs['InstanceId'] LOGGER.info("Test Case DB Instance ID:" + db_instance_id) rds_client.stop_db_instance(DBInstanceIdentifier=db_instance_id) # ...waiting for the stop to complete, then proceeding. We're procedurally stopping the DB so that we can prove # the Automation Under Test won't implode under legit edge cases (like a logical noop case) verify_db_stopped(db_instance_id) try: LOGGER.info('Executing SSM automation document to stop instances') # Stop the Rds instance execution = ssm_doc.execute_automation(params={ 'InstanceId': [db_instance_id], 'AutomationAssumeRole': [role_arn] }) self.assertEqual( ssm_doc.automation_execution_status(ssm_client, execution, False), 'Success') # Now obtain evidence to prove the Rds instance has stopped db_state = rds_client.describe_db_instances( DBInstanceIdentifier=db_instance_id) self.assertEqual(db_state['DBInstances'][0]['DBInstanceStatus'], "stopped") LOGGER.info('Verified the DB instance is stopped') finally: try: ssm_doc.destroy() except Exception: pass test_cf_stack.delete_stack()
def test_update_document(self): ssm_doc = ssm_testing.SSMTester( ssm_client=ssm_client, doc_filename=os.path.join(DOC_DIR, 'Output/aws-RebootRdsInstance.json'), doc_name=SSM_DOC_NAME, doc_type='Automation') LOGGER.info("Declaring Test Stack") test_cf_stack = ssm_testing.CFNTester( cfn_client=cfn_client, template_filename=os.path.join( DOC_DIR, 'Tests/CloudFormationTemplates/TestTemplate.yml'), stack_name=TEST_CFN_STACK_NAME) LOGGER.info('Creating Test Stack') test_cf_stack.create_stack([{ 'ParameterKey': 'UserARN', 'ParameterValue': sts_client.get_caller_identity().get('Arn') }, { 'ParameterKey': 'DBInstanceClass', 'ParameterValue': TEST_DB_CLASS }, { 'ParameterKey': 'AllocatedStorage', 'ParameterValue': TEST_DB_ALLOCATED_STORAGE }, { 'ParameterKey': 'Engine', 'ParameterValue': TEST_DB_ENGINE }, { 'ParameterKey': 'MasterUsername', 'ParameterValue': TEST_DB_MASTER_USERNAME }, { 'ParameterKey': 'MasterUserPassword', 'ParameterValue': TEST_DB_MASTER_USER_PASSWORD }]) LOGGER.info('Test Stack has been created') # Verify role exists role_arn = test_cf_stack.stack_outputs['AutomationAssumeRoleARN'] verify_role_created(role_arn) # Start an Rds instance for us to test LOGGER.info('Creating automation document') self.assertEqual(ssm_doc.create_document(), 'Active') instance_id = test_cf_stack.stack_outputs['InstanceId'] LOGGER.info('DB instance featured in this test run has id ' + instance_id) db_state = rds_client.describe_db_instances( DBInstanceIdentifier=instance_id) LOGGER.info('It current state is ' + db_state['DBInstances'][0]['DBInstanceStatus']) try: LOGGER.info('Commencing automation execution') execution = ssm_doc.execute_automation(params={ 'InstanceId': [instance_id], 'AutomationAssumeRole': [role_arn] }) LOGGER.info('automation execution-id ' + execution) exec_fail = 'Automation execution did NOT end successfully' self.assertEqual( ssm_doc.automation_execution_status(ssm_client, execution, False), 'Success', exec_fail) db_state = rds_client.describe_db_instances( DBInstanceIdentifier=instance_id) self.assertEqual(db_state['DBInstances'][0]['DBInstanceStatus'], "available") LOGGER.info('Verified the DB instance is available') finally: try: LOGGER.info('Destroying automation document') ssm_doc.destroy() except Exception: pass LOGGER.info('Standing down Test Stack') test_cf_stack.delete_stack() LOGGER.info('Test cleanup completed')
def test_exit_standby_document(self): user_arn = boto3.client('sts', region_name=REGION).get_caller_identity().get('Arn') with create_admin_role(iam_client, sts_client, PREFIX + "exit-standby-test", user_arn) as admin_role: admin_role_arn = admin_role["Role"]["Arn"] available_subnets = vpcUtil.find_default_subnets() # ensure the account being used has a default VPC. assert len(available_subnets) > 0, "No default subnet available for testing" ssm_doc = ssm_testing.SSMTester( ssm_client=ssm_client, doc_filename=os.path.join( DOC_DIR, 'Output/aws-ASGExitStandby.json'), doc_name=EXIT_STANDBY_SSM_DOC_NAME, doc_type='Automation' ) test_cf_stack = ssm_testing.CFNTester( cfn_client=cfn_client, template_filename=os.path.abspath(os.path.join( DOC_DIR, 'Tests/CloudFormationTemplates/ASG.yml')), stack_name=EXIT_STANDBY_CFN_STACK_NAME ) LOGGER.info('Creating AutoScaling Group for testing') stack_param = { 'AMI': AMI_ID, 'Subnets': available_subnets[0].id, 'InstanceType': INSTANCE_TYPE } test_cf_stack.create_stack([ {'ParameterKey': key, 'ParameterValue': value} for key, value in stack_param.iteritems()]) asg_name = test_cf_stack.stack_outputs["ASGName"] LOGGER.info("Waiting for an instance to become ready...") working_instance = asg_wait_for_running_instance( asg_name=asg_name, number_of_instance=1, max_wait_sec=1800)[0] LOGGER.info("Setting instance to enter standby mode") as_client.enter_standby( InstanceIds=[working_instance], AutoScalingGroupName=asg_name, ShouldDecrementDesiredCapacity=True) # poll the instance until it reaches the standby state asg_wait_for_instance_in_state(working_instance, 'Standby') try: LOGGER.info("Creating automation document") assert ssm_doc.create_document() == 'Active', 'Document not created successfully' LOGGER.info( "Executing SSM automation document to remove instance from standby mode on {}".format(working_instance)) execution = ssm_doc.execute_automation( params={'LambdaRoleArn': [admin_role_arn], 'InstanceId': [working_instance], 'AutomationAssumeRole': [admin_role_arn]}) # Collect asg instance lifecycle change. asg_status_changes = [] asg_status_ignores = ["Pending"] # Status callback to collect any necessary data def status_callback(_): collect_asg_status_change(asg_name, working_instance, asg_status_ignores, asg_status_changes) # Wait for SSM to finish while collecting value change (callback). result = ssm_doc.automation_execution_status(ssm_client, execution, status_callback=status_callback) # Verify instance status change. LOGGER.info("ASG status change sequence: " + str(asg_status_changes)) expected_status_change_sequence = [ "Standby", "InService" ] is_status_change_expected = asg_status_changes == expected_status_change_sequence assert is_status_change_expected, 'ASG instant lifecycle did not match expected.' LOGGER.info('Verifying automation executions have concluded successfully') assert result == 'Success', 'Document did not complete' finally: test_cf_stack.delete_stack() ssm_doc.destroy()
def test_update_document(self): cfn_client = boto3.client('cloudformation', region_name=REGION) ssm_client = boto3.client('ssm', region_name=REGION) ssm_doc = ssm_testing.SSMTester( ssm_client=ssm_client, doc_filename=os.path.join(DOC_DIR, 'Output/aws-StartRdsInstance.json'), doc_name=SSM_DOC_NAME, doc_type='Automation') test_cf_stack = ssm_testing.CFNTester( cfn_client=cfn_client, template_filename=os.path.join( DOC_DIR, 'Tests/CloudFormationTemplates/TestTemplate.yml'), stack_name=TEST_CFN_STACK_NAME) LOGGER.info('Creating Test Stack') test_cf_stack.create_stack([{ 'ParameterKey': 'UserARN', 'ParameterValue': sts_client.get_caller_identity().get('Arn') }, { 'ParameterKey': 'DBInstanceClass', 'ParameterValue': TEST_DB_CLASS }, { 'ParameterKey': 'AllocatedStorage', 'ParameterValue': TEST_DB_ALLOCATED_STORAGE }, { 'ParameterKey': 'Engine', 'ParameterValue': TEST_DB_ENGINE }, { 'ParameterKey': 'MasterUsername', 'ParameterValue': TEST_DB_MASTER_USERNAME }, { 'ParameterKey': 'MasterUserPassword', 'ParameterValue': TEST_DB_MASTER_USER_PASSWORD }]) LOGGER.info('Test Stack has been created') # Verify role exists role_arn = test_cf_stack.stack_outputs['AutomationAssumeRoleARN'] verify_role_created(role_arn) # Start an Rds instance for us to test LOGGER.info('Creating automation document') self.assertEqual(ssm_doc.create_document(), 'Active') db_instance_id = test_cf_stack.stack_outputs['InstanceId'] # This case verifies the impl-under-test is resilient in the face of required INACTION # Make sure the furnished RDS instance is in running verify_db_started(db_instance_id) try: LOGGER.info('Executing SSM automation document to stop instances') # Stop the Rds instance execution = ssm_doc.execute_automation(params={ 'InstanceId': [db_instance_id], 'AutomationAssumeRole': [role_arn] }) self.assertEqual( ssm_doc.automation_execution_status(ssm_client, execution, False), 'Success') db_state = rds_client.describe_db_instances( DBInstanceIdentifier=db_instance_id) self.assertEqual(db_state['DBInstances'][0]['DBInstanceStatus'], "available") LOGGER.info('Verified the DB instance is stopped') finally: try: ssm_doc.destroy() except Exception: pass test_cf_stack.delete_stack()
def test_update_document(self): cfn_client = boto3.client('cloudformation', region_name=REGION) ssm_client = boto3.client('ssm', region_name=REGION) ssm_doc = ssm_testing.SSMTester( ssm_client=ssm_client, doc_filename=os.path.join( DOC_DIR, 'Documents/npark-encryptrootvolume.json'), doc_name=SSM_DOC_NAME, doc_type='Automation') test_cf_stack = ssm_testing.CFNTester( cfn_client=cfn_client, template_filename=os.path.abspath( os.path.join( DOC_DIR, "Tests/CloudFormationTemplates/TestTemplate.yml")), stack_name=TEST_CFN_STACK_NAME) LOGGER.info('Creating Test Stack') LOGGER.info('AMI:' + LINUX_AMI_ID) LOGGER.info('Instance Type:' + LINUX_INSTANCE_TYPE) test_cf_stack.create_stack([{ 'ParameterKey': 'AMI', 'ParameterValue': LINUX_AMI_ID }, { 'ParameterKey': 'INSTANCETYPE', 'ParameterValue': LINUX_INSTANCE_TYPE }, { 'ParameterKey': 'UserARN', 'ParameterValue': sts_client.get_caller_identity().get('Arn') }]) LOGGER.info('Test Stack has been created') # Verify role exists role_arn = test_cf_stack.stack_outputs['AutomationAssumeRoleARN'] verify_role_created(role_arn) try: LOGGER.info("Creating automation document") self.assertEqual(ssm_doc.create_document(), 'Active') instance_id = test_cf_stack.stack_outputs['InstanceId'] kms_key_id = test_cf_stack.stack_outputs['KmsKeyId'] execution = ssm_doc.execute_automation( params={ 'instanceId': [instance_id], 'kmsKeyId': [kms_key_id], 'automationAssumeRole': [role_arn] }) self.assertEqual( ssm_doc.automation_execution_status(ssm_client, execution, False), 'Success') LOGGER.info('Encryption of root volume has been completed') response = ssm_doc.automation_execution_status( ssm_client, execution) if response == 'Success': response = ec2_client.describe_instances( InstanceIds=[instance_id], DryRun=False) rootdevicename = response['Reservations'][0]['Instances'][0][ 'RootDeviceName'] response = ec2_client.describe_volumes(Filters=[ { 'Name': 'attachment.instance-id', 'Values': [instance_id], }, { 'Name': 'attachment.device', 'Values': [rootdevicename], }, ], DryRun=False) is_encrypted = response['Volumes'][0]['Encrypted'] self.assertEqual(is_encrypted, True) if is_encrypted: LOGGER.info("All Tests Successful, will clean up now") else: LOGGER.info( "FAIL: root volume is NOT encrypted, will clean up now" ) finally: try: ssm_doc.destroy() except Exception: pass test_cf_stack.delete_stack()
def test_update_document(self): cfn_client = boto3.client('cloudformation', region_name=REGION) ssm_client = boto3.client('ssm', region_name=REGION) test_cf_stack = ssm_testing.CFNTester( cfn_client=cfn_client, template_filename=os.path.abspath(os.path.join( DOC_DIR, "Tests/CloudFormationTemplates/TestNotAssociated.yml")), stack_name=TEST_CFN_STACK_NAME ) LOGGER.info('Creating Test Stack') test_cf_stack.create_stack([ { 'ParameterKey': 'AMI', 'ParameterValue': LINUX_AMI_ID }, { 'ParameterKey': 'INSTANCETYPE', 'ParameterValue': LINUX_INSTANCE_TYPE }, { 'ParameterKey': 'UserARN', 'ParameterValue': sts_client.get_caller_identity().get('Arn') } ]) LOGGER.info('Test Stack has been created') # Verify role exists role_arn = test_cf_stack.stack_outputs['AutomationAssumeRoleARN'] verify_role_created(role_arn) # Crete the lambda ssm_doc = ssm_testing.SSMTester( ssm_client=ssm_client, doc_filename=os.path.join(DOC_DIR, 'Output/aws-AttachIAMToInstance.json'), doc_name=SSM_DOC_NAME, doc_type='Automation' ) LOGGER.info("Creating automation document") self.assertEqual(ssm_doc.create_document(), 'Active') try: instance_id = test_cf_stack.stack_outputs['InstanceId'] role_name = test_cf_stack.stack_outputs['AutomationAssumeRoleName'] execution = ssm_doc.execute_automation( params={'InstanceId': [instance_id], 'RoleName': [role_name], 'AutomationAssumeRole': [role_arn]}) self.assertEqual(ssm_doc.automation_execution_status(ssm_client, execution, False), 'Success') LOGGER.info('automation executed successfully') response = ssm_client.get_automation_execution(AutomationExecutionId=execution) str_payload = response['AutomationExecution']['Outputs']['attachIAMToInstance.Payload'][0] payload = json.loads(str_payload) association_id = payload['AssociationId'] profile_name = payload['InstanceProfileName'] self.assertEqual(role_name, payload['RoleName']) LOGGER.info('Verify that the instance has a profile') profile_instance_response = ec2_client.describe_iam_instance_profile_associations(Filters=[{ 'Name': 'instance-id', 'Values': [instance_id] }]) self.assertEqual(len(profile_instance_response['IamInstanceProfileAssociations']), 1) iam_instance_profile_association = profile_instance_response['IamInstanceProfileAssociations'][0] self.assertEqual(len(profile_instance_response['IamInstanceProfileAssociations']), 1) self.assertEqual(iam_instance_profile_association['AssociationId'], association_id) self.assertEqual(iam_instance_profile_association['InstanceId'], instance_id) LOGGER.info('Verify that the instance profile has the role') instance_profile_response = iam_client.get_instance_profile( InstanceProfileName=profile_name ) self.assertEqual(instance_profile_response['InstanceProfile']['InstanceProfileName'], profile_name) role_count = 0 for role in instance_profile_response['InstanceProfile']['Roles']: if role['RoleName'] == role_name: role_count += 1 self.assertEqual(role_count, 1) LOGGER.info('Tests successful. Cleaning up') remove_role_from_instance_profile(profile_name, role_name) delete_instance_profile(profile_name) disassociate_iam_instance_profile(association_id) LOGGER.info('Clean up successful') finally: try: ssm_doc.destroy() except Exception: pass test_cf_stack.delete_stack()
def test_update_document(self): cfn_client = boto3.client('cloudformation', region_name=REGION) ssm_client = boto3.client('ssm', region_name=REGION) ssm_doc = ssm_testing.SSMTester( ssm_client=ssm_client, doc_filename=os.path.join(DOC_DIR, 'Output/aws-AttachEBSVolume.json'), doc_name=SSM_DOC_NAME, doc_type='Automation' ) test_cf_stack = ssm_testing.CFNTester( cfn_client=cfn_client, template_filename=os.path.abspath(os.path.join( DOC_DIR, "Tests/CloudFormationTemplates/TestTemplate.yml")), stack_name=TEST_CFN_STACK_NAME ) LOGGER.info('Creating Test Stack') test_cf_stack.create_stack([ { 'ParameterKey': 'AMI', 'ParameterValue': LINUX_AMI_ID }, { 'ParameterKey': 'INSTANCETYPE', 'ParameterValue': LINUX_INSTANCE_TYPE }, { 'ParameterKey': 'UserARN', 'ParameterValue': sts_client.get_caller_identity().get('Arn') } ]) LOGGER.info('Test Stack has been created') # Verify role exists role_arn = test_cf_stack.stack_outputs['AutomationAssumeRoleARN'] verify_role_created(role_arn) try: LOGGER.info("Creating automation document") self.assertEqual(ssm_doc.create_document(), 'Active') device = 'xvdh' instance_id = test_cf_stack.stack_outputs['InstanceId'] volume_id = test_cf_stack.stack_outputs['VolumeId'] execution = ssm_doc.execute_automation( params={'Device': [device], 'InstanceId': [instance_id], 'VolumeId': [volume_id], 'AutomationAssumeRole': [role_arn]}) self.assertEqual(ssm_doc.automation_execution_status(ssm_client, execution, False), 'Success') LOGGER.info('Volume is attached, now verifying') ec2 = boto3.resource('ec2') volume = ec2.Volume(volume_id) # Test instance exists in volume self.assertGreater(len(volume.attachments), 0) self.assertEqual(volume.attachments[0]['InstanceId'], instance_id) volume.detach_from_instance() finally: try: ssm_doc.destroy() except Exception: pass test_cf_stack.delete_stack()
def test_update_document(self): cfn_client = boto3.client('cloudformation', region_name=REGION) ssm_client = boto3.client('ssm', region_name=REGION) ssm_doc = ssm_testing.SSMTester(ssm_client=ssm_client, doc_filename=os.path.join( DOC_DIR, 'Output/aws-ResizeInstance.json'), doc_name=SSM_DOC_NAME, doc_type='Automation') test_cf_stack = ssm_testing.CFNTester( cfn_client=cfn_client, template_filename=os.path.abspath( os.path.join( DOC_DIR, "Tests/CloudFormationTemplates/TestTemplate.yml")), stack_name=TEST_CFN_STACK_NAME) LOGGER.info('Creating Test Stack') LOGGER.info('AMI:' + LINUX_AMI_ID) LOGGER.info('Instance Type:' + LINUX_INSTANCE_TYPE) test_cf_stack.create_stack([{ 'ParameterKey': 'AMI', 'ParameterValue': LINUX_AMI_ID }, { 'ParameterKey': 'INSTANCETYPE', 'ParameterValue': LINUX_INSTANCE_TYPE }, { 'ParameterKey': 'UserARN', 'ParameterValue': sts_client.get_caller_identity().get('Arn') }]) LOGGER.info('Test Stack has been created') # Verify role exists role_arn = test_cf_stack.stack_outputs['AutomationAssumeRoleARN'] verify_role_created(role_arn) try: LOGGER.info("Creating automation document") self.assertEqual(ssm_doc.create_document(), 'Active') instance_id = test_cf_stack.stack_outputs['InstanceId'] execution = ssm_doc.execute_automation( params={ 'InstanceId': [instance_id], 'InstanceType': [NEW_INSTANCE_TYPE], 'AutomationAssumeRole': [role_arn] }) self.assertEqual( ssm_doc.automation_execution_status(ssm_client, execution, False), 'Success') LOGGER.info('Instance has changed, Verifying instance') ec2 = boto3.resource('ec2') instance = ec2.Instance(instance_id) LOGGER.info("Current instance Type:" + instance.instance_type) # Test instance exists in volume self.assertEqual(instance.instance_type, NEW_INSTANCE_TYPE) self.assertEqual(instance.state.get('Code'), 16) LOGGER.info("All Tests Successful, will clean up now") finally: try: ssm_doc.destroy() except Exception: pass test_cf_stack.delete_stack()
def test_document(): """Verify correct deployment and use of document.""" cfn_client = boto3.client('cloudformation', region_name=REGION) ec2_client = boto3.client('ec2', region_name=REGION) ssm_client = boto3.client('ssm', region_name=REGION) ssm_doc = ssm_testing.SSMTester( ssm_client=ssm_client, doc_filename=os.path.join(DOC_DIR, 'Documents', 'aws-TerminateEC2InstanceWithApproval.json'), doc_name=SSM_DOC_NAME, doc_type='Automation' ) test_cf_stack = ssm_testing.CFNTester( cfn_client=cfn_client, template_filename=os.path.join(DOC_DIR, 'Tests', 'CloudFormationTemplates', 'TwoInstances.yml'), stack_name=INSTANCE_CFN_STACK_NAME ) automation_role = ssm_doc.get_automation_role( boto3.client('sts', region_name=REGION), boto3.client('iam', region_name=REGION), SERVICE_ROLE_NAME ) LOGGER.info('Starting 2 instances for testing') test_cf_stack.create_stack([ { 'ParameterKey': 'AMI', 'ParameterValue': AMIID }, { 'ParameterKey': 'INSTANCETYPE', 'ParameterValue': INSTANCE_TYPE } ]) try: LOGGER.info('Creating automation document') assert ssm_doc.create_document() == 'Active', ('Document not ' 'created ' 'successfully') LOGGER.info('Running automation to terminate multiple instances ' '(using defined role)') instances_1_2 = [test_cf_stack.stack_outputs['Instance0Id'], test_cf_stack.stack_outputs['Instance1Id']] LOGGER.info('Verifying all instances are running') describe_res = ec2_client.describe_instance_status( InstanceIds=instances_1_2, IncludeAllInstances=True ) assert all(d['InstanceState']['Name'] == 'running' for d in describe_res['InstanceStatuses']) is True, ( # noqa pylint: disable=line-too-long 'Instances not started') LOGGER.info("Executing SSM automation document to terminate instances") user_arn = boto3.client('sts', region_name=REGION).get_caller_identity().get('Arn') sns_topic_arn = test_cf_stack.stack_outputs['SNSTopicArn'] LOGGER.info("User ARN for approval: " + user_arn) LOGGER.info("SNS Topic ARN for approval: " + sns_topic_arn) execution = ssm_doc.execute_automation( params={'InstanceId': instances_1_2, 'AutomationAssumeRole': [automation_role], 'Approvers': [user_arn], 'SNSTopicArn': [sns_topic_arn]}) # since this automation requires approval to continue, the correct status at this point should be 'Waiting' assert ssm_doc.automation_execution_status(ssm_client, execution, False) == 'Waiting', \ 'Automation not waiting for approval' LOGGER.info('Approving continuation of execution') ssm_client.send_automation_signal( AutomationExecutionId=execution, SignalType='Approve' ) LOGGER.info('Verifying automation executions have concluded ' 'successfully') assert ssm_doc.automation_execution_status( ssm_client, execution ) == 'Success', 'Instance not terminated correctly' LOGGER.info('Ensuring instances have terminated') describe_res = ec2_client.describe_instance_status( InstanceIds=instances_1_2, IncludeAllInstances=True ) assert all(d['InstanceState']['Name'] == 'terminated' for d in describe_res['InstanceStatuses']) is True finally: test_cf_stack.delete_stack() ssm_doc.destroy()
def test_enter_standby_document(self): available_subnets = vpcUtil.find_default_subnets() # ensure the account being used has a default VPC. assert len( available_subnets) > 0, "No default subnet available for testing" ssm_doc = ssm_testing.SSMTester( ssm_client=ssm_client, doc_filename=os.path.join( DOC_DIR, 'Documents/aws-ASGEnterStandbyWithApproval.json'), doc_name=ENTER_STANDBY_SSM_DOC_NAME, doc_type='Automation') test_cf_stack = ssm_testing.CFNTester( cfn_client=cfn_client, template_filename=os.path.abspath( os.path.join(DOC_DIR, 'Tests/CloudFormationTemplates/ASG.yml')), stack_name=ENTER_STANDBY_CFN_STACK_NAME) automation_role = ssm_doc.get_automation_role(sts_client, iam_client, SERVICE_ROLE_NAME) LOGGER.info('Creating AutoScaling Group for testing') stack_param = { 'AMI': AMI_ID, 'Subnets': available_subnets[0].id, 'InstanceType': INSTANCE_TYPE } test_cf_stack.create_stack([{ 'ParameterKey': key, 'ParameterValue': value } for key, value in stack_param.iteritems()]) asg_name = test_cf_stack.stack_outputs["ASGName"] LOGGER.info("Waiting for an instance to become ready...") working_instance = asg_wait_for_running_instance(asg_name=asg_name, number_of_instance=1, max_wait_sec=300)[0] try: LOGGER.info("Creating automation document") assert ssm_doc.create_document( ) == 'Active', 'Document not created successfully' user_arn = sts_client.get_caller_identity().get('Arn') sns_topic_arn = test_cf_stack.stack_outputs['SNSTopicArn'] LOGGER.info("User ARN for approval: " + user_arn) LOGGER.info("SNS Topic ARN for approval: " + sns_topic_arn) LOGGER.info( "Executing SSM automation document to set instance to standby mode on {}" .format(working_instance)) execution = ssm_doc.execute_automation( params={ 'InstanceId': [working_instance], 'LambdaRoleArn': [automation_role], 'AutomationAssumeRole': [automation_role], 'Approvers': [user_arn], 'SNSTopicArn': [sns_topic_arn] }) # Send approval signal # Since this automation requires approval to continue, the correct status at this point should be 'Waiting' assert ssm_doc.automation_execution_status(ssm_client, execution, False) == 'Waiting', \ 'Automation not waiting for approval' LOGGER.info('Approving continuation of execution') ssm_client.send_automation_signal(AutomationExecutionId=execution, SignalType='Approve') # Collect asg instance lifecycle change. asg_status_changes = [] asg_status_ignores = ["EnteringStandby", "Pending"] # Status callback to collect any necessary data def status_callback(_): collect_asg_status_change(asg_name, working_instance, asg_status_ignores, asg_status_changes) # Wait for SSM to finish while collecting value change (callback). result = ssm_doc.automation_execution_status( ssm_client, execution, status_callback=status_callback) # Verify instance status change. LOGGER.info("ASG status change sequence: " + str(asg_status_changes)) expected_status_change_sequence = ["InService", "Standby"] is_status_change_expected = asg_status_changes == expected_status_change_sequence assert is_status_change_expected, 'ASG instant lifecycle did not match expected.' LOGGER.info( 'Verifying automation executions have concluded successfully') assert result == 'Success', 'Document did not complete' finally: try: LOGGER.info( 'Taking instance out of standby (required for CF stack teardown)' ) as_client.exit_standby(InstanceIds=[working_instance], AutoScalingGroupName=asg_name) finally: test_cf_stack.delete_stack() ssm_doc.destroy()
def test_update_document(self): cfn_client = boto3.client('cloudformation', region_name=REGION) ssm_client = boto3.client('ssm', region_name=REGION) ssm_doc = ssm_testing.SSMTester(ssm_client=ssm_client, doc_filename=os.path.join( DOC_DIR, 'Output/aws-DeleteSnapshot.json'), doc_name=SSM_DOC_NAME, doc_type='Automation') test_cf_stack = ssm_testing.CFNTester( cfn_client=cfn_client, template_filename=os.path.abspath( os.path.join( DOC_DIR, "Tests/CloudFormationTemplates/TestTemplate.yml")), stack_name=TEST_CFN_STACK_NAME) LOGGER.info('Creating Test Stack') test_cf_stack.create_stack([{ 'ParameterKey': 'UserARN', 'ParameterValue': sts_client.get_caller_identity().get('Arn') }]) LOGGER.info('Test Stack has been created') # Verify role exists role_arn = test_cf_stack.stack_outputs['AutomationAssumeRoleARN'] verify_role_created(role_arn) LOGGER.info("Creating automation document") self.assertEqual(ssm_doc.create_document(), 'Active') volume_id = test_cf_stack.stack_outputs['VolumeId'] # Now create the snapshot snapshot = self.create_snapshot(volume_id) try: execution = ssm_doc.execute_automation( params={ 'SnapshotId': [snapshot.snapshot_id], 'AutomationAssumeRole': [role_arn] }) self.assertEqual( ssm_doc.automation_execution_status(ssm_client, execution, False), 'Success') LOGGER.info('Snapshot is deleted: ' + volume_id) snapshot_response = ec2_client.describe_snapshots( Filters=[{ 'Name': 'volume-id', 'Values': [volume_id] }]) # Test instance exists in volume snapshots = snapshot_response['Snapshots'] self.assertEqual(len(snapshots), 0) LOGGER.info('Verified snapshot is deleted') finally: try: ssm_doc.destroy() except Exception: pass self.delete_snapshot(snapshot.snapshot_id) test_cf_stack.delete_stack()
def test_update_document(self): cfn_client = boto3.client('cloudformation', region_name=REGION) ssm_client = boto3.client('ssm', region_name=REGION) ssm_doc = ssm_testing.SSMTester(ssm_client=ssm_client, doc_filename=os.path.join( DOC_DIR, 'Documents/aws-CreateImage.json'), doc_name=SSM_DOC_NAME, doc_type='Automation') test_cf_stack = ssm_testing.CFNTester( cfn_client=cfn_client, template_filename=os.path.abspath( os.path.join( DOC_DIR, "Tests/CloudFormationTemplates/TestTemplate.yml")), stack_name=TEST_CFN_STACK_NAME) LOGGER.info('Creating Test Stack') LOGGER.info('AMI:' + LINUX_AMI_ID) LOGGER.info('Instance Type:' + LINUX_INSTANCE_TYPE) test_cf_stack.create_stack([{ 'ParameterKey': 'AMI', 'ParameterValue': LINUX_AMI_ID }, { 'ParameterKey': 'INSTANCETYPE', 'ParameterValue': LINUX_INSTANCE_TYPE }, { 'ParameterKey': 'UserARN', 'ParameterValue': sts_client.get_caller_identity().get('Arn') }]) LOGGER.info('Test Stack has been created') # Verify role exists role_arn = test_cf_stack.stack_outputs['AutomationAssumeRoleARN'] verify_role_created(role_arn) try: LOGGER.info("Creating automation document") self.assertEqual(ssm_doc.create_document(), 'Active') instance_id = test_cf_stack.stack_outputs['InstanceId'] execution = ssm_doc.execute_automation(params={ 'InstanceId': [instance_id], 'AutomationAssumeRole': [role_arn] }) self.assertEqual( ssm_doc.automation_execution_status(ssm_client, execution, False), 'Success') LOGGER.info('Create a new Amazon Machine Image has been initiated') ec2_resource = boto3.resource('ec2') ec2client = boto3.client('ec2') instance = ec2_resource.Instance(instance_id) imageName = instance_id + '_' + execution describeImage = ec2client.describe_images( Filters=[{ 'Name': 'name', 'Values': [imageName], }]) ImageId = describeImage['Images'][0]['ImageId'] # Test Amazon Machine Image exists waiter = ec2client.get_waiter('image_available') waiter.wait(ImageIds=[ImageId]) LOGGER.info("All Tests Successful, will clean up now") #Get SnapshotId from Amazon Machine Image imageData = ec2_resource.Image(ImageId) SnapshotId = imageData.block_device_mappings[0]['Ebs'][ 'SnapshotId'] LOGGER.info( "Got the SnapshotId from the Amazon Machine Image for the clean up process." ) finally: try: ssm_doc.destroy() ec2client.deregister_image(ImageId=ImageId) ec2client.delete_snapshot(SnapshotId=SnapshotId) except Exception: pass test_cf_stack.delete_stack()