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' ]
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' ]
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' ]
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
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 }
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)
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']}, ), ) }
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']}, ), ) }
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 }), ) }
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'], }, ), ) }
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', )
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
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'] }
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', )
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']) }
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 }
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', ]
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')} ), ) }
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
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 }
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), }, )
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 }
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'}, ) ]
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'}, ) ]
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' }, ) ]
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' ]
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' } }, ))
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
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
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, ), ]