def _plan_managediamrole(self, resource): # type: (models.ManagedIAMRole) -> Sequence[InstructionMsg] document = resource.policy.document role_exists = self._remote_state.resource_exists(resource) varname = '%s_role_arn' % resource.role_name if not role_exists: return [(models.APICall( method_name='create_role', params={ 'name': resource.role_name, 'trust_policy': resource.trust_policy, 'policy': document }, output_var=varname, ), "Creating IAM role: %s\n" % resource.role_name), models.RecordResourceVariable( resource_type='iam_role', resource_name=resource.resource_name, name='role_arn', variable_name=varname, ), models.RecordResourceValue( resource_type='iam_role', resource_name=resource.resource_name, name='role_name', value=resource.role_name, )] role_arn = self._remote_state.resource_deployed_values( resource)['role_arn'] return [ models.StoreValue(name=varname, value=role_arn), (models.APICall( method_name='put_role_policy', params={ 'role_name': resource.role_name, 'policy_name': resource.role_name, 'policy_document': document }, ), "Updating policy for IAM role: %s\n" % resource.role_name), models.RecordResourceVariable( resource_type='iam_role', resource_name=resource.resource_name, name='role_arn', variable_name=varname, ), models.RecordResourceValue( resource_type='iam_role', resource_name=resource.resource_name, name='role_name', value=resource.role_name, ) ]
def _plan_s3bucketnotification(self, resource): # type: (models.S3BucketNotification) -> Sequence[InstructionMsg] function_arn = Variable('%s_lambda_arn' % resource.lambda_function.resource_name) return [ models.APICall( method_name='add_permission_for_s3_event', params={ 'bucket': resource.bucket, 'function_arn': function_arn }, ), (models.APICall(method_name='connect_s3_bucket_to_lambda', params={ 'bucket': resource.bucket, 'function_arn': function_arn, 'prefix': resource.prefix, 'suffix': resource.suffix, 'events': resource.events }), 'Configuring S3 events in bucket %s to function %s\n' % (resource.bucket, resource.lambda_function.function_name)), models.RecordResourceValue( resource_type='s3_event', resource_name=resource.resource_name, name='bucket', value=resource.bucket, ), models.RecordResourceVariable( resource_type='s3_event', resource_name=resource.resource_name, name='lambda_arn', variable_name=function_arn.name, ), ]
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 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 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 _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 _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, ), ]
def _plan_snslambdasubscription(self, resource): # type: (models.SNSLambdaSubscription) -> Sequence[InstructionMsg] function_arn = Variable('%s_lambda_arn' % resource.lambda_function.resource_name) topic_arn_varname = '%s_topic_arn' % resource.resource_name subscribe_varname = '%s_subscription_arn' % resource.resource_name instruction_for_topic_arn = [] # type: List[InstructionMsg] if resource.topic.startswith('arn:aws:sns:'): instruction_for_topic_arn += [ models.StoreValue( name=topic_arn_varname, value=resource.topic, ) ] else: # To keep the user API simple, we only require the topic # name and not the ARN. However, the APIs require the topic # ARN so we need to reconstruct it here in the planner. instruction_for_topic_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=topic_arn_varname, value=StringFormat( 'arn:aws:sns:{region_name}:{account_id}:%s' % (resource.topic), ['region_name', 'account_id'], ), ), ] if self._remote_state.resource_exists(resource): # Given there's nothing about an SNS subscription you can # configure for now, if the resource exists, we don't do # anything. The resource sweeper will verify that if the # subscription doesn't actually apply that we should unsubscribe # from the topic. deployed = self._remote_state.resource_deployed_values(resource) subscription_arn = deployed['subscription_arn'] return instruction_for_topic_arn + [ models.RecordResourceValue( resource_type='sns_event', resource_name=resource.resource_name, name='topic', value=resource.topic, ), models.RecordResourceVariable( resource_type='sns_event', resource_name=resource.resource_name, name='lambda_arn', variable_name=function_arn.name, ), models.RecordResourceValue( resource_type='sns_event', resource_name=resource.resource_name, name='subscription_arn', value=subscription_arn, ), models.RecordResourceVariable( resource_type='sns_event', resource_name=resource.resource_name, name='topic_arn', variable_name=topic_arn_varname, ), ] return instruction_for_topic_arn + [ models.APICall( method_name='add_permission_for_sns_topic', params={ 'topic_arn': Variable(topic_arn_varname), 'function_arn': function_arn }, ), (models.APICall( method_name='subscribe_function_to_topic', params={ 'topic_arn': Variable(topic_arn_varname), 'function_arn': function_arn }, output_var=subscribe_varname, ), 'Subscribing %s to SNS topic %s\n' % (resource.lambda_function.function_name, resource.topic)), models.RecordResourceValue( resource_type='sns_event', resource_name=resource.resource_name, name='topic', value=resource.topic, ), models.RecordResourceVariable( resource_type='sns_event', resource_name=resource.resource_name, name='lambda_arn', variable_name=function_arn.name, ), models.RecordResourceVariable( resource_type='sns_event', resource_name=resource.resource_name, name='subscription_arn', variable_name=subscribe_varname, ), models.RecordResourceVariable( resource_type='sns_event', resource_name=resource.resource_name, name='topic_arn', variable_name=topic_arn_varname, ), ]