Moto: CloudFormation trigger lambda via SQS

Created on 5 Feb 2019  路  6Comments  路  Source: spulec/moto

I am attempting to use moto 1.3.7 (via serverless / localstack) to create a lambda that is triggered by SQS. When I tried to deploy I got the following stack trace

File ".venv/lib/python3.6/site-packages/werkzeug/serving.py", line 270, in run_wsgi
execute(self.server.app)
File ".venv/lib/python3.6/site-packages/werkzeug/serving.py", line 258, in execute
application_iter = app(environ, start_response)
File ".venv/lib/python3.6/site-packages/moto/server.py", line 101, in __call__
return backend_app(environ, start_response)
File ".venv/lib/python3.6/site-packages/flask/app.py", line 1997, in __call__
return self.wsgi_app(environ, start_response)
File ".venv/lib/python3.6/site-packages/flask/app.py", line 1985, in wsgi_app
response = self.handle_exception(e)
File ".venv/lib/python3.6/site-packages/flask/app.py", line 1540, in handle_exception
reraise(exc_type, exc_value, tb)
File ".venv/lib/python3.6/site-packages/flask/_compat.py", line 33, in reraise
raise value
File ".venv/lib/python3.6/site-packages/flask/app.py", line 1982, in wsgi_app
response = self.full_dispatch_request()
File ".venv/lib/python3.6/site-packages/flask/app.py", line 1614, in full_dispatch_request
rv = self.handle_user_exception(e)
File ".venv/lib/python3.6/site-packages/flask/app.py", line 1517, in handle_user_exception
reraise(exc_type, exc_value, tb)
File ".venv/lib/python3.6/site-packages/flask/_compat.py", line 33, in reraise
raise value
File ".venv/lib/python3.6/site-packages/flask/app.py", line 1612, in full_dispatch_request
rv = self.dispatch_request()
File ".venv/lib/python3.6/site-packages/flask/app.py", line 1598, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File ".venv/lib/python3.6/site-packages/moto/core/utils.py", line 140, in __call__
result = self.callback(request, request.url, {})
File ".venv/lib/python3.6/site-packages/moto/core/responses.py", line 117, in dispatch
return cls()._dispatch(*args, **kwargs)
File ".venv/lib/python3.6/site-packages/moto/core/responses.py", line 200, in _dispatch
return self.call_action()
File ".venv/lib/python3.6/site-packages/moto/core/responses.py", line 274, in call_action
response = method()
File ".venv/lib/python3.6/site-packages/moto/cloudformation/responses.py", line 262, in update_stack
tags=tags,
File ".venv/lib/python3.6/site-packages/moto/cloudformation/models.py", line 241, in update_stack
stack.update(template, role_arn, parameters=parameters, tags=tags)
File ".venv/lib/python3.6/site-packages/moto/cloudformation/models.py", line 111, in update
self.resource_map.update(self.template_dict, parameters)
File ".venv/lib/python3.6/site-packages/moto/cloudformation/parsing.py", line 483, in update
resource_name, resource_json, self, self._region_name)
File ".venv/lib/python3.6/site-packages/moto/cloudformation/parsing.py", line 299, in parse_and_create_resource
resource_name, resource_json, region_name)
File ".venv/lib/python3.6/site-packages/moto/awslambda/models.py", line 445, in create_from_cloudformation_json
'StartingPosition': properties['StartingPosition']
KeyError: 'StartingPosition'

The CloudFormation JSON being deployed is

{
   "AWSTemplateFormatVersion":"2010-09-09",
   "Description":"The AWS CloudFormation template for this Serverless application",
   "Resources":{
      "ServerlessDeploymentBucket":{
         "Type":"AWS::S3::Bucket"
      },
      "HelloLogGroup":{
         "Type":"AWS::Logs::LogGroup",
         "Properties":{
            "LogGroupName":"/aws/lambda/localstack-poc-hello"
         }
      },
      "IamRoleLambdaExecution":{
         "Type":"AWS::IAM::Role",
         "Properties":{
            "AssumeRolePolicyDocument":{
               "Version":"2012-10-17",
               "Statement":[
                  {
                     "Effect":"Allow",
                     "Principal":{
                        "Service":[
                           "lambda.amazonaws.com"
                        ]
                     },
                     "Action":[
                        "sts:AssumeRole"
                     ]
                  }
               ]
            },
            "Policies":[
               {
                  "PolicyName":{
                     "Fn::Join":[
                        "-",
                        [
                           "local",
                           "localstack-poc",
                           "lambda"
                        ]
                     ]
                  },
                  "PolicyDocument":{
                     "Version":"2012-10-17",
                     "Statement":[
                        {
                           "Effect":"Allow",
                           "Action":[
                              "logs:CreateLogStream"
                           ],
                           "Resource":[
                              {
                                 "Fn::Sub":"arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/localstack-poc-hello:*"
                              }
                           ]
                        },
                        {
                           "Effect":"Allow",
                           "Action":[
                              "logs:PutLogEvents"
                           ],
                           "Resource":[
                              {
                                 "Fn::Sub":"arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/localstack-poc-hello:*:*"
                              }
                           ]
                        },
                        {
                           "Effect":"Allow",
                           "Action":[
                              "sqs:ReceiveMessage",
                              "sqs:DeleteMessage",
                              "sqs:GetQueueAttributes"
                           ],
                           "Resource":[
                              {
                                 "Fn::GetAtt":[
                                    "MyQueue",
                                    "Arn"
                                 ]
                              }
                           ]
                        }
                     ]
                  }
               }
            ],
            "Path":"/",
            "RoleName":{
               "Fn::Join":[
                  "-",
                  [
                     "localstack-poc",
                     "local",
                     "us-east-1",
                     "lambdaRole"
                  ]
               ]
            }
         }
      },
      "HelloLambdaFunction":{
         "Type":"AWS::Lambda::Function",
         "Properties":{
            "Code":{
               "S3Bucket":{
                  "Ref":"ServerlessDeploymentBucket"
               },
               "S3Key":"serverless/localstack-poc/local/1549333110291-2019-02-05T02:18:30.291Z/localstack-poc.zip"
            },
            "FunctionName":"localstack-poc-hello",
            "Handler":"handler.hello",
            "MemorySize":1024,
            "Role":{
               "Fn::GetAtt":[
                  "IamRoleLambdaExecution",
                  "Arn"
               ]
            },
            "Runtime":"python3.6",
            "Timeout":6
         },
         "DependsOn":[
            "HelloLogGroup",
            "IamRoleLambdaExecution"
         ]
      },
      "HelloLambdaVersion7lxGKanE5nEnf91l0NuzeIbvYDLEqsyG73dMlYvIOGY":{
         "Type":"AWS::Lambda::Version",
         "DeletionPolicy":"Retain",
         "Properties":{
            "FunctionName":{
               "Ref":"HelloLambdaFunction"
            },
            "CodeSha256":"6Mjv7NuUsRtLWrD6YhKZey2t4KM62BnZ+B8R5Ny/5ZY="
         }
      },
      "HelloEventSourceMappingSQSMyQueue":{
         "Type":"AWS::Lambda::EventSourceMapping",
         "DependsOn":"IamRoleLambdaExecution",
         "Properties":{
            "BatchSize":10,
            "EventSourceArn":{
               "Fn::GetAtt":[
                  "MyQueue",
                  "Arn"
               ]
            },
            "FunctionName":{
               "Fn::GetAtt":[
                  "HelloLambdaFunction",
                  "Arn"
               ]
            },
            "Enabled":"True"
         }
      },
      "MyQueue":{
         "Type":"AWS::SQS::Queue",
         "Properties":{
            "QueueName":"localstack-poc-queue"
         }
      }
   },
   "Outputs":{
      "ServerlessDeploymentBucketName":{
         "Value":{
            "Ref":"ServerlessDeploymentBucket"
         }
      },
      "HelloLambdaFunctionQualifiedArn":{
         "Description":"Current Lambda function version",
         "Value":{
            "Ref":"HelloLambdaVersion7lxGKanE5nEnf91l0NuzeIbvYDLEqsyG73dMlYvIOGY"
         }
      }
   }
}

As per https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-eventsourcemapping.html, StartingPosition is only required for Kineses an DynamoDB Streams. Is it possible to modify the code to make StartingPosition optional? I have done this on my local moto deployment and successfully deployed the CloudFormation JSON above. I am happy to create a pull request.

enhancement

Most helpful comment

Thanks; it looks like we don't support this right now. I'm going to set it as a feature request.

All 6 comments

@jaygelman could you please either submit a PR or share the way you patched this? I'm in the same exact spot, where I'm using serverless with a Lambda+SQS, and having the exact same failure from CloudFormation.

@FnTm Change /opt/code/localstack/.venv/lib/python2.7/site-packages/moto/awslambda/models.py by modifying classEventSourceMapping's create_from_cloudformation_json and __init__ :

    def __init__(self, spec):
        # required
        self.function_name = spec['FunctionName']
        self.event_source_arn = spec['EventSourceArn']
        self.starting_position = spec.get('StartingPosition', 'LATEST')

        # optional
        self.batch_size = spec.get('BatchSize', 100)
        self.enabled = spec.get('Enabled', True)
        self.starting_position_timestamp = spec.get('StartingPositionTimestamp',
                                                    None)

    @classmethod
    def create_from_cloudformation_json(cls, resource_name, cloudformation_json,
                                        region_name):
        properties = cloudformation_json['Properties']
        spec = {
            'FunctionName': properties['FunctionName'],
            'EventSourceArn': properties['EventSourceArn']
        }
        optional_properties = 'BatchSize Enabled StartingPositionTimestamp'.split()
        for prop in optional_properties:
            if prop in properties:
                spec[prop] = properties[prop]
        return EventSourceMapping(spec)

Thanks; it looks like we don't support this right now. I'm going to set it as a feature request.

Bump, please! I need this fix. :)

I'm assuming that this will be fixed in #2376

Closing this - #2376 should now be included in 1.3.14
Feel free to open a new issue if something are still missing

Was this page helpful?
0 / 5 - 0 ratings