def __init__(self, stack, paco_ctx): resource = stack.resource super().__init__(stack, paco_ctx) self.set_aws_name('DBClusterParameterGroup', self.resource_group_name, resource.name) self.init_template('DB Cluster Parameter Group') # Resources cfn_export_dict = { 'Family': resource.family, 'Parameters': {} } if resource.description != None: cfn_export_dict['Description'] = resource.description else: cfn_export_dict['Description'] = troposphere.Ref('AWS::StackName') for key, value in resource.parameters.items(): cfn_export_dict['Parameters'][key] = value dbparametergroup_resource = troposphere.rds.DBClusterParameterGroup.from_dict( 'DBClusterParameterGroup', cfn_export_dict ) self.template.add_resource(dbparametergroup_resource) # Outputs self.create_output( title='DBClusterParameterGroupName', description='DB Cluster Parameter Group Name', value=troposphere.Ref(dbparametergroup_resource), ref=[self.resource.paco_ref_parts, self.resource.paco_ref_parts + ".name"] )
def get_or_create_resource(self, path, api, template): """Returns the ID of the Resource ``path`` in ``api``. If the resorce doesn't exits, create a new one and add it to ``template``.""" # Add leading slash if path and path[0] != '/': path = '/{}'.format(path) # Remove trailing slash if path and path[-1] == '/': path = path[:-1] # Make / the root path if not path: path = '/' # Return API root resource if if path == '/': return troposphere.GetAtt(api, 'RootResourceId') if path in self._resources: return self._resources[path] parent_path, path_part = path.rsplit('/', 1) parent_id = self.get_or_create_resource(parent_path, api, template) resource = Resource(utils.valid_cloudformation_name( self.name, 'Resource', *path.split('/')), ParentId=parent_id, PathPart=path_part, RestApiId=troposphere.Ref(api)) template.add_resource(resource) self._resources[path] = troposphere.Ref(resource) return self._resources[path]
def queue_policy(self): return ts.sqs.QueuePolicy( self._get_logical_id('QueuePolicy'), Queues=[ts.Ref(self.queue)], PolicyDocument={ 'Version': '2012-10-17', 'Statement': [{ 'Sid': 'allow-sns-notifications', 'Effect': 'Allow', 'Principal': { 'AWS': '*', }, 'Action': ['sqs:SendMessage'], 'Resource': '*', 'Condition': { # todo: allow all topics? # 'ArnEquals': {'aws:SourceArn': self.config['SourceTopics']} 'ArnLike': { 'aws:SourceArn': ts.Join(':', [ 'arn:aws:sns', ts.Ref('AWS::Region'), ts.Ref('AWS::AccountId'), '*', ]) }, }, }], }, )
def __init__(self, stack, paco_ctx): super().__init__(stack, paco_ctx) self.set_aws_name('Example', self.resource_group_name, self.resource.name) # Troposphere Template Initialization self.init_template('Example Template') if not self.resource.is_enabled(): return # Parameters example_param = self.create_cfn_parameter( name='ExampleParameterName', param_type='String', description='Example parameter.', value=self.resource.example_variable, ) # Resource example_dict = {'some_property': troposphere.Ref(example_param)} example_res = troposphere.resource.Example.from_dict( 'ExampleResource', example_dict) self.template.add_resource(example_res) # Outputs self.create_output(title='ExampleResourceId', description="Example resource Id.", value=troposphere.Ref(example_res), ref=self.resource.paco_ref_parts + ".id")
def create_group(self, sg_group_id, sg_name, sg_config, template, vpc_id_param): # GroupName group_name = self.create_resource_name_join( [ self.env_ctx.netenv_id, self.env_ctx.env_id, sg_group_id, sg_name ], separator='-', camel_case=True, filter_id='SecurityGroup.GroupName') # GroupDescription if sg_config.group_description != None and sg_config.group_description != '': group_description = sg_config.group_description else: group_description = "Paco generated Security Group" # legacy_flag: aim_name_2019_11_28 - Use AIM name if self.paco_ctx.legacy_flag('aim_name_2019_11_28') == True: group_description = "AIM generated Security Group" # Security Group group_logical_id = self.create_cfn_logical_id(sg_name) group_res = troposphere.ec2.SecurityGroup( title=group_logical_id, template=template, GroupName=group_name, GroupDescription=group_description, VpcId=troposphere.Ref(vpc_id_param), Tags=troposphere.codebuild.Tags(Name=group_name)) # Output group_config_ref = '.'.join([self.config_ref, sg_name]) self.create_output(title=group_logical_id + 'Id', value=troposphere.Ref(group_res), ref=group_config_ref + '.id')
def create_lambda_invoke_properties(self, stage, action, info): function_arn_param = self.create_cfn_parameter( param_type='String', name=self.create_cfn_logical_id('Lambda' + stage.name + action.name), description='The name of the Lambda for stage {} and action {}'. format(stage.name, action.name), value=action.target_lambda + '.arn', ) user_parameters_param = self.create_cfn_parameter( param_type='String', name=self.create_cfn_logical_id('UserParameters' + stage.name + action.name), description='The UserParameters for stage {} and action {}'.format( stage.name, action.name), value=action.user_parameters, ) lambda_function_name = troposphere.Join('', [ troposphere.Select( 6, troposphere.Split(':', troposphere.Ref(function_arn_param))) ]) return { 'Configuration': { 'FunctionName': lambda_function_name, 'UserParameters': troposphere.Ref(user_parameters_param), }, }
def register_resources_template(self, template): """Register one ``EventSourceMapping`` into the resources template. Note: We preprend a 30s Sleep before the creation of this resource because the IAM role of the lambda is not propagated fast enough uppon creation, and CloudFormation checks if the referenced lambda has permission to consume this stream on creation time. Because the ``Lambda`` and the ``EventSourceMapping`` are created in the same stack we need to introduce this as palliative measure, sorry! """ sleep_lambda = 'lambda:contrib_helpers:sleep:current' sleep = Sleep.create_with( utils.valid_cloudformation_name(self.name, "Sleep"), DependsOn=[self.project.reference(sleep_lambda)], lambda_arn=troposphere.Ref(self.project.reference(sleep_lambda)), Time=30) template.add_resource(sleep) template.add_resource( awslambda.EventSourceMapping( self.in_project_cf_name, DependsOn=[sleep.name, self.get_function_name()], BatchSize=self.get_batch_size(), Enabled=self.get_enabled(), EventSourceArn=self.settings.get('stream'), FunctionName=troposphere.Ref(self.get_function_name()), StartingPosition=self.get_starting_position()))
def register_type_project_template(cls, project, template): """Registers into the project stack a S3 bucket where all lambdas code will be stored, as well as an output so any subsequent template can have a reference to this resource.""" bucket_name = troposphere.Join( "-", [ utils.validate_code_bucket(project.settings['code-bucket']), troposphere.Ref(troposphere.AWS_REGION), troposphere.Ref('Stage') ] ) code_bucket = s3.Bucket( "CodeBucket", BucketName=bucket_name, AccessControl=s3.Private, VersioningConfiguration=s3.VersioningConfiguration( Status='Enabled' ) ) template.add_resource(code_bucket) template.add_output([ troposphere.Output( "CodeBucket", Description="CodeBucket name", Value=bucket_name, ) ])
def register_resources_template(self, template): targets, target_lambdas = [], [] for name, target in six.iteritems(self.settings.get('targets', {})): target_lambdas.append(target['lambda']) targets.append( events.Target( Arn=self.get_destination_arn(target['lambda']), Id=self.get_function_name(target['lambda']), Input=target.get('input', ''), InputPath=target.get('input_path', ''), )) rule = events.Rule(utils.valid_cloudformation_name(self.name, "Rule"), Description=self.settings.get('description', ''), EventPattern=self.settings.get( 'event_pattern', troposphere.Ref(troposphere.AWS_NO_VALUE)), ScheduleExpression=self.settings.get( 'schedule_expression', troposphere.Ref(troposphere.AWS_NO_VALUE)), State=self.get_enabled(), Targets=targets) template.add_resource(rule) for lambda_ in target_lambdas: template.add_resource( troposphere.awslambda.Permission( utils.valid_cloudformation_name(self.name, 'rule', 'permission'), Action="lambda:InvokeFunction", FunctionName=self.get_destination_arn(lambda_), Principal="events.amazonaws.com", SourceArn=troposphere.GetAtt(rule, 'Arn'), ))
def ec2_user_data(self): return ts.Base64( ts.Join( '', [ # -x print commands as they're executed # -e exit on error '#!/bin/bash -xe', '\n', # todo: figure out what these commands do 'yum install -y aws-cfn-bootstrap', '\n', '/opt/aws/bin/cfn-init -v ', ' --stack ', ts.Ref('AWS::StackName'), ' --resource ', self.launch_config_logical_id, ' --region ', ts.Ref('AWS::Region'), '\n', '/opt/aws/bin/cfn-signal -e $? ', ' --stack ', ts.Ref('AWS::StackName'), ' --resource ', self.auto_scaling_group_logical_id, ' --region ', ts.Ref('AWS::Region'), '\n', ]))
def __init__(self, stack, paco_ctx, network): efs_config = stack.resource super().__init__(stack, paco_ctx) self.set_aws_name('EFS', self.resource_group_name, self.resource.name) self.init_template('Elastic Filesystem') if not efs_config.is_enabled(): return # Parameters sg_list_param = self.create_cfn_ref_list_param( param_type='List<AWS::EC2::SecurityGroup::Id>', name='TargetSecurityGroupList', description='EFS mount target security group list.', value=efs_config.security_groups, ref_attribute='id', ) encrypted_param = self.create_cfn_parameter( name='EncryptedAtRest', param_type='String', description= 'Boolean indicating whether the data will be encrypted at rest.', value=efs_config.encrypted, ) # Elastic File System if efs_config.enable_automatic_backups == True: efs_backup_policy = 'ENABLED' else: efs_backup_policy = 'DISABLED' efs_res = troposphere.efs.FileSystem( title='EFS', template=self.template, Encrypted=troposphere.Ref(encrypted_param), BackupPolicy=troposphere.efs.BackupPolicy( Status=efs_backup_policy)) self.create_output(title=efs_res.title + 'Id', description="Elastic File System ID.", value=troposphere.Ref(efs_res), ref=efs_config.paco_ref_parts + ".id") # Mount Targets for az_idx in range(1, network.availability_zones + 1): subnet_id_ref = network.vpc.segments[ efs_config.segment].paco_ref_parts + '.az{}.subnet_id'.format( az_idx) subnet_param = self.create_cfn_parameter( name='SubnetIdAZ{}'.format(az_idx), param_type='String', description='The SubnetId for AZ{}.'.format(az_idx), value='paco.ref ' + subnet_id_ref, ) efs_mount_logical_id = self.create_cfn_logical_id( 'EFSMountTargetAZ{}'.format(az_idx)) troposphere.efs.MountTarget( title=efs_mount_logical_id, template=self.template, FileSystemId=troposphere.Ref(efs_res), SecurityGroups=troposphere.Ref(sg_list_param), SubnetId=troposphere.Ref(subnet_param))
def add_apigateway_resource(self, resource): resource_logical_id = 'ApiGatewayResource' + self.create_cfn_logical_id(resource.name + md5sum(str_data=resource.paco_ref_parts)) cfn_export_dict = resource.cfn_export_dict parent_resource = resource.__parent__.__parent__ # root resource if schemas.IApiGatewayRestApi.providedBy(parent_resource): cfn_export_dict["ParentId"] = troposphere.GetAtt(self.restapi_resource, "RootResourceId") # child resource else: cfn_export_dict["ParentId"] = troposphere.Ref(parent_resource.resource) cfn_export_dict["RestApiId"] = troposphere.Ref(self.restapi_resource) resource_resource = troposphere.apigateway.Resource.from_dict(resource_logical_id, cfn_export_dict) resource.resource = resource_resource self.template.add_resource(resource_resource) self.create_output( title=self.create_cfn_logical_id(f'ApiGatewayRestApiResource{resource.name}' + md5sum(str_data=resource.paco_ref_parts)), value=troposphere.Ref(resource_resource), ref=resource.paco_ref_parts + '.id', ) # Add an OPTIONS method if CORS is enabled if resource.enable_cors == True: options_config = { 'http_method': 'OPTIONS', 'integration': { 'integration_type': 'MOCK', 'integration_http_method': 'OPTIONS', 'pass_through_behavior': 'WHEN_NO_MATCH', 'request_templates': {'application/json': '{"statusCode": 200}'}, 'integration_responses': [{ 'status_code': '200', 'response_parameters': { 'method.response.header.Access-Control-Allow-Headers': "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'", 'method.response.header.Access-Control-Allow-Methods': "'POST,OPTIONS'", 'method.response.header.Access-Control-Allow-Origin': "'*'", }, 'response_templates': {'application/json': ''}, },], }, 'method_responses': [{ 'status_code': '200', 'response_models': [{ 'content_type': 'application/json', 'model_name': 'emptyjson', }], 'response_parameters': { 'method.response.header.Access-Control-Allow-Headers': False, 'method.response.header.Access-Control-Allow-Methods': False, 'method.response.header.Access-Control-Allow-Origin': False, }, }], } options_config['resource_name'] = resource.nested_name method_name = f'{resource.nested_name}PacoCORS' options_method = ApiGatewayMethod(method_name, self.apigatewayrestapi.methods) apply_attributes_from_config(options_method, options_config) self.apigatewayrestapi.methods[method_name] = options_method return resource_resource
def __init__( self, stack, paco_ctx, sns_topic_list ): super().__init__( stack, paco_ctx, iam_capabilities=["CAPABILITY_NAMED_IAM"], ) account_ctx = stack.account_ctx aws_region = stack.aws_region self.set_aws_name('LambdaSNSSubs', self.resource_group_name, self.resource_name) awslambda = self.awslambda = self.stack.resource self.init_template('Lambda SNS Subscriptions') # if not enabled finish with only empty placeholder if not self.awslambda.is_enabled(): return # Permissions # SNS Topic Lambda permissions and subscription lambda_arn_param = self.create_cfn_parameter( name='LambdaFunctionArn', param_type='String', description='An SNS Topic ARN to grant permission to.', value=self.awslambda.paco_ref + '.arn' ) idx = 1 for sns_topic in sns_topic_list: # SNS Topic Arn parameters if is_ref(sns_topic): sns_topic_value = sns_topic + '.arn' sns_topic_obj = get_model_obj_from_ref(sns_topic, self.paco_ctx.project) region_name = sns_topic_obj.region_name else: sns_topic_value = sns_topic region_name = sns_topic.split(':')[3] param_name = 'SNSTopicArn%d' % idx self.create_cfn_parameter( name=param_name, param_type='String', description='An SNS Topic ARN to grant permission to.', value=sns_topic_value ) # SNS Topic subscription troposphere.sns.SubscriptionResource( title=param_name + 'Subscription', template=self.template, Endpoint=troposphere.Ref(lambda_arn_param), Protocol='lambda', TopicArn=troposphere.Ref(param_name), Region=region_name ) idx += 1
def __init__(self, paco_ctx, account_ctx, aws_region, stack_group, stack_tags, zone_config, config_ref): super().__init__(paco_ctx, account_ctx, aws_region, enabled=zone_config.is_enabled(), config_ref=config_ref, iam_capabilities=["CAPABILITY_NAMED_IAM"], stack_group=stack_group, stack_tags=stack_tags) self.set_aws_name('HostedZone', zone_config.name) self.init_template('Route53 Hosted Zone: ' + zone_config.domain_name) self.paco_ctx.log_action_col("Init", "Route53", "Hosted Zone", "{}".format(zone_config.domain_name)) if zone_config.external_resource != None and zone_config.external_resource.is_enabled( ): hosted_zone_id_output_value = zone_config.external_resource.hosted_zone_id nameservers_output_value = ','.join( zone_config.external_resource.nameservers) else: hosted_zone_res = troposphere.route53.HostedZone( title='HostedZone', template=self.template, Name=zone_config.domain_name) hosted_zone_id_output_value = troposphere.Ref(hosted_zone_res) nameservers_output_value = troposphere.Join( ',', troposphere.GetAtt(hosted_zone_res, 'NameServers')) self.create_output(title='HostedZoneId', value=hosted_zone_id_output_value, ref=config_ref + '.id') self.create_output(title='HostedZoneNameServers', value=nameservers_output_value, ref=config_ref + '.name_servers') if len(zone_config.record_sets) > 0: record_set_list = [] for record_set_config in zone_config.record_sets: record_set_res = troposphere.route53.RecordSet( Name=record_set_config.record_name, Type=record_set_config.type, TTL=record_set_config.ttl, ResourceRecords=record_set_config.resource_records) record_set_list.append(record_set_res) group_res = troposphere.route53.RecordSetGroup( title='RecordSetGroup', template=self.template, HostedZoneId=troposphere.Ref(hosted_zone_res), RecordSets=record_set_list) group_res.DependsOn = hosted_zone_res self.set_template()
def __init__(self, stack, paco_ctx, awslambda): super().__init__(stack, paco_ctx) self.set_aws_name('ApiGatewayLamdaPermission', self.resource_group_name, self.resource_name) self.init_template('Cross-account Api Gateway Lambda Permission') apigateway = self.resource api_gateway_id_param = self.create_cfn_parameter( name=self.create_cfn_logical_id('ApiGatewayRestApiId'), param_type='String', description='API Gateway Rest API Id', value=apigateway.paco_ref + '.id', ) lambda_arn_param = self.create_cfn_parameter( name=self.create_cfn_logical_id('LambdaArn'), param_type='String', description='Lambda Arn', value=awslambda.paco_ref + '.arn', ) # Lambda Permission for cross-account API Gateway invocation for method in apigateway.methods.values(): if method.integration != None and method.integration.integration_lambda != None: if awslambda.paco_ref == method.integration.integration_lambda: if apigateway.get_account().name != awslambda.get_account().name: # Grant Cross-Account API Gateway permission path_part = '' if method.resource_name: name_parts = method.resource_name.split('.') resource = method.get_resource() if len(name_parts) > 1: # child resource last_resource = resource while schemas.IApiGatewayResource.providedBy(resource): last_resource = resource resource = resource.__parent__.__parent__ path_part = last_resource.path_part + '/*' # add /* to match all child resource else: # parent resource path_part = resource.path_part lambda_permission_resource = troposphere.awslambda.Permission( title='ApiGatewayRestApiMethod' + md5sum(str_data=method.paco_ref), Action="lambda:InvokeFunction", FunctionName=troposphere.Ref(lambda_arn_param), Principal='apigateway.amazonaws.com', SourceArn=troposphere.Join('', [ "arn:aws:execute-api:", awslambda.region_name, # lambda region ":", apigateway.get_account().account_id, # account id ":", troposphere.Ref(api_gateway_id_param), f"/*/{method.http_method}/{path_part}", ]) ) self.template.add_resource(lambda_permission_resource)
def prepare_s3bucket_artifact(self, is_zip=False): """ Add a Hook which will prepare the Lambda Code artifact and upload to an S3 Bucket if it doesn't already exist. Add Parameters for CodeS3Bucket and CodeS3Key. The Parameter values are placeholder values that will be updated by the hook. """ ignore_changes = True # always create an artifact on CREATE stack_hooks = StackHooks() stack_hooks.add( name='PrepLambdaCodeArtifactToS3Bucket', stack_action=['create',], stack_timing='pre', hook_method=self.prepare_s3bucket_artifact_hook, cache_method=self.prepare_s3bucket_artifact_cache, hook_arg=is_zip, ) self.stack.add_hooks(stack_hooks) # only UPDATE an artifact if --auto-publish-code is true if self.paco_ctx.auto_publish_code == True: ignore_changes = False stack_hooks = StackHooks() stack_hooks.add( name='PrepLambdaCodeArtifactToS3Bucket', stack_action=['update'], stack_timing='pre', hook_method=self.prepare_s3bucket_artifact_hook, cache_method=self.prepare_s3bucket_artifact_cache, hook_arg=is_zip, ) self.stack.add_hooks(stack_hooks) self.s3bucket_param = self.create_cfn_parameter( name='CodeS3Bucket', description="S3 Bucket for the Lambda Code artifact", param_type='String', value='', ignore_changes=ignore_changes, ) self.s3key_param = self.create_cfn_parameter( name='CodeS3Key', description="S3 Key for the Lambda Code artifact", param_type='String', value='', ignore_changes=ignore_changes, ) cfn_s3_code = { 'S3Bucket': troposphere.Ref(self.s3bucket_param), 'S3Key': troposphere.Ref(self.s3key_param), } return cfn_s3_code
def ec2_launch_config(self): return ts.autoscaling.LaunchConfiguration( self.launch_config_logical_id, KeyName=self.key_name, ImageId=self.ami, AssociatePublicIpAddress=True, SecurityGroups=[ts.Ref(self.security_group)], IamInstanceProfile=ts.Ref(self.ec2_instance_profile), InstanceType=self.ec2_instance_type, Metadata=self.ec2_metadata, UserData=self.ec2_user_data, )
def ecs_service(self): return ts.ecs.Service( self._get_logical_id('EcsService'), Cluster=ts.Ref(self.ecs_cluster), DesiredCount=2, TaskDefinition=ts.Ref(self.ecs_task_def), # no limits on the order of stopping / starting tasks # data remains in the queue and workers are gracefully shut down DeploymentConfiguration=ts.ecs.DeploymentConfiguration( MaximumPercent=200, MinimumHealthyPercent=0, ), )
def listener(self): return ts.elasticloadbalancingv2.Listener( self._get_logical_id('Listener'), Protocol='HTTP', Port=80, LoadBalancerArn=ts.Ref(self.elb), DefaultActions=[ ts.elasticloadbalancingv2.Action( Type='forward', TargetGroupArn=ts.Ref(self.target_group), ) ], )
def get_integration_uri(self, resource): integration_type = self._get_integration_type(resource) if integration_type == LAMBDA_INTEGRATION: return troposphere.Join('', [ 'arn:aws:apigateway:', troposphere.Ref(troposphere.AWS_REGION), ':lambda:path/2015-03-31/functions/', troposphere.Ref( self.get_function_name(resource)), '/invocations' ]) elif integration_type == HTTP_INTEGRATION: return resource['integration']['uri'] elif integration_type == MOCK_INTEGRATION: return troposphere.Ref(troposphere.AWS_NO_VALUE)
def __init__(self, stack, paco_ctx, role, s3_bucket_name): super().__init__(stack, paco_ctx) self.set_aws_name('Config') self.init_template('Config') config = stack.resource # Parameters role_arn_param = self.create_cfn_parameter( param_type='String', name='AWSConfigRoleArn', description='IAM Role assumed by AWS Config', value=role.get_arn()) s3_bucket_name_param = self.create_cfn_parameter( param_type='String', name='S3BucketName', description='S3 Bucket', value=s3_bucket_name, ) # ConfigurationRecorder resource include_global = False if config.global_resources_region == stack.aws_region: include_global = True config_recorder_dict = { 'RecordingGroup': { 'AllSupported': True, 'IncludeGlobalResourceTypes': include_global, }, 'RoleARN': troposphere.Ref(role_arn_param), } config_recorder_resource = troposphere.config.ConfigurationRecorder.from_dict( 'ConfigurationRecorder', config_recorder_dict) self.template.add_resource(config_recorder_resource) # DeliveryChannel resource delivery_channel_dict = { 'ConfigSnapshotDeliveryProperties': { 'DeliveryFrequency': config.delivery_frequency }, 'S3BucketName': troposphere.Ref(s3_bucket_name_param), } # ToDo: SnsTopic for Config # SnsTopicARN: String delivery_channel_resource = troposphere.config.DeliveryChannel.from_dict( 'DeliveryChannel', delivery_channel_dict, ) #delivery_channel_resource.DependsOn = config_recorder_resource self.template.add_resource(delivery_channel_resource)
def create_s3deploy_properties(self, stage, action, info): base_name = stage.name + action.name s3_deploy_bucket_name_param = self.create_cfn_parameter( param_type='String', name=self.create_cfn_logical_id('S3DeployBucketName' + base_name), description='The name of the S3 bucket to deploy to.', value=action.bucket + '.name', ) s3_deploy_extract_param = self.create_cfn_parameter( param_type='String', name=self.create_cfn_logical_id('S3DeployExtract' + base_name), description= 'Boolean indicating whether the deployment artifact will be extracted.', value=action.extract, ) s3_deploy_object_key_param = 'AWS::NoValue' if action.object_key != None: s3_deploy_object_key_param = self.create_cfn_parameter( param_type='String', name=self.create_cfn_logical_id('S3DeployObjectKey' + base_name), description= 'S3 object key to store the deployment artifact as.', value=action.object_key, ) bucket = get_model_obj_from_ref(action.bucket, self.paco_ctx.project) account = get_model_obj_from_ref(bucket.account, self.paco_ctx.project) input_artifacts = [] for artifact in action.input_artifacts: stage_name, action_name = artifact.split('.') source_action = self.pipeline.stages[stage_name][action_name] input_name = '{}Artifact{}{}'.format( ACTION_MAP[source_action.type]['Name'], stage_name, action_name, ) input_artifacts.append( troposphere.codepipeline.InputArtifacts(Name=input_name)) return { 'Configuration': { 'BucketName': troposphere.Ref(s3_deploy_bucket_name_param), 'Extract': troposphere.Ref(s3_deploy_extract_param), 'ObjectKey': troposphere.Ref(s3_deploy_object_key_param), }, 'InputArtifacts': input_artifacts, 'RoleArn': troposphere.Ref(self.s3deploy_buckets[account.name]), #'RunOrder': troposphere.If('ManualApprovalIsEnabled', 2, 1) }
def __init__(self, stack, paco_ctx): pinpoint_app = stack.resource super().__init__(stack, paco_ctx) self.set_aws_name('PinpointApp', self.resource_group_name, self.resource.name) self.init_template('Pinpoint Application') if not pinpoint_app.is_enabled(): return # Pinpoint Application pinpoint_app_logical_id = 'PinpointApplication' pinpointapp_resource = troposphere.pinpoint.App( pinpoint_app_logical_id, Name=pinpoint_app.title, ) self.template.add_resource(pinpointapp_resource) if pinpoint_app.sms_channel: cfn_export_dict = pinpoint_app.sms_channel.cfn_export_dict cfn_export_dict['ApplicationId'] = troposphere.Ref( pinpoint_app_logical_id) sms_channel_resource = troposphere.pinpoint.SMSChannel.from_dict( 'SMSChannel', cfn_export_dict, ) self.template.add_resource(sms_channel_resource) if pinpoint_app.email_channel: cfn_export_dict = pinpoint_app.email_channel.cfn_export_dict cfn_export_dict['ApplicationId'] = troposphere.Ref( pinpoint_app_logical_id) cfn_export_dict[ 'Identity'] = f'arn:aws:ses:{self.aws_region}:{self.account_ctx.id}:identity/{pinpoint_app.email_channel.from_address}' email_channel_resource = troposphere.pinpoint.EmailChannel.from_dict( 'EmailChannel', cfn_export_dict, ) self.template.add_resource(email_channel_resource) # Output self.create_output(title=pinpointapp_resource.title + 'Id', description="Pinpoint Application Id", value=troposphere.Ref(pinpointapp_resource), ref=pinpoint_app.paco_ref_parts + ".id") self.create_output(title=pinpointapp_resource.title + 'Arn', description="Pinpoint Application Arn", value=troposphere.GetAtt(pinpointapp_resource, "Arn"), ref=pinpoint_app.paco_ref_parts + ".arn")
def register_resources_template(self, template): extra = defaultdict(list) for notification_id, notification in six.iteritems( self._notifications): notification.register_destination_publish_permission(template) extra[notification.api_property].append( NotificationConfiguration( Id=troposphere.Join('-', ['gordon', notification.id]), DestinationArn=notification.get_destination_arn(), Events=[e for e, _, _ in notification.events], KeyFilters=[ KeyFilter(Name=name, Value=value) for name, value in notification.filters ])) bucket_notification_configuration_lambda = 'lambda:contrib_s3:bucket_notification_configuration:current' template.add_resource( S3BucketNotificationConfiguration.create_with( utils.valid_cloudformation_name(self.name), DependsOn=[ self.project.reference( bucket_notification_configuration_lambda) ], lambda_arn=troposphere.Ref( self.project.reference( bucket_notification_configuration_lambda)), Bucket=self.get_bucket_name(), **dict([[k, v] for k, v in six.iteritems(extra) if v])))
def get_destination_arn(self): destination = self.settings['topic'] region = troposphere.Ref(troposphere.AWS_REGION) if isinstance(destination, six.string_types): if destination.startswith('arn:aws:'): return destination account = troposphere.Ref(troposphere.AWS_ACCOUNT_ID) elif isinstance(destination, dict): account = destination['account_id'] destination = destination['name'] else: return destination return troposphere.Join(":", ["arn:aws:sns", region, account, destination])
def get_destination_url(self): destination = self.settings['queue'] region = troposphere.Ref(troposphere.AWS_REGION) if isinstance(destination, six.string_types): account = troposphere.Ref(troposphere.AWS_ACCOUNT_ID) elif isinstance(destination, dict): account = destination['account_id'] destination = destination['name'] else: return destination return troposphere.Join("", [ "https://sqs.", region, ".amazonaws.com/", account, "/", destination ])
def init_custompolicy_permission(self, permission_config, assume_role_res): for managed_policy in permission_config.managed_policies: if 'ManagedPolicyArns' not in assume_role_res.properties.keys(): assume_role_res.properties['ManagedPolicyArns'] = [] assume_role_res.properties['ManagedPolicyArns'].append('arn:aws:iam::aws:policy/' + managed_policy) for policy in permission_config.policies: policy_statements = [] for policy_statement in policy.statement: statement_dict = { 'Effect': policy_statement.effect, 'Action': [ Action(*action.split(':')) for action in policy_statement.action ], } # Resource statement_dict['Resource'] = policy_statement.resource policy_statements.append( Statement(**statement_dict) ) # Make the policy managed_policy_res = troposphere.iam.ManagedPolicy( title=self.create_cfn_logical_id_join( str_list=["CustomPolicy", policy.name], camel_case=True ), PolicyDocument=PolicyDocument( Version="2012-10-17", Statement=policy_statements ), Roles=[ troposphere.Ref(assume_role_res) ] ) self.template.add_resource(managed_policy_res)
def __init__(self, stack, paco_ctx): ebs_config = stack.resource super().__init__(stack, paco_ctx) self.set_aws_name('EBS', self.resource_group_name, self.resource.name) # Troposphere Template Initialization self.init_template('Elastic Block Store Volume') # EBS Resource ebs_dict = { 'VolumeType': ebs_config.volume_type, 'AvailabilityZone': vocabulary.aws_regions[self.aws_region]['zones'][ebs_config.availability_zone-1] } # Snapshot overrides Size if ebs_config.snapshot_id != None and ebs_config.snapshot_id != '': ebs_dict['SnapshotId'] = ebs_config.snapshot_id else: ebs_dict['Size'] = ebs_config.size_gib ebs_res = troposphere.ec2.Volume.from_dict( 'EBS', ebs_dict ) self.template.add_resource(ebs_res) # Outputs self.create_output( title='EBSVolumeId', description="The EBS Volume Id.", value=troposphere.Ref(ebs_res), ref=ebs_config.paco_ref_parts + ".id", )
def create_notification_params(self, alarm): "Create a Parameter for each SNS Topic an alarm should notify. Return a list of Refs to those Params." notification_paco_refs = [] for group in alarm.notification_groups: if not self.notification_region: region = alarm.region_name else: region = self.notification_region notification_paco_refs.append( self.paco_ctx.project['resource']['snstopics'][region][group].paco_ref + '.arn' ) notification_cfn_refs = [] for notification_paco_ref in notification_paco_refs: # Create parameter param_name = 'Notification{}'.format(utils.md5sum(str_data=notification_paco_ref)) if param_name in self.notification_param_map.keys(): notification_param = self.notification_param_map[param_name] else: notification_param = self.create_cfn_parameter( param_type='String', name=param_name, description='SNS Topic to notify', value=notification_paco_ref, min_length=1, # prevent borked empty values from breaking notification ) self.notification_param_map[param_name] = notification_param notification_cfn_refs.append(troposphere.Ref(notification_param)) return notification_cfn_refs
def set_alarm_actions_to_cfn_export(self, alarm, cfn_export_dict): "Sets the AlarmActions, OKActions and InsufficientDataActions for a Troposphere dict" alarm_action_list = [] notification_groups = self.paco_ctx.project['resource'][ 'notificationgroups'][alarm.region_name] for alarm_action in alarm.get_alarm_actions_paco_refs( notification_groups): # Create parameter param_name = 'AlarmAction{}'.format( utils.md5sum(str_data=alarm_action)) if param_name in self.alarm_action_param_map.keys(): alarm_action_param = self.alarm_action_param_map[param_name] else: alarm_action_param = self.create_cfn_parameter( param_type='String', name=param_name, description='SNSTopic for Alarm to notify.', value=alarm_action) self.alarm_action_param_map[param_name] = alarm_action_param alarm_action_list.append(troposphere.Ref(alarm_action_param)) cfn_export_dict['AlarmActions'] = alarm_action_list if getattr(alarm, 'enable_ok_actions', False): cfn_export_dict['OKActions'] = alarm_action_list if getattr(alarm, 'enable_insufficient_data_actions', False): cfn_export_dict['InsufficientDataActions'] = alarm_action_list