Exemple #1
0
 def test_can_update_managed_role(self):
     role = models.ManagedIAMRole(
         resource_name='resource_name',
         role_name='myrole',
         trust_policy={},
         policy=models.AutoGenIAMPolicy(document={'role': 'policy'}),
     )
     self.remote_state.declare_resource_exists(role, role_arn='myrole:arn')
     plan = self.determine_plan(role)
     assert plan[0] == models.StoreValue(name='myrole_role_arn',
                                         value='myrole:arn')
     self.assert_apicall_equals(
         plan[1],
         models.APICall(
             method_name='put_role_policy',
             params={
                 'role_name': 'myrole',
                 'policy_name': 'myrole',
                 'policy_document': {
                     'role': 'policy'
                 }
             },
         ))
     assert plan[-2].variable_name == 'myrole_role_arn'
     assert plan[-1].value == 'myrole'
     assert list(self.last_plan.messages.values()) == [
         'Updating policy for IAM role: myrole\n'
     ]
Exemple #2
0
 def test_can_create_plan_for_filebased_role(self):
     self.remote_state.declare_no_resources_exists()
     resource = models.ManagedIAMRole(
         resource_name='default-role',
         role_name='myrole',
         trust_policy={'trust': 'policy'},
         policy=models.FileBasedIAMPolicy(filename='foo.json',
                                          document={'iam': 'policy'}),
     )
     plan = self.determine_plan(resource)
     expected = models.APICall(
         method_name='create_role',
         params={
             'name': 'myrole',
             'trust_policy': {
                 'trust': 'policy'
             },
             'policy': {
                 'iam': 'policy'
             }
         },
     )
     self.assert_apicall_equals(plan[0], expected)
     assert list(self.last_plan.messages.values()) == [
         'Creating IAM role: myrole\n'
     ]
Exemple #3
0
 def test_can_update_lambda_function_code(self):
     function = create_function_resource('function_name')
     copy_of_function = attr.evolve(function)
     self.remote_state.declare_resource_exists(copy_of_function)
     # Now let's change the memory size and ensure we
     # get an update.
     function.memory_size = 256
     plan = self.determine_plan(function)
     existing_params = {
         'function_name': 'appname-dev-function_name',
         'role_arn': 'role:arn',
         'zip_contents': mock.ANY,
         'runtime': 'python2.7',
         'environment_variables': {},
         'tags': {},
         'timeout': 60,
         'security_group_ids': [],
         'subnet_ids': [],
     }
     expected_params = dict(memory_size=256, **existing_params)
     expected = models.APICall(
         method_name='update_function',
         params=expected_params,
     )
     self.assert_apicall_equals(plan[0], expected)
     assert list(self.last_plan.messages.values()) == [
         'Updating lambda function: appname-dev-function_name\n'
     ]
Exemple #4
0
 def _inject_websocket_integrations(self, configs):
     # type: (Dict[str, Any]) -> Sequence[InstructionMsg]
     instructions = []  # type: List[InstructionMsg]
     for key, config in configs.items():
         instructions.append(
             models.StoreValue(
                 name='websocket-%s-integration-lambda-path' % key,
                 value=StringFormat(
                     'arn:aws:apigateway:{region_name}:lambda:path/'
                     '2015-03-31/functions/arn:aws:lambda:{region_name}:'
                     '{account_id}:function:%s/'
                     'invocations' % config['name'],
                     ['region_name', 'account_id'],
                 ),
             ), )
         instructions.append(
             models.APICall(
                 method_name='create_websocket_integration',
                 params={
                     'api_id':
                     Variable('websocket_api_id'),
                     'lambda_function':
                     Variable('websocket-%s-integration-lambda-path' % key),
                     'handler_type':
                     key,
                 },
                 output_var='%s-integration-id' % key,
             ), )
     return instructions
Exemple #5
0
    def _delete_api_mapping(self,
                            domain_name,   # type: str
                            api_mapping    # type: Dict[str, Any]
                            ):
        # type: (...) -> ResourceValueType
        if api_mapping['key'] == '/':
            path_key = '(none)'
        else:
            path_key = api_mapping['key'].lstrip("/")

        params = {
            'domain_name': domain_name,
            'path_key': path_key
        }
        msg = 'Deleting base path mapping from %s custom domain name: %s\n' % (
            domain_name, api_mapping['key']
        )
        return {
            'instructions': (
                models.APICall(
                    method_name='delete_api_mapping',
                    params=params,
                ),
            ),
            'message': msg
        }
Exemple #6
0
 def _plan_deletion(self,
                    plan,       # type: List[models.Instruction]
                    messages,   # type: Dict[int, str]
                    remaining,  # type: List[str]
                    deployed,   # type: DeployedResources
                    ):
     # type: (...) -> None
     for name in remaining:
         resource_values = deployed.resource_values(name)
         if resource_values['resource_type'] == 'lambda_function':
             apicall = models.APICall(
                 method_name='delete_function',
                 params={'function_name': resource_values['lambda_arn']},)
             messages[id(apicall)] = (
                 "Deleting function: %s\n" % resource_values['lambda_arn'])
             plan.append(apicall)
         elif resource_values['resource_type'] == 'iam_role':
             apicall = models.APICall(
                 method_name='delete_role',
                 params={'name': resource_values['role_name']},
             )
             messages[id(apicall)] = (
                 "Deleting IAM role: %s\n" % resource_values['role_name'])
             plan.append(apicall)
         elif resource_values['resource_type'] == 'cloudwatch_event':
             apicall = models.APICall(
                 method_name='delete_rule',
                 params={'rule_name': resource_values['rule_name']},
             )
             plan.append(apicall)
         elif resource_values['resource_type'] == 'rest_api':
             rest_api_id = resource_values['rest_api_id']
             apicall = models.APICall(
                 method_name='delete_rest_api',
                 params={'rest_api_id': rest_api_id}
             )
             messages[id(apicall)] = (
                 "Deleting Rest API: %s\n" % resource_values['rest_api_id'])
             plan.append(apicall)
         elif resource_values['resource_type'] == 's3_event':
             bucket = resource_values['bucket']
             function_arn = resource_values['lambda_arn']
             apicall = models.APICall(
                 method_name='disconnect_s3_bucket_from_lambda',
                 params={'bucket': bucket, 'function_arn': function_arn}
             )
             plan.append(apicall)
Exemple #7
0
 def _delete_sqs_event(self, resource_values):
     # type: (Dict[str, Any]) -> ResourceValueType
     return {
         'instructions': (models.APICall(
             method_name='remove_sqs_event_source',
             params={'event_uuid': resource_values['event_uuid']},
         ), )
     }
Exemple #8
0
 def _delete_cloudwatch_event(self, resource_values):
     # type: (Dict[str, Any]) -> ResourceValueType
     return {
         'instructions': (models.APICall(
             method_name='delete_rule',
             params={'rule_name': resource_values['rule_name']},
         ), )
     }
Exemple #9
0
 def _delete_s3_event(self, resource_values):
     # type: (Dict[str, Any]) -> ResourceValueType
     bucket = resource_values['bucket']
     function_arn = resource_values['lambda_arn']
     return {
         'instructions': (
             models.APICall(method_name='disconnect_s3_bucket_from_lambda',
                            params={
                                'bucket': bucket,
                                'function_arn': function_arn
                            }),
             models.APICall(method_name='remove_permission_for_s3_event',
                            params={
                                'bucket': bucket,
                                'function_arn': function_arn
                            }),
         )
     }
Exemple #10
0
 def _delete_sns_event(self, resource_values):
     # type: (Dict[str, Any]) -> ResourceValueType
     subscription_arn = resource_values['subscription_arn']
     return {
         'instructions': (
             models.APICall(
                 method_name='unsubscribe_from_topic',
                 params={'subscription_arn': subscription_arn},
             ),
             models.APICall(
                 method_name='remove_permission_for_sns_topic',
                 params={
                     'topic_arn': resource_values['topic_arn'],
                     'function_arn': resource_values['lambda_arn'],
                 },
             ),
         )
     }
Exemple #11
0
 def test_can_plan_s3_event(self):
     function = create_function_resource('function_name')
     bucket_event = models.S3BucketNotification(
         resource_name='function_name-s3event',
         bucket='mybucket',
         events=['s3:ObjectCreated:*'],
         prefix=None,
         suffix=None,
         lambda_function=function,
     )
     plan = self.determine_plan(bucket_event)
     self.assert_apicall_equals(
         plan[0],
         models.APICall(
             method_name='add_permission_for_s3_event',
             params={
                 'bucket': 'mybucket',
                 'function_arn': Variable('function_name_lambda_arn'),
             },
         ))
     self.assert_apicall_equals(
         plan[1],
         models.APICall(
             method_name='connect_s3_bucket_to_lambda',
             params={
                 'bucket': 'mybucket',
                 'function_arn': Variable('function_name_lambda_arn'),
                 'events': ['s3:ObjectCreated:*'],
                 'prefix': None,
                 'suffix': None,
             },
         ))
     assert plan[2] == models.RecordResourceValue(
         resource_type='s3_event',
         resource_name='function_name-s3event',
         name='bucket',
         value='mybucket',
     )
     assert plan[3] == models.RecordResourceVariable(
         resource_type='s3_event',
         resource_name='function_name-s3event',
         name='lambda_arn',
         variable_name='function_name_lambda_arn',
     )
Exemple #12
0
    def _create_cloudwatchevent(self, resource):
        # type: (models.CloudWatchEventBase) -> Sequence[InstructionMsg]

        function_arn = Variable('%s_lambda_arn' %
                                resource.lambda_function.resource_name)

        params = {'rule_name': resource.rule_name}
        if isinstance(resource, models.ScheduledEvent):
            resource = cast(models.ScheduledEvent, resource)
            params['schedule_expression'] = resource.schedule_expression
            if resource.rule_description is not None:
                params['rule_description'] = resource.rule_description
        else:
            resource = cast(models.CloudWatchEvent, resource)
            params['event_pattern'] = resource.event_pattern

        plan = [
            models.APICall(
                method_name='get_or_create_rule_arn',
                params=params,
                output_var='rule-arn',
            ),
            models.APICall(method_name='connect_rule_to_lambda',
                           params={
                               'rule_name': resource.rule_name,
                               'function_arn': function_arn
                           }),
            models.APICall(
                method_name='add_permission_for_cloudwatch_event',
                params={
                    'rule_arn': Variable('rule-arn'),
                    'function_arn': function_arn
                },
            ),
            # You need to remove targets (which have IDs)
            # before you can delete a rule.
            models.RecordResourceValue(
                resource_type='cloudwatch_event',
                resource_name=resource.resource_name,
                name='rule_name',
                value=resource.rule_name,
            )
        ]
        return plan
Exemple #13
0
 def _delete_iam_role(self, resource_values):
     # type: (Dict[str, Any]) -> ResourceValueType
     return {
         'instructions': (models.APICall(
             method_name='delete_role',
             params={'name': resource_values['role_name']},
         ), ),
         'message':
         'Deleting IAM role: %s\n' % resource_values['role_name']
     }
Exemple #14
0
 def test_can_plan_scheduled_event(self):
     function = create_function_resource('function_name')
     event = models.ScheduledEvent(
         resource_name='bar',
         rule_name='myrulename',
         schedule_expression='rate(5 minutes)',
         lambda_function=function,
     )
     plan = self.determine_plan(event)
     assert len(plan) == 4
     self.assert_apicall_equals(
         plan[0],
         models.APICall(
             method_name='get_or_create_rule_arn',
             params={
                 'rule_name': 'myrulename',
                 'schedule_expression': 'rate(5 minutes)',
             },
             output_var='rule-arn',
         ))
     self.assert_apicall_equals(
         plan[1],
         models.APICall(method_name='connect_rule_to_lambda',
                        params={
                            'rule_name': 'myrulename',
                            'function_arn':
                            Variable('function_name_lambda_arn')
                        }))
     self.assert_apicall_equals(
         plan[2],
         models.APICall(
             method_name='add_permission_for_scheduled_event',
             params={
                 'rule_arn': Variable('rule-arn'),
                 'function_arn': Variable('function_name_lambda_arn'),
             },
         ))
     assert plan[3] == models.RecordResourceValue(
         resource_type='cloudwatch_event',
         resource_name='bar',
         name='rule_name',
         value='myrulename',
     )
Exemple #15
0
 def _delete_lambda_layer(self, resource_values):
     # type: (Dict[str, str]) -> ResourceValueType
     apicall = models.APICall(
         method_name='delete_layer_version',
         params={'layer_version_arn': resource_values['layer_version_arn']})
     return {
         'instructions': (apicall, ),
         'message': ("Deleting layer version: %s\n" %
                     resource_values['layer_version_arn'])
     }
Exemple #16
0
 def _delete_rest_api(self, resource_values):
     # type: (Dict[str, Any]) -> ResourceValueType
     msg = 'Deleting Rest API: %s\n' % resource_values['rest_api_id']
     return {
         'instructions': (models.APICall(
             method_name='delete_rest_api',
             params={'rest_api_id': resource_values['rest_api_id']}), ),
         'message':
         msg
     }
Exemple #17
0
    def test_can_create_function_with_reserved_concurrency(self):
        function = create_function_resource('function_name')
        function.reserved_concurrency = 5
        self.remote_state.declare_no_resources_exists()
        plan = self.determine_plan(function)
        expected = [
            models.APICall(
                method_name='create_function',
                params={
                    'function_name': 'appname-dev-function_name',
                    'role_arn': 'role:arn',
                    'zip_contents': mock.ANY,
                    'runtime': 'python2.7',
                    'handler': 'app.app',
                    'environment_variables': {},
                    'tags': {},
                    'timeout': 60,
                    'memory_size': 128,
                    'security_group_ids': [],
                    'subnet_ids': [],
                },
            ),
            models.APICall(
                method_name='put_function_concurrency',
                params={
                    'function_name': 'appname-dev-function_name',
                    'reserved_concurrent_executions': 5
                },
                output_var='reserved_concurrency_result',
            )
        ]

        # create_function
        self.assert_apicall_equals(plan[0], expected[0])
        # put_function_concurrency
        self.assert_apicall_equals(plan[2], expected[1])

        assert list(self.last_plan.messages.values()) == [
            'Creating lambda function: appname-dev-function_name\n',
            'Updating lambda function concurrency limit:'
            ' appname-dev-function_name\n',
        ]
Exemple #18
0
 def _delete_s3_event(self, resource_values):
     # type: (Dict[str, Any]) -> ResourceValueType
     bucket = resource_values['bucket']
     function_arn = resource_values['lambda_arn']
     return {
         'instructions': (
             models.BuiltinFunction('parse_arn', [function_arn],
                                    output_var='parsed_lambda_arn'),
             models.JPSearch('account_id', input_var='parsed_lambda_arn',
                             output_var='account_id'),
             models.APICall(
                 method_name='disconnect_s3_bucket_from_lambda',
                 params={'bucket': bucket, 'function_arn': function_arn}
             ),
             models.APICall(
                 method_name='remove_permission_for_s3_event',
                 params={'bucket': bucket, 'function_arn': function_arn,
                         'account_id': Variable('account_id')}
             ),
         )
     }
Exemple #19
0
 def _plan_scheduledevent(self, resource):
     # type: (models.ScheduledEvent) -> Sequence[_INSTRUCTION_MSG]
     function_arn = Variable('%s_lambda_arn' %
                             resource.lambda_function.resource_name)
     # Because the underlying API calls have PUT semantics,
     # we don't have to check if the resource exists and have
     # a separate code path for updates.  We could however
     # check if the resource exists to avoid unnecessary API
     # calls, but that's a later optimization.
     plan = [
         models.APICall(
             method_name='get_or_create_rule_arn',
             params={
                 'rule_name': resource.rule_name,
                 'schedule_expression': resource.schedule_expression
             },
             output_var='rule-arn',
         ),
         models.APICall(method_name='connect_rule_to_lambda',
                        params={
                            'rule_name': resource.rule_name,
                            'function_arn': function_arn
                        }),
         models.APICall(
             method_name='add_permission_for_scheduled_event',
             params={
                 'rule_arn': Variable('rule-arn'),
                 'function_arn': function_arn
             },
         ),
         # You need to remote targets (which have IDs)
         # before you can delete a rule.
         models.RecordResourceValue(
             resource_type='cloudwatch_event',
             resource_name=resource.resource_name,
             name='rule_name',
             value=resource.rule_name,
         )
     ]
     return plan
Exemple #20
0
 def _delete_lambda_function(self,
                             resource_values  # type: Dict[str, Any]
                             ):
     # type: (...) -> ResourceValueType
     msg = 'Deleting function: %s\n' % resource_values['lambda_arn']
     return {
         'instructions': (
             models.APICall(
                 method_name='delete_function',
                 params={'function_name': resource_values['lambda_arn']},
             ),
         ),
         'message': msg
     }
Exemple #21
0
 def _create_route_for_key(self, route_key):
     # type: (str) -> models.APICall
     integration_id = {
         '$connect': 'connect-integration-id',
         '$disconnect': 'disconnect-integration-id',
     }.get(route_key, 'message-integration-id')
     return models.APICall(
         method_name='create_websocket_route',
         params={
             'api_id': Variable('websocket_api_id'),
             'route_key': route_key,
             'integration_id': Variable(integration_id),
         },
     )
Exemple #22
0
 def _delete_domain_name(
         self,
         resource_values  # type: Dict[str, Any]
 ):
     # type: (...) -> ResourceValueType
     params = {'domain_name': resource_values['domain_name']}
     msg = 'Deleting custom domain name: %s\n' % resource_values['name']
     return {
         'instructions': (models.APICall(
             method_name='delete_domain_name',
             params=params,
         ), ),
         'message':
         msg
     }
Exemple #23
0
 def test_can_delete_rest_api(self):
     plan = []
     deployed = {
         'resources': [{
             'name': 'rest_api',
             'rest_api_id': 'my_rest_api_id',
             'resource_type': 'rest_api',
         }]
     }
     config = FakeConfig(deployed)
     self.execute(plan, config)
     assert plan == [
         models.APICall(
             method_name='delete_rest_api',
             params={'rest_api_id': 'my_rest_api_id'},
         )
     ]
Exemple #24
0
 def test_can_delete_scheduled_event(self):
     plan = []
     deployed = {
         'resources': [{
             'name': 'index-event',
             'resource_type': 'cloudwatch_event',
             'rule_name': 'app-dev-index-event',
         }]
     }
     config = FakeConfig(deployed)
     self.execute(plan, config)
     assert plan == [
         models.APICall(
             method_name='delete_rule',
             params={'rule_name': 'app-dev-index-event'},
         )
     ]
Exemple #25
0
 def test_can_delete_s3_event(self):
     plan = []
     deployed = {
         'resources': [{
             'name': 'test-s3-event',
             'resource_type': 's3_event',
             'bucket': 'mybucket',
             'lambda_arn': 'lambda_arn',
         }]
     }
     config = FakeConfig(deployed)
     self.execute(plan, config)
     assert plan == [
         models.APICall(
             method_name='disconnect_s3_bucket_from_lambda',
             params={
                 'bucket': 'mybucket',
                 'function_arn': 'lambda_arn'
             },
         )
     ]
Exemple #26
0
 def test_can_create_function(self):
     function = create_function_resource('function_name')
     self.remote_state.declare_no_resources_exists()
     plan = self.determine_plan(function)
     expected = models.APICall(
         method_name='create_function',
         params={
             'function_name': 'appname-dev-function_name',
             'role_arn': 'role:arn',
             'zip_contents': mock.ANY,
             'runtime': 'python2.7',
             'handler': 'app.app',
             'environment_variables': {},
             'tags': {},
             'timeout': 60,
             'memory_size': 128,
         },
     )
     self.assert_apicall_equals(plan[0], expected)
     assert list(self.last_plan.messages.values()) == [
         'Creating lambda function: appname-dev-function_name\n'
     ]
Exemple #27
0
 def test_can_update_file_based_policy(self):
     role = models.ManagedIAMRole(
         resource_name='resource_name',
         role_name='myrole',
         trust_policy={},
         policy=models.FileBasedIAMPolicy(filename='foo.json',
                                          document={'iam': 'policy'}),
     )
     self.remote_state.declare_resource_exists(role, role_arn='myrole:arn')
     plan = self.determine_plan(role)
     assert plan[0] == models.StoreValue(name='myrole_role_arn',
                                         value='myrole:arn')
     self.assert_apicall_equals(
         plan[1],
         models.APICall(
             method_name='put_role_policy',
             params={
                 'role_name': 'myrole',
                 'policy_name': 'myrole',
                 'policy_document': {
                     'iam': 'policy'
                 }
             },
         ))
Exemple #28
0
    def _plan_websocketapi(self, resource):
        # type: (models.WebsocketAPI) -> Sequence[InstructionMsg]
        configs = self._create_websocket_function_configs(resource)
        routes = resource.routes

        # Which lambda function we use here does not matter. We are only using
        # it to find the account id and the region.
        lambda_arn_var = list(configs.values())[0]['lambda_arn_var']
        shared_plan_preamble = [
            # The various API gateway API calls need
            # to know the region name and account id so
            # we'll take care of that up front and store
            # them in variables.
            models.BuiltinFunction(
                'parse_arn',
                [lambda_arn_var],
                output_var='parsed_lambda_arn',
            ),
            models.JPSearch('account_id',
                            input_var='parsed_lambda_arn',
                            output_var='account_id'),
            models.JPSearch('region',
                            input_var='parsed_lambda_arn',
                            output_var='region_name'),
        ]  # type: List[InstructionMsg]

        # There's also a set of instructions that are needed
        # at the end of deploying a websocket API that apply to both
        # the update and create case.
        shared_plan_epilogue = [
            models.StoreValue(
                name='websocket_api_url',
                value=StringFormat(
                    'wss://{websocket_api_id}.execute-api.{region_name}'
                    '.amazonaws.com/%s/' % resource.api_gateway_stage,
                    ['websocket_api_id', 'region_name'],
                ),
            ),
            models.RecordResourceVariable(
                resource_type='websocket_api',
                resource_name=resource.resource_name,
                name='websocket_api_url',
                variable_name='websocket_api_url',
            ),
            models.RecordResourceVariable(
                resource_type='websocket_api',
                resource_name=resource.resource_name,
                name='websocket_api_id',
                variable_name='websocket_api_id',
            ),
        ]  # type: List[InstructionMsg]

        shared_plan_epilogue += [
            models.APICall(
                method_name='add_permission_for_apigateway_v2',
                params={
                    'function_name': function_config['name'],
                    'region_name': Variable('region_name'),
                    'account_id': Variable('account_id'),
                    'api_id': Variable('websocket_api_id')
                },
            ) for function_config in configs.values()
        ]

        main_plan = []  # type: List[InstructionMsg]
        if not self._remote_state.resource_exists(resource):
            # The resource does not exist, we create it in full here.
            main_plan += [
                (models.APICall(
                    method_name='create_websocket_api',
                    params={'name': resource.name},
                    output_var='websocket_api_id',
                ), "Creating websocket api: %s\n" % resource.name),
                models.StoreValue(
                    name='routes',
                    value=[],
                ),
            ]
            main_plan += self._inject_websocket_integrations(configs)

            for route_key in routes:
                main_plan += [self._create_route_for_key(route_key)]
            main_plan += [
                models.APICall(
                    method_name='deploy_websocket_api',
                    params={
                        'api_id': Variable('websocket_api_id'),
                    },
                    output_var='deployment-id',
                ),
                models.APICall(method_name='create_stage',
                               params={
                                   'api_id': Variable('websocket_api_id'),
                                   'stage_name': resource.api_gateway_stage,
                                   'deployment_id': Variable('deployment-id'),
                               }),
            ]
        else:
            # Already exists. Need to sync up the routes, the easiest way to do
            # this is to delete them and their integrations and re-create them.
            # They will not work if the lambda function changes from under
            # them, and the logic for detecting that and making just the needed
            # changes is complex. There is an integration test to ensure there
            # no dropped messages during a redeployment.
            deployed = self._remote_state.resource_deployed_values(resource)
            main_plan += [
                models.StoreValue(name='websocket_api_id',
                                  value=deployed['websocket_api_id']),
                models.APICall(
                    method_name='get_websocket_routes',
                    params={'api_id': Variable('websocket_api_id')},
                    output_var='routes',
                ),
                models.APICall(
                    method_name='delete_websocket_routes',
                    params={
                        'api_id': Variable('websocket_api_id'),
                        'routes': Variable('routes'),
                    },
                ),
                models.APICall(method_name='get_websocket_integrations',
                               params={
                                   'api_id': Variable('websocket_api_id'),
                               },
                               output_var='integrations'),
                models.APICall(method_name='delete_websocket_integrations',
                               params={
                                   'api_id': Variable('websocket_api_id'),
                                   'integrations': Variable('integrations'),
                               })
            ]
            main_plan += self._inject_websocket_integrations(configs)
            for route_key in routes:
                main_plan += [self._create_route_for_key(route_key)]
        return shared_plan_preamble + main_plan + shared_plan_epilogue
Exemple #29
0
    def _plan_restapi(self, resource):
        # type: (models.RestAPI) -> Sequence[InstructionMsg]
        function = resource.lambda_function
        function_name = function.function_name
        varname = '%s_lambda_arn' % function.resource_name
        lambda_arn_var = Variable(varname)
        # There's a set of shared instructions that are needed
        # in both the update as well as the initial create case.
        # That's what this shared_plan_premable is for.
        shared_plan_preamble = [
            # The various API gateway API calls need
            # to know the region name and account id so
            # we'll take care of that up front and store
            # them in variables.
            models.BuiltinFunction(
                'parse_arn',
                [lambda_arn_var],
                output_var='parsed_lambda_arn',
            ),
            models.JPSearch('account_id',
                            input_var='parsed_lambda_arn',
                            output_var='account_id'),
            models.JPSearch('region',
                            input_var='parsed_lambda_arn',
                            output_var='region_name'),
            # The swagger doc uses the 'api_handler_lambda_arn'
            # var name so we need to make sure we populate this variable
            # before importing the rest API.
            models.CopyVariable(from_var=varname,
                                to_var='api_handler_lambda_arn'),
        ]  # type: List[InstructionMsg]
        # There's also a set of instructions that are needed
        # at the end of deploying a rest API that apply to both
        # the update and create case.
        shared_plan_patch_ops = [{
            'op': 'replace',
            'path': '/minimumCompressionSize',
            'value': resource.minimum_compression
        }]  # type: List[Dict]

        shared_plan_epilogue = [
            models.APICall(method_name='update_rest_api',
                           params={
                               'rest_api_id': Variable('rest_api_id'),
                               'patch_operations': shared_plan_patch_ops
                           }),
            models.APICall(
                method_name='add_permission_for_apigateway',
                params={
                    'function_name': function_name,
                    'region_name': Variable('region_name'),
                    'account_id': Variable('account_id'),
                    'rest_api_id': Variable('rest_api_id')
                },
            ),
            models.APICall(
                method_name='deploy_rest_api',
                params={
                    'rest_api_id': Variable('rest_api_id'),
                    'api_gateway_stage': resource.api_gateway_stage
                },
            ),
            models.StoreValue(
                name='rest_api_url',
                value=StringFormat(
                    'https://{rest_api_id}.execute-api.{region_name}'
                    '.amazonaws.com/%s/' % resource.api_gateway_stage,
                    ['rest_api_id', 'region_name'],
                ),
            ),
            models.RecordResourceVariable(
                resource_type='rest_api',
                resource_name=resource.resource_name,
                name='rest_api_url',
                variable_name='rest_api_url',
            ),
        ]  # type: List[InstructionMsg]
        for auth in resource.authorizers:
            shared_plan_epilogue.append(
                models.APICall(
                    method_name='add_permission_for_apigateway',
                    params={
                        'function_name': auth.function_name,
                        'region_name': Variable('region_name'),
                        'account_id': Variable('account_id'),
                        'rest_api_id': Variable('rest_api_id')
                    },
                ))
        if not self._remote_state.resource_exists(resource):
            plan = shared_plan_preamble + [
                (models.APICall(
                    method_name='import_rest_api',
                    params={
                        'swagger_document': resource.swagger_doc,
                        'endpoint_type': resource.endpoint_type
                    },
                    output_var='rest_api_id',
                ), "Creating Rest API\n"),
                models.RecordResourceVariable(
                    resource_type='rest_api',
                    resource_name=resource.resource_name,
                    name='rest_api_id',
                    variable_name='rest_api_id',
                ),
            ]
        else:
            deployed = self._remote_state.resource_deployed_values(resource)
            shared_plan_epilogue.insert(
                0,
                models.APICall(method_name='get_rest_api',
                               params={'rest_api_id': Variable('rest_api_id')},
                               output_var='rest_api'))
            shared_plan_patch_ops.append({
                'op':
                'replace',
                'path':
                StringFormat(
                    '/endpointConfiguration/types/%s' %
                    ('{rest_api[endpointConfiguration][types][0]}'),
                    ['rest_api']),
                'value':
                resource.endpoint_type
            })
            plan = shared_plan_preamble + [
                models.StoreValue(name='rest_api_id',
                                  value=deployed['rest_api_id']),
                models.RecordResourceVariable(
                    resource_type='rest_api',
                    resource_name=resource.resource_name,
                    name='rest_api_id',
                    variable_name='rest_api_id',
                ),
                (models.APICall(
                    method_name='update_api_from_swagger',
                    params={
                        'rest_api_id': Variable('rest_api_id'),
                        'swagger_document': resource.swagger_doc,
                    },
                ), "Updating rest API\n"),
            ]

        plan.extend(shared_plan_epilogue)
        return plan
Exemple #30
0
 def _plan_sqseventsource(self, resource):
     # type: (models.SQSEventSource) -> Sequence[InstructionMsg]
     queue_arn_varname = '%s_queue_arn' % resource.resource_name
     uuid_varname = '%s_uuid' % resource.resource_name
     function_arn = Variable('%s_lambda_arn' %
                             resource.lambda_function.resource_name)
     instruction_for_queue_arn = [
         models.BuiltinFunction(
             'parse_arn',
             [function_arn],
             output_var='parsed_lambda_arn',
         ),
         models.JPSearch('account_id',
                         input_var='parsed_lambda_arn',
                         output_var='account_id'),
         models.JPSearch('region',
                         input_var='parsed_lambda_arn',
                         output_var='region_name'),
         models.StoreValue(
             name=queue_arn_varname,
             value=StringFormat(
                 'arn:aws:sqs:{region_name}:{account_id}:%s' %
                 (resource.queue),
                 ['region_name', 'account_id'],
             ),
         ),
     ]  # type: List[InstructionMsg]
     if self._remote_state.resource_exists(resource):
         deployed = self._remote_state.resource_deployed_values(resource)
         uuid = deployed['event_uuid']
         return instruction_for_queue_arn + [
             models.APICall(method_name='update_sqs_event_source',
                            params={
                                'event_uuid': uuid,
                                'batch_size': resource.batch_size
                            }),
             models.RecordResourceValue(
                 resource_type='sqs_event',
                 resource_name=resource.resource_name,
                 name='queue_arn',
                 value=deployed['queue_arn'],
             ),
             models.RecordResourceValue(
                 resource_type='sqs_event',
                 resource_name=resource.resource_name,
                 name='event_uuid',
                 value=uuid,
             ),
             models.RecordResourceValue(
                 resource_type='sqs_event',
                 resource_name=resource.resource_name,
                 name='queue',
                 value=resource.queue,
             ),
             models.RecordResourceValue(
                 resource_type='sqs_event',
                 resource_name=resource.resource_name,
                 name='lambda_arn',
                 value=deployed['lambda_arn'],
             ),
         ]
     return instruction_for_queue_arn + [
         (models.APICall(
             method_name='create_sqs_event_source',
             params={
                 'queue_arn': Variable(queue_arn_varname),
                 'batch_size': resource.batch_size,
                 'function_name': function_arn
             },
             output_var=uuid_varname,
         ), 'Subscribing %s to SQS queue %s\n' %
          (resource.lambda_function.function_name, resource.queue)),
         models.RecordResourceVariable(
             resource_type='sqs_event',
             resource_name=resource.resource_name,
             name='queue_arn',
             variable_name=queue_arn_varname,
         ),
         # We record this because this is what's used to unsubscribe
         # lambda to the SQS queue.
         models.RecordResourceVariable(
             resource_type='sqs_event',
             resource_name=resource.resource_name,
             name='event_uuid',
             variable_name=uuid_varname,
         ),
         models.RecordResourceValue(
             resource_type='sqs_event',
             resource_name=resource.resource_name,
             name='queue',
             value=resource.queue,
         ),
         models.RecordResourceVariable(
             resource_type='sqs_event',
             resource_name=resource.resource_name,
             name='lambda_arn',
             variable_name=function_arn.name,
         ),
     ]