Example #1
0
    def register_pre_resources_template(self, template):
        """Register one UploadToS3 action into the pre_resources template, as
        well as several Outputs so subsequente templates can reference these
        files.
        Before registering these actions, we create the .zip file we'll
        upload to s3 on apply time.
        """

        code_path = os.path.join(self.project.build_path, 'code')
        if not os.path.exists(code_path):
            os.makedirs(code_path)

        # We need to know to which bucket we are uploading these files.
        template.add_parameter(
            actions.Parameter(
                name="CodeBucket"
            )
        )

        filename = os.path.join(code_path, self.get_bucket_key())
        with open(filename, 'wb') as f:
            f.write(self.get_zip_file().read())

        context, context_key = {}, self.get_context_key()
        try:
            lambda_context = self.project.get_resource('contexts::{}'.format(context_key))
        except exceptions.ResourceNotFoundError:
            if context_key != 'default':
                raise
        else:
            context = lambda_context.settings

        template.add(
            actions.InjectContextAndUploadToS3(
                name="{}-upload".format(self.name),
                bucket=actions.Ref(name='CodeBucket'),
                key=self.get_bucket_key(),
                filename=os.path.relpath(filename, self.project.build_path),
                context_to_inject=context,
                context_destinaton=self.get_context_destination()
            )
        )
        template.add_output(
            actions.Output(
                name=utils.valid_cloudformation_name(self.name, "s3url"),
                value=actions.GetAttr(
                    action="{}-upload".format(self.name),
                    attr="s3url",
                )
            )
        )
        template.add_output(
            actions.Output(
                name=utils.valid_cloudformation_name(self.name, "s3version"),
                value=actions.GetAttr(
                    action="{}-upload".format(self.name),
                    attr="s3version",
                )
            )
        )
Example #2
0
    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'),
                ))
Example #3
0
    def register_pre_resources_template(self, template):
        """Register one UploadToS3 action into the pre_resources template, as
        well as several Outputs so subsequente templates can reference these
        files.
        Before registering these actions, we create the .zip file we'll
        upload to s3 on apply time.
        """

        code_path = os.path.join(self.project.build_path, 'code')
        if not os.path.exists(code_path):
            os.makedirs(code_path)

        # We need to know to which bucket we are uploading these files.
        template.add_parameter(
            actions.Parameter(
                name="CodeBucket"
            )
        )

        filename = os.path.join(code_path, self.get_bucket_key())
        with open(filename, 'wb') as f:
            f.write(self.get_zip_file().read())

        context, context_key = {}, self.get_context_key()
        try:
            lambda_context = self.project.get_resource('contexts::{}'.format(context_key))
        except exceptions.ResourceNotFoundError:
            if context_key != 'default':
                raise
        else:
            context = lambda_context.settings

        template.add(
            actions.InjectContextAndUploadToS3(
                name="{}-upload".format(self.name),
                bucket=actions.Ref(name='CodeBucket'),
                key=self.get_bucket_key(),
                filename=os.path.relpath(filename, self.project.build_path),
                context_to_inject=context,
                context_destinaton=self.get_context_destination()
            )
        )
        template.add_output(
            actions.Output(
                name=utils.valid_cloudformation_name(self.name, "s3url"),
                value=actions.GetAttr(
                    action="{}-upload".format(self.name),
                    attr="s3url",
                )
            )
        )
        template.add_output(
            actions.Output(
                name=utils.valid_cloudformation_name(self.name, "s3version"),
                value=actions.GetAttr(
                    action="{}-upload".format(self.name),
                    attr="s3version",
                )
            )
        )
Example #4
0
    def _get_policies(self):
        """Returns a list of policies to attach to the IAM Role of this Lambda.
        Users can add more policies to this Role by defining policy documents
        in the settings of the lambda under the ``policies`` key."""

        policies = []

        if self._get_true_false('auto-run-policy', 't'):
            policies.append(
                iam.Policy(PolicyName=utils.valid_cloudformation_name(
                    self.name, 'logs', 'policy'),
                           PolicyDocument={
                               "Version":
                               "2012-10-17",
                               "Statement": [{
                                   "Effect":
                                   "Allow",
                                   "Action": ["lambda:InvokeFunction"],
                                   "Resource": ["*"]
                               }, {
                                   "Effect":
                                   "Allow",
                                   "Action": [
                                       "logs:CreateLogGroup",
                                       "logs:CreateLogStream",
                                       "logs:PutLogEvents"
                                   ],
                                   "Resource":
                                   "arn:aws:logs:*:*:*",
                               }]
                           }))

        if self.settings.get('vpc') and self._get_true_false(
                'auto-vpc-policy', 't'):
            policies.append(
                iam.Policy(PolicyName=utils.valid_cloudformation_name(
                    self.name, 'vpc'),
                           PolicyDocument={
                               "Version":
                               "2012-10-17",
                               "Statement": [{
                                   "Effect":
                                   "Allow",
                                   "Action": [
                                       "ec2:CreateNetworkInterface",
                                       "ec2:DescribeNetworkInterfaces",
                                       "ec2:DeleteNetworkInterface"
                                   ],
                                   "Resource": ["*"]
                               }]
                           }))

        for policy_nme, policy_document in six.iteritems(
                self.settings.get('policies', {})):
            policies.append(
                iam.Policy(PolicyName=utils.valid_cloudformation_name(
                    self.name, policy_nme, 'policy'),
                           PolicyDocument=policy_document))
        return policies
Example #5
0
    def test_0001_project(self):
        self._test_project_step('0001_project')
        self.assert_stack_succeed('p')
        self.assert_stack_succeed('r')

        lambda_ = self.get_lambda(utils.valid_cloudformation_name('cron:example'))
        rule_ = self.get_rule(utils.valid_cloudformation_name('every_night_rule'))
        targets = self.get_rule_targets(rule_['Name'])
        self.assertEqual(rule_['ScheduleExpression'], 'cron(0 20 * * ? *)')
        self.assertEqual(len(targets), 1)
        self.assertEqual(targets[0]['Arn'], '{}:current'.format(lambda_['FunctionArn']))
Example #6
0
    def test_0001_project(self):
        self._test_project_step('0001_project')
        self.assert_stack_succeed('p')
        self.assert_stack_succeed('r')

        lambda_ = self.get_lambda(
            utils.valid_cloudformation_name('cron:example'))
        rule_ = self.get_rule(
            utils.valid_cloudformation_name('every_night_rule'))
        targets = self.get_rule_targets(rule_['Name'])
        self.assertEqual(rule_['ScheduleExpression'], 'cron(0 20 * * ? *)')
        self.assertEqual(len(targets), 1)
        self.assertEqual(targets[0]['Arn'],
                         '{}:current'.format(lambda_['FunctionArn']))
Example #7
0
File: base.py Project: Empia/gordon
    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()
            )
        )
Example #8
0
    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]
Example #9
0
    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])))
Example #10
0
    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])
            )
        )
Example #11
0
 def register_destination_publish_permission(self, template):
     template.add_resource(
         sns.TopicPolicy(
             utils.valid_cloudformation_name(
                 self.bucket_notification_configuration.name, self.id,
                 'permission'),
             Topics=[self.get_destination_arn()],
             PolicyDocument={
                 "Version":
                 "2008-10-17",
                 "Id":
                 "PublicationPolicy",
                 "Statement": [{
                     "Effect": "Allow",
                     "Principal": {
                         "AWS": "*"
                     },
                     "Action": ["sns:Publish"],
                     "Resource": self.get_destination_arn(),
                     "Condition": {
                         "ArnEquals": {
                             "aws:SourceArn":
                             self.bucket_notification_configuration.
                             get_bucket_arn()
                         }
                     }
                 }]
             }))
Example #12
0
    def get_role(self):
        """Returns the role this lambda function will use. Users can customize
        which role to apply by referencing the ARN of the role. If no Role
        is defined, gordon will create and assing one with the basic
        permissions suggested by AWS.

        Users can customize the policies attached to the role using
        ``policies`` in the lambda settings."""

        role = self.settings.get('role')

        if isinstance(role, six.string_types) or isinstance(role, troposphere.Ref):
            return role
        elif role is None:
            pass
        else:
            raise exceptions.InvalidLambdaRoleError(self.name, role)

        return iam.Role(
            utils.valid_cloudformation_name(self.name, 'role'),
            AssumeRolePolicyDocument={
                "Version": "2012-10-17",
                "Statement": [{
                    "Effect": "Allow",
                    "Principal": {
                        "Service": ["lambda.amazonaws.com"]
                    },
                    "Action": ["sts:AssumeRole"]
                }]
            },
            Policies=self._get_policies()
        )
Example #13
0
    def get_role(self):
        """Returns the role this lambda function will use. Users can customize
        which role to apply by referencing the ARN of the role. If no Role
        is defined, gordon will create and assing one with the basic
        permissions suggested by AWS.

        Users can customize the policies attached to the role using
        ``policies`` in the lambda settings."""

        role = self.settings.get('role')

        if isinstance(role, six.string_types) or isinstance(
                role, troposphere.Ref):
            return role
        elif role is None:
            pass
        else:
            raise exceptions.InvalidLambdaRoleError(self.name, role)

        return iam.Role(utils.valid_cloudformation_name(self.name, 'role'),
                        AssumeRolePolicyDocument={
                            "Version":
                            "2012-10-17",
                            "Statement": [{
                                "Effect": "Allow",
                                "Principal": {
                                    "Service": ["lambda.amazonaws.com"]
                                },
                                "Action": ["sts:AssumeRole"]
                            }]
                        },
                        Policies=self._get_policies())
Example #14
0
    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()))
Example #15
0
 def register_destination_publish_permission(self, template):
     template.add_resource(
         sns.TopicPolicy(
             utils.valid_cloudformation_name(
                 self.bucket_notification_configuration.name,
                 self.id,
                 'permission'
             ),
             Topics=[self.get_destination_arn()],
             PolicyDocument={
                 "Version": "2008-10-17",
                 "Id": "PublicationPolicy",
                 "Statement": [{
                     "Effect": "Allow",
                     "Principal": {
                       "AWS": "*"
                     },
                     "Action": ["sns:Publish"],
                     "Resource": self.get_destination_arn(),
                     "Condition": {
                         "ArnEquals": {"aws:SourceArn": self.bucket_notification_configuration.get_bucket_arn()}
                     }
                 }]
             }
         )
     )
Example #16
0
    def __init__(self, *args, **kwargs):
        super(Lambda, self).__init__(*args, **kwargs)
        self.current_alias_project_name = '{}:current'.format(
            self.in_project_name)
        self.current_alias_cf_name = utils.valid_cloudformation_name(
            self.name, "CurrentAlias")

        self.project.register_resource_reference(
            self.current_alias_project_name, self.current_alias_cf_name, self)
Example #17
0
    def __init__(self, *args, **kwargs):
        super(Lambda, self).__init__(*args, **kwargs)
        self.current_alias_project_name = '{}:current'.format(self.in_project_name)
        self.current_alias_cf_name = utils.valid_cloudformation_name(self.name, "CurrentAlias")

        self.project.register_resource_reference(
            self.current_alias_project_name,
            self.current_alias_cf_name,
            self
        )
Example #18
0
File: tests.py Project: T2BE/gordon
    def test_0001_project(self):
        self._test_project_step('0001_project')

        self.assert_stack_succeed('p')
        self.assert_stack_succeed('r')

        lambda_ = self.get_lambda(valid_cloudformation_name('kinesisconsumer:consumer'))
        self.assertEqual(lambda_['Runtime'], 'python2.7')

        aliases = self.get_lambda_aliases(function_name=lambda_['FunctionName'])
        self.assertEqual(aliases.keys(), ['current'])
Example #19
0
 def register_destination_publish_permission(self, template):
     template.add_resource(
         awslambda.Permission(
             utils.valid_cloudformation_name(
                 self.bucket_notification_configuration.name, self.id,
                 'permission'),
             Action="lambda:InvokeFunction",
             FunctionName=self.get_destination_arn(),
             Principal="s3.amazonaws.com",
             SourceAccount=troposphere.Ref(troposphere.AWS_ACCOUNT_ID),
         ))
Example #20
0
    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'
                    ),
                )
            )
Example #21
0
    def test_0001_project(self):
        self._test_project_step('0001_project')

        self.assert_stack_succeed('p')
        self.assert_stack_succeed('r')

        lambda_ = self.get_lambda(
            valid_cloudformation_name('kinesisconsumer:consumer'))
        self.assertEqual(lambda_['Runtime'], 'python2.7')

        aliases = self.get_lambda_aliases(
            function_name=lambda_['FunctionName'])
        self.assertEqual(list(aliases.keys()), ['current'])
Example #22
0
 def register_destination_publish_permission(self, template):
     template.add_resource(
         awslambda.Permission(
             utils.valid_cloudformation_name(
                 self.bucket_notification_configuration.name,
                 self.id,
                 'permission'
             ),
             Action="lambda:InvokeFunction",
             FunctionName=self.get_destination_arn(),
             Principal="s3.amazonaws.com",
             SourceAccount=troposphere.Ref(troposphere.AWS_ACCOUNT_ID),
         )
     )
Example #23
0
    def __init__(self, name, settings, project=None, app=None):
        self.name = name
        self.app = app
        self.project = project or self.app.project
        self.settings = settings
        for key in self.required_settings:
            if key not in self.settings:
                raise exceptions.ResourceSettingRequiredError(self.name, key)

        self.in_project_name = self._get_in_project_name()
        self.in_project_cf_name = utils.valid_cloudformation_name(
            self.in_project_name.split(':', 1)[1])

        self.project.register_resource_reference(self.in_project_name,
                                                 self.in_project_cf_name, self)
Example #24
0
    def test_0001_project(self):
        self._test_project_step('0001_project')
        self.assert_stack_succeed('p')
        self.assert_stack_succeed('r')

        lambda_ = self.get_lambda(
            utils.valid_cloudformation_name('javaexample:javaexample'))
        self.assertEqual(lambda_['Runtime'], 'java8')
        self.assertEqual(lambda_['Description'], 'My description')
        self.assertEqual(lambda_['MemorySize'], 192)
        self.assertEqual(lambda_['Timeout'], 123)

        aliases = self.get_lambda_aliases(
            function_name=lambda_['FunctionName'])
        self.assertEqual(list(aliases.keys()), ['current'])

        response = self.invoke_lambda(function_name=lambda_['FunctionName'],
                                      payload={'key1': 'hello'})
        self.assert_lambda_response(response, 'hello')
Example #25
0
File: tests.py Project: T2BE/gordon
    def test_0001_project(self):
        self._test_project_step('0001_project')
        self.assert_stack_succeed('p')
        self.assert_stack_succeed('r')

        lambda_ = self.get_lambda(utils.valid_cloudformation_name('pyexample:pyexample'))
        self.assertEqual(lambda_['Runtime'], 'python2.7')
        self.assertEqual(lambda_['Description'], 'My description')
        self.assertEqual(lambda_['MemorySize'], 192)
        self.assertEqual(lambda_['Timeout'], 123)

        aliases = self.get_lambda_aliases(function_name=lambda_['FunctionName'])
        self.assertEqual(aliases.keys(), ['current'])

        response = self.invoke_lambda(
            function_name=lambda_['FunctionName'],
            payload={'key1': 'hello'}
        )
        self.assert_lambda_response(response, 'hello')
Example #26
0
File: base.py Project: Empia/gordon
    def __init__(self, name, settings, project=None, app=None):
        self.name = name
        self.app = app
        self.project = project or self.app.project
        self.settings = settings
        for key in self.required_settings:
            if key not in self.settings:
                raise exceptions.ResourceSettingRequiredError(self.name, key)

        self.in_project_name = self._get_in_project_name()
        self.in_project_cf_name = utils.valid_cloudformation_name(
            self.in_project_name.split(':', 1)[1]
        )

        self.project.register_resource_reference(
            self.in_project_name,
            self.in_project_cf_name,
            self
        )
Example #27
0
    def test_0002_project(self):
        self._test_project_step('0002_project')
        self.assert_stack_succeed('p')
        self.assert_stack_succeed('r')

        lambda_ = self.get_lambda(utils.valid_cloudformation_name('pyexample:pyexample'))
        self.assertEqual(lambda_['Runtime'], 'python2.7')
        self.assertEqual(lambda_['Description'], 'My second description')
        self.assertEqual(lambda_['MemorySize'], 256)
        self.assertEqual(lambda_['Timeout'], 199)

        aliases = self.get_lambda_aliases(function_name=lambda_['FunctionName'])
        self.assertEqual(list(aliases.keys()), ['current'])

        response = self.invoke_lambda(
            function_name=lambda_['FunctionName'],
            payload={'key1': 'hello', 'key2': 'bye'}
        )
        self.assert_lambda_response(response, 'bye')
Example #28
0
    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]
Example #29
0
    def register_resources_template(self, template):
        """Register the lambda Function into the troposphere template. If
        this function requires a custom Role, register it too."""

        role = self.get_role()
        depends_on = []
        if isinstance(role, iam.Role):
            template.add_resource(role)
            depends_on.append(role.name)
            role = troposphere.GetAtt(role, 'Arn')

        template.add_parameter(
            troposphere.Parameter(
                utils.valid_cloudformation_name(self.name, "s3version"),
                Type="String",
            ))

        extra = {}
        if self.settings.get('vpc'):
            vpc = self.project.get_resource('vpc::{}'.format(
                self.settings.get('vpc')))

            if isinstance(vpc.settings['security-groups'], troposphere.Ref):
                vpc.settings[
                    'security-groups']._type = 'List<AWS::EC2::SecurityGroup::Id>'

            if isinstance(vpc.settings['subnet-ids'], troposphere.Ref):
                vpc.settings['subnet-ids']._type = 'List<AWS::EC2::Subnet::Id>'

            extra['VpcConfig'] = awslambda.VPCConfig(
                SecurityGroupIds=vpc.settings['security-groups'],
                SubnetIds=vpc.settings['subnet-ids'])

        function = template.add_resource(
            awslambda.Function(self.in_project_cf_name,
                               DependsOn=depends_on,
                               Code=awslambda.Code(
                                   S3Bucket=troposphere.Ref("CodeBucket"),
                                   S3Key=self.get_bucket_key(),
                                   S3ObjectVersion=troposphere.Ref(
                                       utils.valid_cloudformation_name(
                                           self.name, "s3version")),
                               ),
                               Description=self.settings.get(
                                   'description', ''),
                               Handler=self.get_handler(),
                               MemorySize=self.get_memory(),
                               Role=role,
                               Runtime=self.get_runtime(),
                               Timeout=self.get_timeout(),
                               **extra))

        lambda_version = 'lambda:contrib_lambdas:version'
        lambda_ref = troposphere.GetAtt(self.project.reference(lambda_version),
                                        'Arn')
        if not self.in_project_name.startswith('lambda:contrib_lambdas:'):
            lambda_version = '{}:current'.format(lambda_version)
            lambda_ref = troposphere.Ref(
                self.project.reference(lambda_version))

        version = template.add_resource(
            LambdaVersion.create_with(
                utils.valid_cloudformation_name(self.name, "Version"),
                DependsOn=[
                    self.project.reference(lambda_version), function.name
                ],
                lambda_arn=lambda_ref,
                FunctionName=troposphere.Ref(function),
                S3ObjectVersion=troposphere.Ref(
                    utils.valid_cloudformation_name(self.name, "s3version")),
            ))

        alias = template.add_resource(
            awslambda.Alias(
                self.current_alias_cf_name,
                DependsOn=[version.name],
                FunctionName=troposphere.Ref(function),
                FunctionVersion=troposphere.GetAtt(version, "Version"),
                Name="current",
            ))
        if self._get_true_false('cli-output', 't'):
            template.add_output([
                troposphere.Output(
                    utils.valid_cloudformation_name("Clioutput",
                                                    self.in_project_name),
                    Value=troposphere.Ref(alias),
                )
            ])
Example #30
0
    def register_resources_template(self, template):
        """Register the lambda Function into the troposphere template. If
        this function requires a custom Role, register it too."""

        role = self.get_role()
        depends_on = []
        if isinstance(role, iam.Role):
            template.add_resource(role)
            depends_on.append(role.name)
            role = troposphere.GetAtt(role, 'Arn')

        template.add_parameter(
            troposphere.Parameter(
                utils.valid_cloudformation_name(self.name, "s3version"),
                Type="String",
            )
        )

        extra = {}
        if self.settings.get('vpc'):
            vpc = self.project.get_resource('vpc::{}'.format(self.settings.get('vpc')))
            extra['VpcConfig'] = awslambda.VPCConfig(
                SecurityGroupIds=vpc.settings['security-groups'],
                SubnetIds=vpc.settings['subnet-ids']
            )

        function = template.add_resource(
            awslambda.Function(
                self.in_project_cf_name,
                DependsOn=depends_on,
                Code=awslambda.Code(
                    S3Bucket=troposphere.Ref("CodeBucket"),
                    S3Key=self.get_bucket_key(),
                    S3ObjectVersion=troposphere.Ref(
                        utils.valid_cloudformation_name(self.name, "s3version")
                    ),
                ),
                Description=self.settings.get('description', ''),
                Handler=self.get_handler(),
                MemorySize=self.get_memory(),
                Role=role,
                Runtime=self.get_runtime(),
                Timeout=self.get_timeout(),
                **extra
            )
        )

        lambda_version = 'lambda:contrib_lambdas:version'
        lambda_ref = troposphere.GetAtt(self.project.reference(lambda_version), 'Arn')
        if not self.in_project_name.startswith('lambda:contrib_lambdas:'):
            lambda_version = '{}:current'.format(lambda_version)
            lambda_ref = troposphere.Ref(self.project.reference(lambda_version))

        version = template.add_resource(
            LambdaVersion.create_with(
                utils.valid_cloudformation_name(self.name, "Version"),
                DependsOn=[
                    self.project.reference(lambda_version),
                    function.name
                ],
                lambda_arn=lambda_ref,
                FunctionName=troposphere.Ref(
                    function
                ),
                S3ObjectVersion=troposphere.Ref(
                   utils.valid_cloudformation_name(self.name, "s3version")
                ),
            )
        )

        alias = template.add_resource(
            awslambda.Alias(
                self.current_alias_cf_name,
                DependsOn=[
                    version.name
                ],
                FunctionName=troposphere.Ref(
                    function
                ),
                FunctionVersion=troposphere.GetAtt(
                    version, "Version"
                ),
                Name="current",
            )
        )
        if self._get_true_false('cli-output', 't'):
            template.add_output([
                troposphere.Output(
                    utils.valid_cloudformation_name("Clioutput", self.in_project_name),
                    Value=troposphere.Ref(alias),
                )
            ])
Example #31
0
    def test_0001_project(self):
        self._test_project_step('0001_project')
        self.assert_stack_succeed('p')
        self.assert_stack_succeed('r')

        lambda_ = self.get_lambda(utils.valid_cloudformation_name('pyexample:hellopy'))
        self.assertEqual(lambda_['Runtime'], 'python2.7')
        self.assertEqual(lambda_['Description'], 'My hello description')
        self.assertEqual(lambda_['MemorySize'], 192)
        self.assertEqual(lambda_['Timeout'], 123)

        aliases = self.get_lambda_aliases(function_name=lambda_['FunctionName'])
        self.assertEqual(list(aliases.keys()), ['current'])

        response = self.invoke_lambda(
            function_name=lambda_['FunctionName'],
            payload={}
        )
        self.assert_lambda_response(response, 'hello')

        lambda_ = self.get_lambda(utils.valid_cloudformation_name('pyexample:byepy'))
        self.assertEqual(lambda_['Runtime'], 'python2.7')
        self.assertEqual(lambda_['Description'], 'My bye description')
        self.assertEqual(lambda_['MemorySize'], 192)
        self.assertEqual(lambda_['Timeout'], 123)

        aliases = self.get_lambda_aliases(function_name=lambda_['FunctionName'])
        self.assertEqual(list(aliases.keys()), ['current'])

        response = self.invoke_lambda(
            function_name=lambda_['FunctionName'],
            payload={}
        )
        self.assert_lambda_response(response, 'bye')

        client = boto3.client('apigateway')
        api = [a for a in client.get_rest_apis()['items'] if a['name'] == 'helloapi-{}'.format(self.uid)][0]
        endpoint = 'https://{}.execute-api.{}.amazonaws.com/{}'.format(api['id'], os.environ['AWS_DEFAULT_REGION'], self.uid)

        response = requests.get(endpoint)
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.content.decode('utf-8'), '"hello"')

        response = requests.get('{}/404'.format(endpoint))
        self.assertEqual(response.status_code, 404)
        self.assertEqual(response.content.decode('utf-8'), '"hello"')

        response = requests.get('{}/shop/2'.format(endpoint))
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.content.decode('utf-8'), '"hello"')

        response = requests.get('{}/http'.format(endpoint))
        self.assertEqual(response.status_code, 200)
        self.assertEqual(json.loads(response.content.decode('utf-8'))['args'], {'hello': 'world'})

        response = requests.get('{}/complex'.format(endpoint))
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.content.decode('utf-8'), '"hello"')

        response = requests.post('{}/complex'.format(endpoint))
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.content.decode('utf-8'), '"bye"')
Example #32
0
    def _get_policies(self):
        """Returns a list of policies to attach to the IAM Role of this Lambda.
        Users can add more policies to this Role by defining policy documents
        in the settings of the lambda under the ``policies`` key."""

        policies = []

        if self._get_true_false('auto-run-policy', 't'):
            policies.append(
                iam.Policy(
                    PolicyName=utils.valid_cloudformation_name(self.name, 'logs', 'policy'),
                    PolicyDocument={
                        "Version": "2012-10-17",
                        "Statement": [
                            {
                                "Effect": "Allow",
                                "Action": [
                                    "lambda:InvokeFunction"
                                ],
                                "Resource": [
                                    "*"
                                ]
                            },
                            {
                                "Effect": "Allow",
                                "Action": [
                                    "logs:CreateLogGroup",
                                    "logs:CreateLogStream",
                                    "logs:PutLogEvents"
                                ],
                                "Resource": "arn:aws:logs:*:*:*",
                            }
                        ]
                    }
                )
            )

        if self.settings.get('vpc') and self._get_true_false('auto-vpc-policy', 't'):
            policies.append(
                iam.Policy(
                    PolicyName=utils.valid_cloudformation_name(self.name, 'vpc'),
                    PolicyDocument={
                        "Version": "2012-10-17",
                        "Statement": [
                            {
                                "Effect": "Allow",
                                "Action": [
                                    "ec2:CreateNetworkInterface"
                                ],
                                "Resource": [
                                    "*"
                                ]
                            }
                        ]
                    }
                )
            )

        for policy_nme, policy_document in six.iteritems(self.settings.get('policies', {})):
            policies.append(
                iam.Policy(
                    PolicyName=utils.valid_cloudformation_name(self.name, policy_nme, 'policy'),
                    PolicyDocument=policy_document
                )
            )
        return policies
Example #33
0
    def register_resources_template(self, template):

        deployment_resources = []
        api = RestApi(
            self.in_project_cf_name,
            Name=troposphere.Join("-", [self.name, troposphere.Ref('Stage')]),
            Description=self.settings.get('description', '')
        )
        template.add_resource(api)
        deployment_resources.append(api)

        invoke_lambda_role = troposphere.iam.Role(
            utils.valid_cloudformation_name(self.name, 'Role'),
            AssumeRolePolicyDocument={
                "Version": "2012-10-17",
                "Statement": [{
                    "Effect": "Allow",
                    "Principal": {
                        "Service": ["apigateway.amazonaws.com"]
                    },
                    "Action": ["sts:AssumeRole"]
                }]
            },
            Policies=[
                troposphere.iam.Policy(
                    PolicyName=utils.valid_cloudformation_name(self.name, 'Role', 'Policy'),
                    PolicyDocument={
                        "Version": "2012-10-17",
                        "Statement": [
                            {
                                "Effect": "Allow",
                                "Action": [
                                    "lambda:InvokeFunction"
                                ],
                                "Resource": [
                                    "*"
                                ]
                            }
                        ]
                    }
                )
            ]
        )

        template.add_resource(invoke_lambda_role)
        deployment_resources.append(invoke_lambda_role)

        deployment_dependencies = []
        for path, resource in six.iteritems(self.settings.get('resources', {})):
            resource_reference = self.get_or_create_resource(path, api, template)
            methods = resource['methods']

            if isinstance(methods, six.string_types):
                methods = [methods]

            if not isinstance(methods, dict):
                method_properties = copy.deepcopy(resource)
                method_properties.pop('methods', None)
                methods = dict([[method, method_properties] for method in methods])

            for method, configuration in six.iteritems(methods):
                method_name = [self.name]
                method_name.extend(path.split('/'))
                method_name.append(method)

                extra = {}
                if 'parameters' in configuration:
                    extra['RequestParameters'] = configuration['parameters']
                m = Method(
                    utils.valid_cloudformation_name(*method_name),
                    HttpMethod=method,
                    AuthorizationType=self.get_authorization_type(configuration),
                    ApiKeyRequired=self.get_api_key_required(configuration),
                    Integration=self.get_integration(configuration, invoke_lambda_role),
                    MethodResponses=self.get_method_responses(configuration),
                    ResourceId=resource_reference,
                    RestApiId=troposphere.Ref(api),
                    **extra
                )
                template.add_resource(m)
                deployment_dependencies.append(m.name)
                deployment_resources.append(m)

        deploy_hash = hashlib.sha1(six.text_type(uuid.uuid4()).encode('utf-8')).hexdigest()
        deploy = Deployment(
            utils.valid_cloudformation_name(self.name, "Deployment", deploy_hash[:8]),
            DependsOn=sorted(deployment_dependencies),
            StageName=troposphere.Ref('Stage'),
            RestApiId=troposphere.Ref(api)
        )

        template.add_resource(deploy)

        if self._get_true_false('cli-output', 't'):
            template.add_output([
                troposphere.Output(
                    utils.valid_cloudformation_name("Clioutput", self.in_project_name),
                    Value=troposphere.Join(
                        "",
                        [
                            "https://",
                            troposphere.Ref(api),
                            ".execute-api.",
                            troposphere.Ref(troposphere.AWS_REGION),
                            ".amazonaws.com/",
                            troposphere.Ref('Stage')
                        ]
                    ),
                )
            ])
Example #34
0
    def register_resources_template(self, template):

        deployment_resources = []
        api = RestApi(
            self.in_project_cf_name,
            Name=troposphere.Join("-", [self.name, troposphere.Ref('Stage')]),
            Description=self.settings.get('description', '')
        )
        template.add_resource(api)
        deployment_resources.append(api)

        invoke_lambda_role = troposphere.iam.Role(
            utils.valid_cloudformation_name(self.name, 'Role'),
            AssumeRolePolicyDocument={
                "Version": "2012-10-17",
                "Statement": [{
                    "Effect": "Allow",
                    "Principal": {
                        "Service": ["apigateway.amazonaws.com"]
                    },
                    "Action": ["sts:AssumeRole"]
                }]
            },
            Policies=[
                troposphere.iam.Policy(
                    PolicyName=utils.valid_cloudformation_name(self.name, 'Role', 'Policy'),
                    PolicyDocument={
                        "Version": "2012-10-17",
                        "Statement": [
                            {
                                "Effect": "Allow",
                                "Action": [
                                    "lambda:InvokeFunction"
                                ],
                                "Resource": [
                                    "*"
                                ]
                            }
                        ]
                    }
                )
            ]
        )

        template.add_resource(invoke_lambda_role)
        deployment_resources.append(invoke_lambda_role)

        deployment_dependencies = []
        for path, resource in six.iteritems(self.settings.get('resources', {})):
            resource_reference = self.get_or_create_resource(path, api, template)
            methods = resource['methods']

            if isinstance(methods, six.string_types):
                methods = [methods]

            if not isinstance(methods, dict):
                method_properties = copy.deepcopy(resource)
                method_properties.pop('methods', None)
                methods = dict([[method, method_properties] for method in methods])

            for method, configuration in six.iteritems(methods):
                method_name = [self.name]
                method_name.extend(path.split('/'))
                method_name.append(method)

                extra = {}
                if 'parameters' in configuration:
                    extra['RequestParameters'] = configuration['parameters']
                m = Method(
                    utils.valid_cloudformation_name(*method_name),
                    HttpMethod=method,
                    AuthorizationType=self.get_authorization_type(configuration),
                    ApiKeyRequired=self.get_api_key_required(configuration),
                    Integration=self.get_integration(configuration, invoke_lambda_role),
                    MethodResponses=self.get_method_responses(configuration),
                    ResourceId=resource_reference,
                    RestApiId=troposphere.Ref(api),
                    **extra
                )
                template.add_resource(m)
                deployment_dependencies.append(m.name)
                deployment_resources.append(m)

        deploy_hash = hashlib.sha1(six.text_type(uuid.uuid4()).encode('utf-8')).hexdigest()
        deploy = Deployment(
            utils.valid_cloudformation_name(self.name, "Deployment", deploy_hash[:8]),
            DependsOn=sorted(deployment_dependencies),
            StageName=troposphere.Ref('Stage'),
            RestApiId=troposphere.Ref(api)
        )

        template.add_resource(deploy)

        if self._get_true_false('cli-output', 't'):
            template.add_output([
                troposphere.Output(
                    utils.valid_cloudformation_name("Clioutput", self.in_project_name),
                    Value=troposphere.Join(
                        "",
                        [
                            "https://",
                            troposphere.Ref(api),
                            ".execute-api.",
                            troposphere.Ref(troposphere.AWS_REGION),
                            ".amazonaws.com/",
                            troposphere.Ref('Stage')
                        ]
                    ),
                )
            ])