def _directory_factory( existing_directory_stack_name, existing_nlb_stack_name, directory_type, bucket_name, test_resources_dir, region, ad_admin_password, ad_user_password, ): directory_stack = None if existing_directory_stack_name: directory_stack_name = existing_directory_stack_name directory_stack = CfnStack(name=directory_stack_name, region=region, template=None) logging.info("Using pre-existing directory stack named %s", directory_stack_name) elif created_directory_stacks.get(region, {}).get("directory"): directory_stack_name = created_directory_stacks.get( region, {}).get("directory") directory_stack = CfnStack(name=directory_stack_name, region=region, template=None) logging.info( "Using directory stack named %s created by another test", directory_stack_name) else: directory_stack = _create_directory_stack( cfn_stacks_factory, request, directory_type, test_resources_dir, ad_admin_password, ad_user_password, bucket_name, region, vpc_stacks[region], ) directory_stack_name = directory_stack.name created_directory_stacks[region][ "directory"] = directory_stack_name _populate_directory_with_users(directory_stack, NUM_USERS_TO_CREATE, region) # Create NLB that will be used to enable LDAPS if existing_nlb_stack_name: nlb_stack_name = existing_nlb_stack_name logging.info("Using pre-existing NLB stack named %s", nlb_stack_name) elif created_directory_stacks.get(region, {}).get("nlb"): nlb_stack_name = created_directory_stacks.get(region, {}).get("nlb") logging.info("Using NLB stack named %s created by another test", nlb_stack_name) else: nlb_stack_name = _create_nlb_stack(cfn_stacks_factory, request, directory_stack, region, test_resources_dir).name created_directory_stacks[region]["nlb"] = nlb_stack_name return directory_stack_name, nlb_stack_name
def _create_vpc_stack(request, template, region, cfn_stacks_factory): if request.config.getoption("vpc_stack"): logging.info("Using stack {0} in region {1}".format( request.config.getoption("vpc_stack"), region)) stack = CfnStack(name=request.config.getoption("vpc_stack"), region=region, template=template.to_json()) else: stack = CfnStack(name="integ-tests-vpc-" + random_alphanumeric(), region=region, template=template.to_json()) cfn_stacks_factory.create_stack(stack) return stack
def _fsx_factory(**kwargs): # FSx stack fsx_template = Template() fsx_template.set_version() fsx_template.set_description("Create FSx stack") # Create security group. If using an existing file system # It must be associated to a security group that allows inbound TCP traffic to port 988 fsx_sg = ec2.SecurityGroup( "FSxSecurityGroup", GroupDescription="SecurityGroup for testing existing FSx", SecurityGroupIngress=[ ec2.SecurityGroupRule( IpProtocol="tcp", FromPort="988", ToPort="988", CidrIp="0.0.0.0/0", ), ], VpcId=vpc_stack.cfn_outputs["VpcId"], ) fsx_filesystem = FileSystem( SecurityGroupIds=[Ref(fsx_sg)], SubnetIds=[vpc_stack.cfn_outputs["PublicSubnetId"]], **kwargs ) fsx_template.add_resource(fsx_sg) fsx_template.add_resource(fsx_filesystem) fsx_stack = CfnStack( name=fsx_stack_name, region=region, template=fsx_template.to_json(), ) cfn_stacks_factory.create_stack(fsx_stack) return fsx_stack.cfn_resources[kwargs.get("title")]
def api_with_default_settings(api_infrastructure_s3_uri, public_ecr_image_uri, api_definition_s3_uri, request, region): factory = CfnStacksFactory(request.config.getoption("credential")) params = [] if api_definition_s3_uri: params.append({ "ParameterKey": "ApiDefinitionS3Uri", "ParameterValue": api_definition_s3_uri }) if public_ecr_image_uri: params.append({ "ParameterKey": "PublicEcrImageUri", "ParameterValue": public_ecr_image_uri }) template = ( api_infrastructure_s3_uri or f"s3://{region}-aws-parallelcluster/parallelcluster/{get_installed_parallelcluster_version()}" "/api/parallelcluster-api.yaml") logging.info( f"Creating API Server stack in {region} with template {template}") stack = CfnStack( name=generate_stack_name("integ-tests-api", request.config.getoption("stackname_suffix")), region=region, parameters=params, capabilities=["CAPABILITY_NAMED_IAM", "CAPABILITY_AUTO_EXPAND"], template=template, ) try: factory.create_stack(stack) yield stack finally: factory.delete_all_stacks()
def custom_security_group(vpc_stack, region, request, cfn_stacks_factory): template = Template() template.set_version("2010-09-09") template.set_description("custom security group stack for testing additional_sg and vpc_security_group_id") security_group = template.add_resource( SecurityGroup( "SecurityGroupResource", GroupDescription="custom security group for testing additional_sg and vpc_security_group_id", VpcId=vpc_stack.cfn_outputs["VpcId"], ) ) template.add_resource( SecurityGroupIngress( "SecurityGroupIngressResource", IpProtocol="-1", FromPort=0, ToPort=65535, SourceSecurityGroupId=Ref(security_group), GroupId=Ref(security_group), ) ) stack = CfnStack( name=generate_stack_name("integ-tests-custom-sg", request.config.getoption("stackname_suffix")), region=region, template=template.to_json(), ) cfn_stacks_factory.create_stack(stack) yield stack if not request.config.getoption("no_delete"): cfn_stacks_factory.delete_stack(stack.name, region)
def vpc_stacks(cfn_stacks_factory, request): """Create VPC used by integ tests in all configured regions.""" regions = request.config.getoption("regions") vpc_stacks = {} for region in regions: # defining subnets per region to allow AZs override public_subnet = SubnetConfig( name="PublicSubnet", cidr="10.0.0.0/24", map_public_ip_on_launch=True, has_nat_gateway=True, default_gateway=Gateways.INTERNET_GATEWAY, availability_zone=random.choice( _AVAILABILITY_ZONE_OVERRIDES.get(region, [None])), ) private_subnet = SubnetConfig( name="PrivateSubnet", cidr="10.0.1.0/24", map_public_ip_on_launch=False, has_nat_gateway=False, default_gateway=Gateways.NAT_GATEWAY, availability_zone=random.choice( _AVAILABILITY_ZONE_OVERRIDES.get(region, [None])), ) vpc_config = VPCConfig(subnets=[public_subnet, private_subnet]) template = VPCTemplateBuilder(vpc_config).build() stack = CfnStack(name="integ-tests-vpc-" + random_alphanumeric(), region=region, template=template.to_json()) cfn_stacks_factory.create_stack(stack) vpc_stacks[region] = stack return vpc_stacks
def vpc_stacks(cfn_stacks_factory, request): """Create VPC used by integ tests in all configured regions.""" public_subnet = SubnetConfig( name="PublicSubnet", cidr="10.0.0.0/24", map_public_ip_on_launch=True, has_nat_gateway=True, default_gateway=Gateways.INTERNET_GATEWAY, ) private_subnet = SubnetConfig( name="PrivateSubnet", cidr="10.0.1.0/24", map_public_ip_on_launch=False, has_nat_gateway=False, default_gateway=Gateways.NAT_GATEWAY, ) vpc_config = VPCConfig(subnets=[public_subnet, private_subnet]) template = VPCTemplateBuilder(vpc_config).build() regions = request.config.getoption("regions") vpc_stacks = {} for region in regions: stack = CfnStack(name="integ-tests-vpc-" + random_alphanumeric(), region=region, template=template.to_json()) cfn_stacks_factory.create_stack(stack) vpc_stacks[region] = stack return vpc_stacks
def _write_file_into_efs(region, vpc_stack, efs_stack, request, key_name, cfn_stacks_factory): """Write file stack contains a mount target and a instance to write a empty file with random name into the efs.""" write_file_template = Template() write_file_template.set_version("2010-09-09") write_file_template.set_description( "Stack to write a file to the existing EFS") default_security_group_id = get_default_vpc_security_group( vpc_stack.cfn_outputs["VpcId"], region) write_file_template.add_resource( MountTarget( "MountTargetResource", FileSystemId=efs_stack.cfn_resources["FileSystemResource"], SubnetId=vpc_stack.cfn_outputs["PublicSubnetId"], SecurityGroups=[default_security_group_id], )) random_file_name = random_alphanumeric() user_data = ( """ #cloud-config package_update: true package_upgrade: true runcmd: - yum install -y nfs-utils - file_system_id_1=""" + efs_stack.cfn_resources["FileSystemResource"] + """ - efs_mount_point_1=/mnt/efs/fs1 - mkdir -p "${!efs_mount_point_1}" - mount -t nfs4 -o nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport,_netdev """ + """"${!file_system_id_1}.efs.${AWS::Region}.${AWS::URLSuffix}:/" "${!efs_mount_point_1}" - touch ${!efs_mount_point_1}/""" + random_file_name + """ - umount ${!efs_mount_point_1} - opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource InstanceToWriteEFS --region ${AWS::Region} """) write_file_template.add_resource( Instance( "InstanceToWriteEFS", CreationPolicy={"ResourceSignal": { "Timeout": "PT10M" }}, ImageId=retrieve_latest_ami(region, "alinux2"), InstanceType="c5.xlarge", SubnetId=vpc_stack.cfn_outputs["PublicSubnetId"], UserData=Base64(Sub(user_data)), KeyName=key_name, DependsOn=["MountTargetResource"], )) write_file_stack = CfnStack( name=generate_stack_name("integ-tests-efs-write-file", request.config.getoption("stackname_suffix")), region=region, template=write_file_template.to_json(), ) cfn_stacks_factory.create_stack(write_file_stack) cfn_stacks_factory.delete_stack(write_file_stack.name, region) return random_file_name
def _create_vpc_stack(request, template, region, cfn_stacks_factory): try: set_credentials(region, request.config.getoption("credential")) if request.config.getoption("vpc_stack"): logging.info("Using stack {0} in region {1}".format(request.config.getoption("vpc_stack"), region)) stack = CfnStack(name=request.config.getoption("vpc_stack"), region=region, template=template.to_json()) else: stack = CfnStack( name=generate_stack_name("integ-tests-vpc", request.config.getoption("stackname_suffix")), region=region, template=template.to_json(), ) cfn_stacks_factory.create_stack(stack) finally: unset_credentials() return stack
def _create_nlb_stack(cfn_stacks_factory, request, directory_stack, region, test_resources_dir): nlb_stack_template_path = os_lib.path.join(test_resources_dir, "NLB_SimpleAD.yaml") nlb_stack_name = generate_stack_name( "integ-tests-MultiUserInfraStackNLB", request.config.getoption("stackname_suffix")) logging.info("Creating stack %s", nlb_stack_name) # TODO: don't hardcode this ARN certificate_arn = "arn:aws:acm:us-east-1:447714826191:certificate/a17e8574-0cea-4d4c-8e79-a8ebb60f6f47" nlb_stack = None with open(nlb_stack_template_path) as nlb_stack_template: nlb_stack = CfnStack( name=nlb_stack_name, region=region, template=nlb_stack_template.read(), parameters=[ { "ParameterKey": "LDAPSCertificateARN", "ParameterValue": certificate_arn, }, { "ParameterKey": "VPCId", "ParameterValue": directory_stack.cfn_outputs["VpcId"], }, { "ParameterKey": "SubnetId1", "ParameterValue": directory_stack.cfn_outputs["PrivateSubnetIds"].split(",") [0], }, { "ParameterKey": "SubnetId2", "ParameterValue": directory_stack.cfn_outputs["PrivateSubnetIds"].split(",") [1], }, { "ParameterKey": "SimpleADPriIP", "ParameterValue": directory_stack.cfn_outputs["DirectoryDnsIpAddresses"]. split(",")[0], }, { "ParameterKey": "SimpleADSecIP", "ParameterValue": directory_stack.cfn_outputs["DirectoryDnsIpAddresses"]. split(",")[1], }, ], ) cfn_stacks_factory.create_stack(nlb_stack) logging.info("Creation of NLB stack %s complete", nlb_stack_name) return nlb_stack
def _create_network(region, template_path, parameters): file_content = extract_template(template_path) stack = CfnStack( name=generate_stack_name("integ-tests-networking", request.config.getoption("stackname_suffix")), region=region, template=file_content, parameters=parameters, ) factory.create_stack(stack) return stack
def _store_secret(secret): template = Template() template.set_version("2010-09-09") template.set_description("stack to store a secret string") template.add_resource(Secret("Secret", SecretString=secret)) stack = CfnStack( name=secret_stack_name, region=region, template=template.to_json(), ) cfn_stacks_factory.create_stack(stack) return stack.cfn_resources["Secret"]
def bastion_instance(vpc_stack, cfn_stacks_factory, request, region, key_name): """Class to create bastion instance used to execute commands on cluster in private subnet.""" bastion_stack_name = utils.generate_stack_name( "integ-tests-networking-bastion", request.config.getoption("stackname_suffix")) bastion_template = Template() bastion_template.set_version() bastion_template.set_description("Create Networking bastion stack") bastion_sg = ec2.SecurityGroup( "NetworkingTestBastionSG", GroupDescription="SecurityGroup for Bastion", SecurityGroupIngress=[ ec2.SecurityGroupRule( IpProtocol="tcp", FromPort="22", ToPort="22", CidrIp="0.0.0.0/0", ), ], VpcId=vpc_stack.cfn_outputs["VpcId"], ) instance = ec2.Instance( "NetworkingBastionInstance", InstanceType="c5.xlarge", ImageId=retrieve_latest_ami(region, "alinux2"), KeyName=key_name, SecurityGroupIds=[Ref(bastion_sg)], SubnetId=vpc_stack.cfn_outputs["PublicSubnetId"], ) bastion_template.add_resource(bastion_sg) bastion_template.add_resource(instance) bastion_template.add_output( Output("BastionIP", Value=GetAtt(instance, "PublicIp"), Description="The Bastion Public IP")) bastion_stack = CfnStack( name=bastion_stack_name, region=region, template=bastion_template.to_json(), ) cfn_stacks_factory.create_stack(bastion_stack) bastion_ip = bastion_stack.cfn_outputs.get("BastionIP") logging.info(f"Bastion_ip: {bastion_ip}") yield f"ec2-user@{bastion_ip}" if not request.config.getoption("no_delete"): cfn_stacks_factory.delete_stack(bastion_stack_name, region)
def _create_network(region, template_path, parameters): file_content = extract_template(template_path) stack = CfnStack( name="integ-tests-networking-{0}{1}{2}".format( random_alphanumeric(), "-" if request.config.getoption("stackname_suffix") else "", request.config.getoption("stackname_suffix"), ), region=region, template=file_content, parameters=parameters, ) factory.create_stack(stack) return stack
def existing_eip(region, request, cfn_stacks_factory): template = Template() template.set_version("2010-09-09") template.set_description("EIP stack for testing existing EIP") template.add_resource(EIP("ElasticIP", Domain="vpc")) stack = CfnStack( name=generate_stack_name("integ-tests-eip", request.config.getoption("stackname_suffix")), region=region, template=template.to_json(), ) cfn_stacks_factory.create_stack(stack) yield stack.cfn_resources["ElasticIP"] if not request.config.getoption("no_delete"): cfn_stacks_factory.delete_stack(stack.name, region)
def efs_stack(cfn_stacks_factory, request, region): """EFS stack contains a single efs resource.""" efs_template = Template() efs_template.set_version("2010-09-09") efs_template.set_description("EFS stack created for testing existing EFS") efs_template.add_resource(FileSystem("FileSystemResource")) stack = CfnStack( name=generate_stack_name("integ-tests-efs", request.config.getoption("stackname_suffix")), region=region, template=efs_template.to_json(), ) cfn_stacks_factory.create_stack(stack) yield stack if not request.config.getoption("no_delete"): cfn_stacks_factory.delete_stack(stack.name, region)
def placement_group_stack(cfn_stacks_factory, request, region): """Placement group stack contains a placement group.""" placement_group_template = Template() placement_group_template.set_version() placement_group_template.set_description( "Placement group stack created for testing existing placement group") placement_group_template.add_resource( PlacementGroup("PlacementGroup", Strategy="cluster")) stack = CfnStack( name=generate_stack_name("integ-tests-placement-group", request.config.getoption("stackname_suffix")), region=region, template=placement_group_template.to_json(), ) cfn_stacks_factory.create_stack(stack) yield stack cfn_stacks_factory.delete_stack(stack.name, region)
def _bastion_factory(): """Create bastion stack.""" bastion_template = Template() bastion_template.set_version() bastion_template.set_description("Create Networking bastion stack") bastion_sg = ec2.SecurityGroup( "NetworkingTestBastionSG", GroupDescription="SecurityGroup for Bastion", SecurityGroupIngress=[ ec2.SecurityGroupRule( IpProtocol="tcp", FromPort="22", ToPort="22", CidrIp="0.0.0.0/0", ), ], VpcId=vpc_stack.cfn_outputs["VpcId"], ) bastion_instance = ec2.Instance( "NetworkingBastionInstance", InstanceType="c5.xlarge", ImageId=retrieve_latest_ami(region, "alinux2"), KeyName=key_name, SecurityGroupIds=[Ref(bastion_sg)], SubnetId=vpc_stack.cfn_outputs["PublicSubnetId"], ) bastion_template.add_resource(bastion_sg) bastion_template.add_resource(bastion_instance) bastion_template.add_output( Output("BastionIP", Value=GetAtt(bastion_instance, "PublicIp"), Description="The Bastion Public IP")) bastion_stack = CfnStack( name=bastion_stack_name, region=region, template=bastion_template.to_json(), ) cfn_stacks_factory.create_stack(bastion_stack) return bastion_stack.cfn_outputs.get("BastionIP")
def create_hosted_zone(): hosted_zone_template = Template() hosted_zone_template.set_version("2010-09-09") hosted_zone_template.set_description( "Hosted zone stack created for testing existing DNS") hosted_zone_template.add_resource( HostedZone( "HostedZoneResource", Name=domain_name, VPCs=[ HostedZoneVPCs(VPCId=vpc_stack.cfn_outputs["VpcId"], VPCRegion=region) ], )) hosted_zone_stack = CfnStack( name=hosted_zone_stack_name, region=region, template=hosted_zone_template.to_json(), ) cfn_stacks_factory.create_stack(hosted_zone_stack) return hosted_zone_stack.cfn_resources[ "HostedZoneResource"], domain_name
def enable_vpc_endpoints(vpc_stack, region, cfn_stacks_factory, request): prefix = "cn." if region.startswith("cn-") else "" # Note that the endpoints service name in China is irregular. vpc_endpoints = [ VPCEndpointConfig( name="LogsEndpoint", service_name=f"com.amazonaws.{region}.logs", type=VPCEndpointConfig.EndpointType.INTERFACE, enable_private_dns=True, ), VPCEndpointConfig( name="CFNEndpoint", service_name=prefix + f"com.amazonaws.{region}.cloudformation", type=VPCEndpointConfig.EndpointType.INTERFACE, enable_private_dns=True, ), VPCEndpointConfig( name="EC2Endpoint", service_name=prefix + f"com.amazonaws.{region}.ec2", type=VPCEndpointConfig.EndpointType.INTERFACE, enable_private_dns=True, ), VPCEndpointConfig( name="S3Endpoint", service_name=f"com.amazonaws.{region}.s3", type=VPCEndpointConfig.EndpointType.GATEWAY, enable_private_dns=False, ), VPCEndpointConfig( name="DynamoEndpoint", service_name=f"com.amazonaws.{region}.dynamodb", type=VPCEndpointConfig.EndpointType.GATEWAY, enable_private_dns=False, ), ] vpc_id = vpc_stack.cfn_outputs["VpcId"] subnet_id = vpc_stack.cfn_outputs["NoInternetSubnetId"] route_table_ids = get_route_tables(subnet_id, region) troposphere_template = Template() for vpc_endpoint in vpc_endpoints: vpc_endpoint_kwargs = { "ServiceName": vpc_endpoint.service_name, "PrivateDnsEnabled": vpc_endpoint.enable_private_dns, "VpcEndpointType": str(vpc_endpoint.type), "VpcId": vpc_id, } if vpc_endpoint.type == VPCEndpointConfig.EndpointType.INTERFACE: vpc_endpoint_kwargs["SubnetIds"] = [subnet_id] elif vpc_endpoint.type == VPCEndpointConfig.EndpointType.GATEWAY: vpc_endpoint_kwargs["RouteTableIds"] = route_table_ids troposphere_template.add_resource( VPCEndpoint( vpc_endpoint.name, **vpc_endpoint_kwargs, )) vpc_endpoints_stack = CfnStack( name=generate_stack_name("integ-tests-vpc-endpoints", request.config.getoption("stackname_suffix")), region=region, template=troposphere_template.to_json(), ) cfn_stacks_factory.create_stack(vpc_endpoints_stack) yield if not request.config.getoption("no_delete"): cfn_stacks_factory.delete_stack(vpc_endpoints_stack.name, region)
def _custom_resource(image_id): nonlocal stack_name_post_test # custom resource stack custom_resource_stack_name = generate_stack_name( "-".join([image_id, "custom", "resource"]), request.config.getoption("stackname_suffix")) stack_name_post_test = custom_resource_stack_name custom_resource_template = Template() custom_resource_template.set_version() custom_resource_template.set_description( "Create build image custom resource stack") # Create a instance role managed_policy_arns = [ "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore", "arn:aws:iam::aws:policy/EC2InstanceProfileForImageBuilder", ] policy_document = iam.Policy( PolicyName="myInstanceRoleInlinePolicy", PolicyDocument={ "Statement": [{ "Effect": "Allow", "Action": [ "ec2:CreateTags", "ec2:ModifyImageAttribute", "s3:GetObject", "cloudformation:ListStacks", ], "Resource": "*", }] }, ) role_name = "".join(["dummyInstanceRole", generate_random_string()]) instance_role = iam.Role( "CustomInstanceRole", AssumeRolePolicyDocument={ "Statement": [{ "Effect": "Allow", "Principal": { "Service": ["ec2.amazonaws.com"] }, "Action": ["sts:AssumeRole"] }] }, Description="custom instance role for build image test.", ManagedPolicyArns=managed_policy_arns, Path="/parallelcluster/", Policies=[policy_document], RoleName=role_name, ) custom_resource_template.add_resource(instance_role) custom_resource_stack = CfnStack( name=custom_resource_stack_name, region=region, template=custom_resource_template.to_json(), capabilities=["CAPABILITY_NAMED_IAM"], ) cfn_stacks_factory.create_stack(custom_resource_stack) instance_role_arn = boto3.client("iam").get_role( RoleName=role_name).get("Role").get("Arn") logging.info("Custom instance role arn %s", instance_role_arn) return instance_role_arn
def _create_directory_stack( cfn_stacks_factory, request, directory_type, test_resources_dir, ad_admin_password, ad_user_password, bucket_name, region, vpc_stack, ): directory_stack_name = generate_stack_name( f"integ-tests-MultiUserInfraStack{directory_type}", request.config.getoption("stackname_suffix")) if directory_type not in ("MicrosoftAD", "SimpleAD"): raise Exception(f"Unknown directory type: {directory_type}") upload_custom_resources(test_resources_dir, bucket_name) directory_stack_template_path = os_lib.path.join(test_resources_dir, "ad_stack.yaml") account_id = (boto3.client( "sts", region_name=region, endpoint_url=get_sts_endpoint( region)).get_caller_identity().get("Account")) config_args = { "region": region, "account": account_id, "admin_node_ami_id": retrieve_latest_ami(region, "alinux2"), "admin_node_instance_type": "c5.large", "admin_node_key_name": request.config.getoption("key_name"), "ad_admin_password": ad_admin_password, "ad_user_password": ad_user_password, "ad_domain_name": f"{directory_type.lower()}.multiuser.pcluster", "default_ec2_domain": "ec2.internal" if region == "us-east-1" else f"{region}.compute.internal", "ad_admin_user": "******" if directory_type == "SimpleAD" else "Admin", "num_users_to_create": 100, "bucket_name": bucket_name, "directory_type": directory_type, } logging.info("Creating stack %s", directory_stack_name) with open( render_jinja_template(directory_stack_template_path, **config_args)) as directory_stack_template: params = [ { "ParameterKey": "Vpc", "ParameterValue": vpc_stack.cfn_outputs["VpcId"] }, { "ParameterKey": "PrivateSubnetOne", "ParameterValue": vpc_stack.cfn_outputs["PrivateSubnetId"] }, { "ParameterKey": "PrivateSubnetTwo", "ParameterValue": vpc_stack.cfn_outputs["PrivateAdditionalCidrSubnetId"], }, { "ParameterKey": "PublicSubnetOne", "ParameterValue": vpc_stack.cfn_outputs["PublicSubnetId"] }, ] directory_stack = CfnStack( name=directory_stack_name, region=region, template=directory_stack_template.read(), parameters=params, capabilities=["CAPABILITY_IAM", "CAPABILITY_NAMED_IAM"], ) cfn_stacks_factory.create_stack(directory_stack) logging.info("Creation of stack %s complete", directory_stack_name) return directory_stack