def test_bucketpolicy( cfn_client, s3_client, cleanup_stacks, cleanup_changesets, is_change_set_created_and_available, is_stack_created, ): stack_name = f"stack-{short_uid()}" change_set_name = f"change-set-{short_uid()}" bucket_name = f"ls-bucket-{short_uid()}" template_rendered = jinja2.Template(load_template_raw("s3_bucketpolicy.yaml")).render( bucket_name=bucket_name, include_policy=True, ) response = cfn_client.create_change_set( StackName=stack_name, ChangeSetName=change_set_name, TemplateBody=template_rendered, ChangeSetType="CREATE", ) change_set_id = response["Id"] stack_id = response["StackId"] try: wait_until(is_change_set_created_and_available(change_set_id)) cfn_client.execute_change_set(ChangeSetName=change_set_id) wait_until(is_stack_created(stack_id)) bucket_policy = s3_client.get_bucket_policy(Bucket=bucket_name)["Policy"] assert bucket_policy nopolicy_template = jinja2.Template(load_template_raw("s3_bucketpolicy.yaml")).render( bucket_name=bucket_name, include_policy=False, ) nopolicy_changeset_name = f"change-set-{short_uid()}" response = cfn_client.create_change_set( StackName=stack_name, ChangeSetName=nopolicy_changeset_name, TemplateBody=nopolicy_template, ChangeSetType="UPDATE", ) change_set_id = response["Id"] wait_until(is_change_set_created_and_available(change_set_id)) cfn_client.execute_change_set(ChangeSetName=change_set_id) wait_until( is_stack_created(stack_id) ) # TODO: fix cloudformation update status when using changesets with pytest.raises(Exception) as err: s3_client.get_bucket_policy(Bucket=bucket_name).get("Policy") assert err.value.response["Error"]["Code"] == "NoSuchBucketPolicy" finally: # pass cleanup_changesets([change_set_id]) cleanup_stacks([stack_id])
def test_bucket_autoname( cfn_client, cleanup_stacks, cleanup_changesets, is_change_set_created_and_available, is_stack_created, ): stack_name = f"STACK-{short_uid()}" change_set_name = f"change-set-{short_uid()}" response = cfn_client.create_change_set( StackName=stack_name, ChangeSetName=change_set_name, TemplateBody=load_template_raw("s3_bucket_autoname.yaml"), ChangeSetType="CREATE", ) change_set_id = response["Id"] stack_id = response["StackId"] try: wait_until(is_change_set_created_and_available(change_set_id)) cfn_client.execute_change_set(ChangeSetName=change_set_id) wait_until(is_stack_created(stack_id)) descr_response = cfn_client.describe_stacks(StackName=stack_id) output = descr_response["Stacks"][0]["Outputs"][0] assert output["OutputKey"] == "BucketNameOutput" assert stack_name.lower() in output["OutputValue"] finally: cleanup_changesets([change_set_id]) cleanup_stacks([stack_id])
def test_sns_topic_fifo_without_suffix_fails( cfn_client, sns_client, cleanup_stacks, cleanup_changesets, is_change_set_created_and_available, is_stack_created, ): """topic name needs .fifo suffix to be valid""" stack_name = f"stack-{short_uid()}" change_set_name = f"change-set-{short_uid()}" topic_name = f"topic-{short_uid()}" template_rendered = jinja2.Template(load_template_raw("sns_topic_fifo_dedup.yaml")).render( sns_topic=topic_name ) response = cfn_client.create_change_set( StackName=stack_name, ChangeSetName=change_set_name, TemplateBody=template_rendered, ChangeSetType="CREATE", ) change_set_id = response["Id"] stack_id = response["StackId"] try: wait_until(is_change_set_created_and_available(change_set_id)) cfn_client.execute_change_set(ChangeSetName=change_set_id) wait_until(is_stack_created(stack_id)) stack = cfn_client.describe_stacks(StackName=stack_id)["Stacks"][0] assert stack.get("StackStatus") == "CREATE_FAILED" # TODO: might be different on AWS, check finally: cleanup_changesets([change_set_id]) cleanup_stacks([stack_id])
def test_statemachine_definitionsubstitution( cfn_client, lambda_client, cleanup_stacks, cleanup_changesets, is_change_set_created_and_available, is_stack_created, stepfunctions_client, s3_client, ): stack_name = f"stack-{short_uid()}" change_set_name = f"change-set-{short_uid()}" response = cfn_client.create_change_set( StackName=stack_name, ChangeSetName=change_set_name, TemplateBody=load_template_raw("stepfunctions_statemachine_substitutions.yaml"), ChangeSetType="CREATE", Capabilities=["CAPABILITY_IAM"], ) change_set_id = response["Id"] stack_id = response["StackId"] try: wait_until(is_change_set_created_and_available(change_set_id)) cfn_client.execute_change_set(ChangeSetName=change_set_id) wait_until(is_stack_created(stack_id)) stack_result = cfn_client.describe_stacks(StackName=stack_id) assert stack_result["Stacks"][0]["StackStatus"] == "CREATE_COMPLETE" outputs = stack_result["Stacks"][0]["Outputs"] assert len(outputs) == 1 statemachine_arn = outputs[0]["OutputValue"] # execute statemachine ex_result = stepfunctions_client.start_execution(stateMachineArn=statemachine_arn) def _is_executed(): return ( stepfunctions_client.describe_execution(executionArn=ex_result["executionArn"])[ "status" ] != "RUNNING" ) wait_until(_is_executed) execution_desc = stepfunctions_client.describe_execution( executionArn=ex_result["executionArn"] ) assert execution_desc["status"] == "SUCCEEDED" # sync execution is currently not supported since botocore adds a "sync-" prefix # ex_result = stepfunctions_client.start_sync_execution(stateMachineArn=statemachine_arn) assert "hello from statemachine" in execution_desc["output"] finally: cleanup_changesets([change_set_id]) cleanup_stacks([stack_id])
def test_update_lambda_inline_code(cfn_client, lambda_client, is_stack_created, is_stack_updated, cleanup_stacks): stack_name = f"stack-{short_uid()}" function_name = f"test-fn-{short_uid()}" try: template_1 = jinja2.Template( load_template_raw("lambda_inline_code.yaml")).render( lambda_return_value="hello world", arch="x86_64", function_name=function_name, ) response = cfn_client.create_stack(StackName=stack_name, TemplateBody=template_1, Capabilities=["CAPABILITY_IAM"]) stack_id = response["StackId"] assert stack_id wait_until(is_stack_created(stack_id)) rs = lambda_client.get_function(FunctionName=function_name) assert function_name == rs["Configuration"]["FunctionName"] assert "x86_64" in rs["Configuration"]["Architectures"] result = lambda_client.invoke(FunctionName=function_name) result = to_str(result["Payload"].read()) assert result.strip('" \n') == "hello world" template_2 = jinja2.Template( load_template_raw("lambda_inline_code.yaml")).render( lambda_return_value="hello globe", arch="arm64", function_name=function_name) cfn_client.update_stack(StackName=stack_name, TemplateBody=template_2, Capabilities=["CAPABILITY_IAM"]) wait_until(is_stack_updated(stack_id)) rs = lambda_client.get_function(FunctionName=function_name) assert function_name == rs["Configuration"]["FunctionName"] assert "arm64" in rs["Configuration"]["Architectures"] result = lambda_client.invoke(FunctionName=function_name) result = to_str(result["Payload"].read()) assert result.strip('" \n') == "hello globe" finally: # cleanup cleanup_stacks([stack_name])
def test_intrinsic_functions( cfn_client, s3_client, cleanup_stacks, cleanup_changesets, is_change_set_created_and_available, is_stack_created, intrinsic_fn, parameter_1, parameter_2, expected_bucket_created, ): stack_name = f"stack-{short_uid()}" change_set_name = f"change-set-{short_uid()}" bucket_name = f"ls-bucket-{short_uid()}" template_rendered = jinja2.Template( load_template_raw("cfn_intrinsic_functions.yaml")).render( bucket_name=bucket_name, intrinsic_fn=intrinsic_fn, ) response = cfn_client.create_change_set( StackName=stack_name, ChangeSetName=change_set_name, TemplateBody=template_rendered, ChangeSetType="CREATE", Parameters=[ { "ParameterKey": "Param1", "ParameterValue": parameter_1 }, { "ParameterKey": "Param2", "ParameterValue": parameter_2 }, ], ) change_set_id = response["Id"] stack_id = response["StackId"] try: wait_until(is_change_set_created_and_available(change_set_id)) cfn_client.execute_change_set(ChangeSetName=change_set_id) wait_until(is_stack_created(stack_id)) buckets = s3_client.list_buckets() bucket_names = [b["Name"] for b in buckets["Buckets"]] assert (bucket_name in bucket_names) == expected_bucket_created finally: cleanup_changesets([change_set_id]) cleanup_stacks([stack_id])
def test_resolve_ssm_withversion( ssm_client, cfn_client, is_change_set_created_and_available, is_stack_created, cleanup_changesets, cleanup_stacks, create_parameter, ): stack_name = f"stack-{short_uid()}" change_set_name = f"change-set-{short_uid()}" parameter_key = f"param-key-{short_uid()}" parameter_value_v0 = f"param-value-{short_uid()}" parameter_value_v1 = f"param-value-{short_uid()}" parameter_value_v2 = f"param-value-{short_uid()}" create_parameter(Name=parameter_key, Type="String", Value=parameter_value_v0) v1 = ssm_client.put_parameter( Name=parameter_key, Overwrite=True, Type="String", Value=parameter_value_v1 ) ssm_client.put_parameter( Name=parameter_key, Overwrite=True, Type="String", Value=parameter_value_v2 ) template_rendered = jinja2.Template(load_template_raw("resolve_ssm_withversion.yaml")).render( parameter_key=parameter_key, parameter_version=str(v1["Version"]) ) response = cfn_client.create_change_set( StackName=stack_name, ChangeSetName=change_set_name, TemplateBody=template_rendered, ChangeSetType="CREATE", ) change_set_id = response["Id"] stack_id = response["StackId"] try: wait_until(is_change_set_created_and_available(change_set_id)) cfn_client.execute_change_set(ChangeSetName=change_set_id) wait_until(is_stack_created(stack_id)) describe_result = cfn_client.describe_stacks(StackName=stack_id)["Stacks"][0] assert describe_result["StackStatus"] == "CREATE_COMPLETE" topic_name = [ o["OutputValue"] for o in describe_result["Outputs"] if o["OutputKey"] == "TopicName" ][0] assert topic_name == parameter_value_v1 finally: cleanup_changesets([change_set_id]) cleanup_stacks([stack_id])
def test_logstream( cfn_client, logs_client, cleanup_stacks, cleanup_changesets, is_change_set_created_and_available, is_stack_created, ): stack_name = f"stack-{short_uid()}" change_set_name = f"change-set-{short_uid()}" response = cfn_client.create_change_set( StackName=stack_name, ChangeSetName=change_set_name, TemplateBody=load_template_raw("logs_group_and_stream.yaml"), ChangeSetType="CREATE", ) change_set_id = response["Id"] stack_id = response["StackId"] try: wait_until(is_change_set_created_and_available(change_set_id)) cfn_client.execute_change_set(ChangeSetName=change_set_id) wait_until(is_stack_created(stack_id)) assert (cfn_client.describe_stacks(StackName=stack_id)["Stacks"][0] ["StackStatus"] == "CREATE_COMPLETE") descr_response = cfn_client.describe_stacks(StackName=stack_id) outputs = { o["OutputKey"]: o["OutputValue"] for o in descr_response["Stacks"][0]["Outputs"] } group_name = outputs["LogGroupNameOutput"] stream_name = outputs["LogStreamNameOutput"] assert group_name assert stream_name streams = logs_client.describe_log_streams( logGroupName=group_name, logStreamNamePrefix=stream_name)["logStreams"] assert len(streams) == 1 assert streams[0]["logStreamName"] == stream_name assert re.match( r"arn:(aws|aws-cn|aws-iso|aws-iso-b|aws-us-gov):logs:.+:.+:log-group:.+:log-stream:.+", streams[0]["arn"], ) assert testutil.response_arn_matches_partition(cfn_client, streams[0]["arn"]) finally: cleanup_changesets([change_set_id]) cleanup_stacks([stack_id])
def test_url_output( cfn_client, apigateway_client, is_change_set_created_and_available, is_stack_created, cleanup_changesets, cleanup_stacks, tmp_http_server, ): test_port, invocations, proxy = tmp_http_server integration_uri = f"http://localhost:{test_port}/{{proxy}}" api_name = f"rest-api-{short_uid()}" stack_name = f"stack-{short_uid()}" change_set_name = f"change-set-{short_uid()}" template_rendered = jinja2.Template( load_template_raw("apigateway-url-output.yaml")).render( api_name=api_name, integration_uri=integration_uri) response = cfn_client.create_change_set( StackName=stack_name, ChangeSetName=change_set_name, TemplateBody=template_rendered, ChangeSetType="CREATE", ) change_set_id = response["Id"] stack_id = response["StackId"] try: wait_until(is_change_set_created_and_available(change_set_id)) cfn_client.execute_change_set(ChangeSetName=change_set_id) wait_until(is_stack_created(stack_id)) describe_response = cfn_client.describe_stacks(StackName=stack_id) outputs = describe_response["Stacks"][0]["Outputs"] assert len(outputs) == 2 api_id = [ o["OutputValue"] for o in outputs if o["OutputKey"] == "ApiV1IdOutput" ][0] api_url = [ o["OutputValue"] for o in outputs if o["OutputKey"] == "ApiV1UrlOutput" ][0] assert api_id assert api_url assert api_id in api_url assert f"https://{api_id}.execute-api.{constants.LOCALHOST_HOSTNAME}:4566" in api_url finally: cleanup_changesets([change_set_id]) cleanup_stacks([stack_id])
def test_eventbus_policy_statement( cfn_client, events_client, cleanup_stacks, cleanup_changesets, is_change_set_created_and_available, is_stack_created, ): stack_name = f"stack-{short_uid()}" change_set_name = f"change-set-{short_uid()}" event_bus_name = f"event-bus-{short_uid()}" statement_id = f"statement-{short_uid()}" template_rendered = jinja2.Template( load_template_raw("eventbridge_policy_statement.yaml")).render( event_bus_name=event_bus_name, statement_id=statement_id) response = cfn_client.create_change_set( StackName=stack_name, ChangeSetName=change_set_name, TemplateBody=template_rendered, ChangeSetType="CREATE", ) change_set_id = response["Id"] stack_id = response["StackId"] try: wait_until(is_change_set_created_and_available(change_set_id)) cfn_client.execute_change_set(ChangeSetName=change_set_id) wait_until(is_stack_created(stack_id)) assert (cfn_client.describe_stacks(StackName=stack_id)["Stacks"][0] ["StackStatus"] == "CREATE_COMPLETE") describe_response = events_client.describe_event_bus( Name=event_bus_name) policy = json.loads(describe_response["Policy"]) assert policy["Version"] == "2012-10-17" assert len(policy["Statement"]) == 1 statement = policy["Statement"][0] assert statement["Sid"] == statement_id assert statement["Action"] == "events:PutEvents" assert statement["Principal"] == "*" assert statement["Effect"] == "Allow" assert event_bus_name in statement["Resource"] finally: cleanup_changesets([change_set_id]) cleanup_stacks([stack_id])
def test_parameter_defaults( cfn_client, cleanup_stacks, cleanup_changesets, is_change_set_created_and_available, is_stack_created, is_stack_deleted, ssm_client, ): stack_name = f"stack-{short_uid()}" change_set_name = f"change-set-{short_uid()}" ssm_parameter_value = f"custom-{short_uid()}" template_rendered = jinja2.Template(load_template_raw("ssm_parameter_defaultname.yaml")).render( ssm_parameter_value=ssm_parameter_value ) response = cfn_client.create_change_set( StackName=stack_name, ChangeSetName=change_set_name, TemplateBody=template_rendered, ChangeSetType="CREATE", ) change_set_id = response["Id"] stack_id = response["StackId"] try: wait_until(is_change_set_created_and_available(change_set_id)) cfn_client.execute_change_set(ChangeSetName=change_set_id) wait_until(is_stack_created(stack_id)) stack = cfn_client.describe_stacks(StackName=stack_id)["Stacks"][0] parameter_name = stack["Outputs"][0]["OutputValue"] assert "CustomParameter" in parameter_name param = ssm_client.get_parameter(Name=parameter_name) assert param["Parameter"]["Value"] == ssm_parameter_value # make sure parameter is deleted cfn_client.delete_stack(StackName=stack_id) wait_until(is_stack_deleted(stack_id)) with pytest.raises(Exception) as ctx: ssm_client.get_parameter(Name=parameter_name) ctx.match("ParameterNotFound") finally: cleanup_changesets([change_set_id]) cleanup_stacks([stack_id])
def test_resolve_secretsmanager( secretsmanager_client, cfn_client, is_change_set_created_and_available, is_stack_created, create_secret, create_parameter, cleanup_changesets, cleanup_stacks, template_name, ): stack_name = f"stack-{short_uid()}" change_set_name = f"change-set-{short_uid()}" parameter_key = f"param-key-{short_uid()}" parameter_value = f"param-value-{short_uid()}" create_secret(Name=parameter_key, SecretString=parameter_value) template_rendered = jinja2.Template(load_template_raw(template_name)).render( parameter_key=parameter_key, ) response = cfn_client.create_change_set( StackName=stack_name, ChangeSetName=change_set_name, TemplateBody=template_rendered, ChangeSetType="CREATE", ) change_set_id = response["Id"] stack_id = response["StackId"] try: wait_until(is_change_set_created_and_available(change_set_id)) cfn_client.execute_change_set(ChangeSetName=change_set_id) wait_until(is_stack_created(stack_id)) describe_result = cfn_client.describe_stacks(StackName=stack_id)["Stacks"][0] assert describe_result["StackStatus"] == "CREATE_COMPLETE" topic_name = [ o["OutputValue"] for o in describe_result["Outputs"] if o["OutputKey"] == "TopicName" ][0] assert topic_name == parameter_value finally: cleanup_changesets([change_set_id]) cleanup_stacks([stack_id])
def test_list_stack_resources_for_removed_resource(cfn_client, is_stack_created, is_change_set_finished): event_bus_name = f"bus-{short_uid()}" template = jinja2.Template( load_template_raw("eventbridge_policy.yaml")).render( event_bus_name=event_bus_name) stack_name = f"stack-{short_uid()}" response = cfn_client.create_stack(StackName=stack_name, TemplateBody=template) stack_id = response["StackId"] assert stack_id wait_until(is_stack_created(stack_id)) # get list of stack resources resources = cfn_client.list_stack_resources( StackName=stack_name)["StackResourceSummaries"] resources_before = len(resources) assert resources_before == 3 statuses = set([res["ResourceStatus"] for res in resources]) assert statuses == {"CREATE_COMPLETE", "UPDATE_COMPLETE"} # remove one resource from the template, then update stack (via change set) template_dict = yaml.load(template) template_dict["Resources"].pop("eventPolicy2") template2 = yaml.dump(template_dict) response = cfn_client.create_change_set(StackName=stack_name, ChangeSetName="cs1", TemplateBody=template2) change_set_id = response["Id"] cfn_client.execute_change_set(ChangeSetName=change_set_id) wait_until(is_change_set_finished(change_set_id)) # get list of stack resources, again - make sure that deleted resource is not contained in result resources = cfn_client.list_stack_resources( StackName=stack_name)["StackResourceSummaries"] assert len(resources) == resources_before - 1 statuses = set([res["ResourceStatus"] for res in resources]) assert statuses == {"CREATE_COMPLETE", "UPDATE_COMPLETE"}
def test_sns_subscription( cfn_client, sns_client, cleanup_stacks, cleanup_changesets, is_change_set_created_and_available, is_stack_created, ): stack_name = f"stack-{short_uid()}" change_set_name = f"change-set-{short_uid()}" topic_name = f"topic-{short_uid()}" queue_name = f"topic-{short_uid()}" template_rendered = jinja2.Template(load_template_raw("sns_topic_subscription.yaml")).render( topic_name=topic_name, queue_name=queue_name ) response = cfn_client.create_change_set( StackName=stack_name, ChangeSetName=change_set_name, TemplateBody=template_rendered, ChangeSetType="CREATE", ) change_set_id = response["Id"] stack_id = response["StackId"] try: wait_until(is_change_set_created_and_available(change_set_id)) cfn_client.execute_change_set(ChangeSetName=change_set_id) wait_until(is_stack_created(stack_id)) outputs = cfn_client.describe_stacks(StackName=stack_id)["Stacks"][0]["Outputs"] assert len(outputs) == 1 and outputs[0]["OutputKey"] == "TopicArnOutput" topic_arn = outputs[0]["OutputValue"] assert topic_arn is not None subscriptions = sns_client.list_subscriptions_by_topic(TopicArn=topic_arn) assert len(subscriptions["Subscriptions"]) > 0 finally: cleanup_changesets([change_set_id]) cleanup_stacks([stack_id])
def test_kms_key_disabled( cfn_client, sqs_client, kms_client, cleanup_stacks, cleanup_changesets, is_change_set_created_and_available, is_stack_created, ): stack_name = f"stack-{short_uid()}" change_set_name = f"change-set-{short_uid()}" template_rendered = load_template_raw("kms_key_disabled.yaml") response = cfn_client.create_change_set( StackName=stack_name, ChangeSetName=change_set_name, TemplateBody=template_rendered, ChangeSetType="CREATE", ) change_set_id = response["Id"] stack_id = response["StackId"] try: wait_until(is_change_set_created_and_available(change_set_id)) cfn_client.execute_change_set(ChangeSetName=change_set_id) wait_until(is_stack_created(stack_id)) outputs = cfn_client.describe_stacks( StackName=stack_id)["Stacks"][0]["Outputs"] assert len(outputs) == 1 key_id = outputs[0]["OutputValue"] assert key_id my_key = kms_client.describe_key(KeyId=key_id) assert not my_key["KeyMetadata"]["Enabled"] finally: cleanup_changesets([change_set_id]) cleanup_stacks([stack_id])
def test_sns_topic_fifo_with_deduplication( cfn_client, sns_client, cleanup_stacks, cleanup_changesets, is_change_set_created_and_available, is_stack_created, ): stack_name = f"stack-{short_uid()}" change_set_name = f"change-set-{short_uid()}" topic_name = f"topic-{short_uid()}.fifo" template_rendered = jinja2.Template(load_template_raw("sns_topic_fifo_dedup.yaml")).render( sns_topic=topic_name ) response = cfn_client.create_change_set( StackName=stack_name, ChangeSetName=change_set_name, TemplateBody=template_rendered, ChangeSetType="CREATE", ) change_set_id = response["Id"] stack_id = response["StackId"] try: wait_until(is_change_set_created_and_available(change_set_id)) cfn_client.execute_change_set(ChangeSetName=change_set_id) wait_until(is_stack_created(stack_id)) topics = sns_client.list_topics()["Topics"] topic_arns = [t["TopicArn"] for t in topics] assert len([t for t in topic_arns if topic_name in t]) == 1 finally: cleanup_changesets([change_set_id]) cleanup_stacks([stack_id])
def test_lambda_autogenerated_name( cfn_client, lambda_client, cleanup_stacks, cleanup_changesets, is_change_set_created_and_available, is_stack_created, ): stack_name = f"stack-{short_uid()}" change_set_name = f"change-set-{short_uid()}" lambda_functional_id = f"MyFn{short_uid()}" template_rendered = jinja2.Template( load_template_raw("cfn_lambda_noname.yaml")).render( lambda_functional_id=lambda_functional_id) response = cfn_client.create_change_set( StackName=stack_name, ChangeSetName=change_set_name, TemplateBody=template_rendered, ChangeSetType="CREATE", ) change_set_id = response["Id"] stack_id = response["StackId"] try: wait_until(is_change_set_created_and_available(change_set_id)) cfn_client.execute_change_set(ChangeSetName=change_set_id) wait_until(is_stack_created(stack_id)) outputs = cfn_client.describe_stacks( StackName=stack_id)["Stacks"][0]["Outputs"] assert len(outputs) == 1 assert lambda_functional_id in outputs[0]["OutputValue"] finally: cleanup_changesets([change_set_id]) cleanup_stacks([stack_id])
def test_create_stack_with_ssm_parameters(cfn_client, ssm_client, sns_client, cleanup_stacks, is_stack_created): stack_name = f"stack-{short_uid()}" parameter_name = f"ls-param-{short_uid()}" parameter_value = f"ls-param-value-{short_uid()}" parameter_logical_id = "parameter123" ssm_client.put_parameter(Name=parameter_name, Value=parameter_value, Type="String") template = load_template_raw("dynamicparameter_ssm_string.yaml") template_rendered = jinja2.Template(template).render( parameter_name=parameter_name) response = cfn_client.create_stack( StackName=stack_name, TemplateBody=template_rendered, ) stack_id = response["StackId"] assert stack_id try: wait_until(is_stack_created(stack_id)) created_stack = cfn_client.describe_stacks( StackName=stack_name)["Stacks"][0] assert created_stack is not None assert created_stack["Parameters"][0][ "ParameterKey"] == parameter_logical_id assert created_stack["Parameters"][0][ "ParameterValue"] == parameter_name assert created_stack["Parameters"][0][ "ResolvedValue"] == parameter_value topics = sns_client.list_topics() topic_arns = [t["TopicArn"] for t in topics["Topics"]] assert any(parameter_value in t for t in topic_arns) finally: cleanup_stacks([stack_id])
def test_sqs_queue_policy( cfn_client, sqs_client, cleanup_stacks, cleanup_changesets, is_change_set_created_and_available, is_stack_created, ): stack_name = f"stack-{short_uid()}" change_set_name = f"change-set-{short_uid()}" template_rendered = load_template_raw("sqs_with_queuepolicy.yaml") response = cfn_client.create_change_set( StackName=stack_name, ChangeSetName=change_set_name, TemplateBody=template_rendered, ChangeSetType="CREATE", ) change_set_id = response["Id"] stack_id = response["StackId"] try: wait_until(is_change_set_created_and_available(change_set_id)) cfn_client.execute_change_set(ChangeSetName=change_set_id) wait_until(is_stack_created(stack_id)) outputs = cfn_client.describe_stacks(StackName=stack_id)["Stacks"][0]["Outputs"] assert len(outputs) == 1 queue_url = outputs[0]["OutputValue"] resp = sqs_client.get_queue_attributes(QueueUrl=queue_url, AttributeNames=["Policy"]) assert ( "Statement" in resp["Attributes"]["Policy"] ) # just kind of a smoke test to see if its set finally: cleanup_changesets([change_set_id]) cleanup_stacks([stack_id])
def test_policy_attachments( cfn_client, iam_client, cleanup_stacks, cleanup_changesets, is_change_set_created_and_available, is_stack_created, ): stack_name = f"stack-{short_uid()}" change_set_name = f"change-set-{short_uid()}" role_name = f"role-{short_uid()}" group_name = f"group-{short_uid()}" user_name = f"user-{short_uid()}" policy_name = f"policy-{short_uid()}" template_rendered = jinja2.Template( load_template_raw("iam_policy_attachments.yaml")).render( role_name=role_name, policy_name=policy_name, user_name=user_name, group_name=group_name, ) response = cfn_client.create_change_set( StackName=stack_name, ChangeSetName=change_set_name, TemplateBody=template_rendered, ChangeSetType="CREATE", ) change_set_id = response["Id"] stack_id = response["StackId"] try: wait_until(is_change_set_created_and_available(change_set_id)) cfn_client.execute_change_set(ChangeSetName=change_set_id) wait_until(is_stack_created(stack_id)) # check inline policies role_inline_policies = iam_client.list_role_policies( RoleName=role_name) user_inline_policies = iam_client.list_user_policies( UserName=user_name) group_inline_policies = iam_client.list_group_policies( GroupName=group_name) assert len(role_inline_policies["PolicyNames"]) == 1 assert len(user_inline_policies["PolicyNames"]) == 1 assert len(group_inline_policies["PolicyNames"]) == 1 # check managed/attached policies role_attached_policies = iam_client.list_attached_role_policies( RoleName=role_name) user_attached_policies = iam_client.list_attached_user_policies( UserName=user_name) group_attached_policies = iam_client.list_attached_group_policies( GroupName=group_name) assert len(role_attached_policies["AttachedPolicies"]) == 1 assert len(user_attached_policies["AttachedPolicies"]) == 1 assert len(group_attached_policies["AttachedPolicies"]) == 1 finally: cleanup_changesets([change_set_id]) cleanup_stacks([stack_id])
def test_event_rule_to_logs( cfn_client, events_client, logs_client, cleanup_stacks, cleanup_changesets, is_change_set_created_and_available, is_stack_created, ): stack_name = f"stack-{short_uid()}" change_set_name = f"change-set-{short_uid()}" event_rule_name = f"event-rule-{short_uid()}" log_group_name = f"log-group-{short_uid()}" message_token = f"test-message-{short_uid()}" event_bus_name = f"bus-{short_uid()}" resource_policy_name = f"policy-{short_uid()}" template_rendered = jinja2.Template( load_template_raw("events_loggroup.yaml")).render( event_rule_name=event_rule_name, log_group_name=log_group_name, event_bus_name=event_bus_name, resource_policy_name=resource_policy_name, ) response = cfn_client.create_change_set( StackName=stack_name, ChangeSetName=change_set_name, TemplateBody=template_rendered, ChangeSetType="CREATE", ) change_set_id = response["Id"] stack_id = response["StackId"] try: wait_until(is_change_set_created_and_available(change_set_id)) cfn_client.execute_change_set(ChangeSetName=change_set_id) wait_until(is_stack_created(stack_id)) assert (cfn_client.describe_stacks(StackName=stack_id)["Stacks"][0] ["StackStatus"] == "CREATE_COMPLETE") log_groups = logs_client.describe_log_groups( logGroupNamePrefix=log_group_name)["logGroups"] log_group_names = [lg["logGroupName"] for lg in log_groups] assert log_group_name in log_group_names resp = events_client.put_events( Entries=[{ "Source": "unittest", "Resources": [], "DetailType": "ls-detail-type", "Detail": json.dumps({"messagetoken": message_token}), "EventBusName": event_bus_name, }]) assert len(resp["Entries"]) == 1 wait_until( lambda: len( logs_client.describe_log_streams(logGroupName=log_group_name)[ "logStreams"]) > 0, 1.0, 5, "linear", ) log_streams = logs_client.describe_log_streams( logGroupName=log_group_name)["logStreams"] assert len(log_streams) == 1 log_events = logs_client.get_log_events( logGroupName=log_group_name, logStreamName=log_streams[0]["logStreamName"]) assert message_token in log_events["events"][0]["message"] finally: cleanup_changesets([change_set_id]) cleanup_stacks([stack_id])
def test_eventbus_policies( cfn_client, events_client, cleanup_stacks, cleanup_changesets, is_change_set_created_and_available, is_stack_created, ): stack_name = f"stack-{short_uid()}" change_set_name = f"change-set-{short_uid()}" event_bus_name = f"event-bus-{short_uid()}" template_rendered = jinja2.Template( load_template_raw("eventbridge_policy.yaml")).render( event_bus_name=event_bus_name) response = cfn_client.create_change_set( StackName=stack_name, ChangeSetName=change_set_name, TemplateBody=template_rendered, ChangeSetType="CREATE", ) change_set_id = response["Id"] stack_id = response["StackId"] try: wait_until(is_change_set_created_and_available(change_set_id)) cfn_client.execute_change_set(ChangeSetName=change_set_id) wait_until(is_stack_created(stack_id)) assert (cfn_client.describe_stacks(StackName=stack_id)["Stacks"][0] ["StackStatus"] == "CREATE_COMPLETE") # check that both statements were added describe_response = events_client.describe_event_bus( Name=event_bus_name) policy = json.loads(describe_response["Policy"]) assert len(policy["Statement"]) == 2 # verify physical resource ID creation pol1_description = cfn_client.describe_stack_resource( StackName=stack_id, LogicalResourceId="eventPolicy") pol2_description = cfn_client.describe_stack_resource( StackName=stack_id, LogicalResourceId="eventPolicy2") assert (pol1_description["StackResourceDetail"]["PhysicalResourceId"] != pol2_description["StackResourceDetail"]["PhysicalResourceId"]) # TODO: Fix cloudformation change set update status # TODO: Fix second changeset execution (should delete resource in stack's _resource_states) # delete one of the 2 statements and check if the other still exists # template_rendered_single_policy = jinja2.Template(load_template_raw("eventbridge_policy_singlepolicy.yaml")).render( # event_bus_name=event_bus_name # ) # change_set_name = f"change-set-update-{short_uid()}" # response = cfn_client.create_change_set( # StackName=stack_name, # ChangeSetName=change_set_name, # TemplateBody=template_rendered_single_policy, # ) # change_set_id = response["Id"] # wait_until(is_change_set_created_and_available(change_set_id)) # cfn_client.execute_change_set(ChangeSetName=change_set_id) # cfn_client.get_waiter("stack_create_complete").wait(StackName=stack_id, WaiterConfig={'Delay': 5, 'MaxAttempts': 10}) # TODO: should be get_waiter("stack_update_complete") # # describe_response = events_client.describe_event_bus(Name=event_bus_name) # policy = json.loads(describe_response['Policy']) # assert len(policy['Statement']) == 1 finally: cleanup_changesets([change_set_id]) cleanup_stacks([stack_id])
def test_nested_statemachine_with_sync2( cfn_client, lambda_client, cleanup_stacks, cleanup_changesets, is_change_set_created_and_available, is_stack_created, stepfunctions_client, s3_client, ): stack_name = f"stack-{short_uid()}" change_set_name = f"change-set-{short_uid()}" response = cfn_client.create_change_set( StackName=stack_name, ChangeSetName=change_set_name, TemplateBody=load_template_raw("sfn_nested_sync2.json"), ChangeSetType="CREATE", Capabilities=["CAPABILITY_IAM"], ) change_set_id = response["Id"] stack_id = response["StackId"] try: wait_until(is_change_set_created_and_available(change_set_id)) cfn_client.execute_change_set(ChangeSetName=change_set_id) wait_until(is_stack_created(stack_id)) stack_result = cfn_client.describe_stacks(StackName=stack_id) assert stack_result["Stacks"][0]["StackStatus"] == "CREATE_COMPLETE" parent_arn = [ o["OutputValue"] for o in stack_result["Stacks"][0]["Outputs"] if o["OutputKey"] == "ParentStateMachineArnOutput" ][0] ex_result = stepfunctions_client.start_execution( stateMachineArn=parent_arn, input='{"Value": 1}' ) def _is_executed(): return ( stepfunctions_client.describe_execution(executionArn=ex_result["executionArn"])[ "status" ] != "RUNNING" ) wait_until(_is_executed) execution_desc = stepfunctions_client.describe_execution( executionArn=ex_result["executionArn"] ) assert execution_desc["status"] == "SUCCEEDED" output = json.loads(execution_desc["output"]) assert output["Value"] == 3 finally: cleanup_changesets([change_set_id]) cleanup_stacks([stack_id])
def test_delete_role_detaches_role_policy( cfn_client, iam_client, cleanup_stacks, cleanup_changesets, is_change_set_created_and_available, is_stack_created, ): stack_name = f"stack-{short_uid()}" change_set_name = f"change-set-{short_uid()}" role_name = f"LsRole{short_uid()}" policy_name = f"LsPolicy{short_uid()}" template_rendered = jinja2.Template( load_template_raw("iam_role_policy.yaml")).render( role_name=role_name, policy_name=policy_name, include_policy=True, ) response = cfn_client.create_change_set( StackName=stack_name, ChangeSetName=change_set_name, TemplateBody=template_rendered, ChangeSetType="CREATE", ) change_set_id = response["Id"] stack_id = response["StackId"] try: wait_until(is_change_set_created_and_available(change_set_id)) cfn_client.execute_change_set(ChangeSetName=change_set_id) wait_until(is_stack_created(stack_id)) attached_policies = iam_client.list_attached_role_policies( RoleName=role_name)["AttachedPolicies"] assert len(attached_policies) > 0 # nopolicy_template = jinja2.Template(load_template_raw("iam_role_policy.yaml")).render( # role_name=role_name, # policy_name=policy_name, # include_policy=False, # ) # nopolicy_changeset_name = f"change-set-{short_uid()}" # response = cfn_client.create_change_set( # StackName=stack_name, # ChangeSetName=nopolicy_changeset_name, # TemplateBody=nopolicy_template, # ChangeSetType="UPDATE", # ) # change_set_id = response["Id"] # wait_until(is_change_set_created_and_available(change_set_id)) # cfn_client.execute_change_set(ChangeSetName=change_set_id) # time.sleep(5) # wait_until(is_stack_created(stack_id)) # TODO: wrong format # wait_until(is_stack_deleted(stack_id)) # TODO: need to update stack to delete only a single resource # attached_policies = iam_client.list_attached_role_policies(RoleName=role_name)['AttachedPolicies'] # assert len(attached_policies) == 0 finally: cleanup_changesets([change_set_id]) cleanup_stacks([stack_id])
def test_cfn_apigateway_aws_integration( cfn_client, apigateway_client, s3_client, iam_client, is_change_set_created_and_available, is_stack_created, cleanup_changesets, cleanup_stacks, ): api_name = f"rest-api-{short_uid()}" stack_name = f"stack-{short_uid()}" change_set_name = f"change-set-{short_uid()}" template_rendered = jinja2.Template( load_template_raw("apigw-awsintegration-request-parameters.yaml") ).render(api_name=api_name) response = cfn_client.create_change_set( StackName=stack_name, ChangeSetName=change_set_name, TemplateBody=template_rendered, ChangeSetType="CREATE", ) change_set_id = response["Id"] stack_id = response["StackId"] try: wait_until(is_change_set_created_and_available(change_set_id)) cfn_client.execute_change_set(ChangeSetName=change_set_id) wait_until(is_stack_created(stack_id)) # check resources creation apis = [ api for api in apigateway_client.get_rest_apis()["items"] if api["name"] == api_name ] assert len(apis) == 1 api_id = apis[0]["id"] # check resources creation resources = apigateway_client.get_resources(restApiId=api_id)["items"] assert (resources[0]["resourceMethods"]["GET"]["requestParameters"] ["method.request.path.id"] is False) assert (resources[0]["resourceMethods"]["GET"]["methodIntegration"] ["requestParameters"]["integration.request.path.object"] == "method.request.path.id") # check domains creation domain_names = [ domain["domainName"] for domain in apigateway_client.get_domain_names()["items"] ] assert len(domain_names) == 1 assert domain_names[0] == "localstack.cloud" # check basepath mappings creation mappings = [ mapping["basePath"] for mapping in apigateway_client.get_base_path_mappings( domainName=domain_names[0])["items"] ] assert len(mappings) == 1 assert mappings[0] == "(none)" finally: cleanup_changesets([change_set_id]) cleanup_stacks([stack_id])