需要在 YAML 中将 lambda 函数 (python) 加入 CloudFormation 模板,我该如何实现?

问题描述

我一直在尝试将 lambda 嵌入到这个 CF 模板中。 Lambda 是在 Python 和 CF 上用 YAML 编码的,我很难将 lambda 转换为 Yaml。

这里的一点帮助将不胜感激。我需要将 lambda 添加到 CF 模板。任何解释也将很有用。

AWstemplateFormatVersion: 2010-09-09
Description: CH CloudFormation template for Deploy and Init of DynamoDB Table
Parameters:
  dbTableName:
    Type: String
    Default: ClientOrders
    Description: Enter the name used for DynamoDB Table
  phoneNumber:
    Type: String
    Default: 1115551111
    Description: Enter your phone number

Resources:
  OrdersTable:
    Type: 'AWS::DynamoDB::Table'
    Properties:
      TableName: !Ref dbTableName # !Join [ "-",[ !Ref "AWS::StackName",!Ref dbTableName ] ]
      AttributeDeFinitions:
        - AttributeName: PhoneNumber
          AttributeType: S
        - AttributeName: OrderNumber
          AttributeType: S
      KeySchema:
        - AttributeName: PhoneNumber
          KeyType: HASH
        - AttributeName: OrderNumber
          KeyType: RANGE
      TimetoLiveSpecification:
        AttributeName: ExpirationTime
        Enabled: true
      ProvisionedThroughput:
        ReadCapacityUnits: '10'
        WriteCapacityUnits: '5'
    DependsOn:
      - DynamoDBQueryPolicy
  DynamoDBQueryPolicy:
    Type: 'AWS::IAM::Policy'
    Properties:
      PolicyName: DynamoDBQueryPolicy
      PolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Action: 'dynamodb:*'
            Resource: '*'
      Roles:
        - !Ref OrdersTableQueryRole
  OrdersTableQueryRole:
    Type: 'AWS::IAM::Role'
    Properties:
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - dynamodb.amazonaws.com
                - lambda.amazonaws.com
            Action:
              - 'sts:AssumeRole'
      Path: /

  phoneRecord:
    DependsOn:
      - OrdersTable
    Type: 'Custom::CrtUpdDltDynamodbDocumentLambda'
    Properties:
      Servicetoken: !GetAtt dynamoSetupLambda.Arn
      DynamoTableName: !Ref dbTableName # !Join [ "-",!Ref dbTableName ] ]
      # DynamoKeyProperty: PhoneNumber
      DynamoItem: !Sub |
        [{
          "PhoneNumber": "784578745","OrderNumber": "11547854","someKey": "someValue"
        },{
          "PhoneNumber": "${phoneNumber}","OrderNumber": "11545154","someKey": "someValue"
        }]
  dynamoSetupLambda:
    Type: AWS::Lambda::Function
    Properties:
      Description: custom resource function invoked for intitial configuration of dynamodb
      Handler: index.lambda_handler
      Timeout: 300
      MemorySize: 128
      Role: !GetAtt 'OrdersTableQueryRole.Arn'
      Runtime: python3.8
      Code:
        ZipFile: |
          import json,boto3,os,threading,logging
          import cfnresponse
          def setup_stack(tableName,dynamoItems):
              dynamodb_client = boto3.resource("dynamodb",region_name=os.environ['AWS_REGION'])
              try:
                  dynamodb_client_table = dynamodb_client.Table(tableName)
                  with dynamodb_client_table.batch_writer() as batch:
                      for message in dynamoItems:
                          batch.put_item(
                              Item=message
                          )
              except Exception as exc:
                  print(exc)
          # def remove_stack(tableName): # will need to clear maybe?
          #     dynamodb_client = boto3.resource(tableName,region_name=os.environ['AWS_REGION'])
          #     dynamodb_client_table = dynamodb_client.Table(table_name)
          #     continue
          def timeout(event,context):
              logging.error('Execution is about to time out,sending failure response to CloudFormation')
              cfnresponse.send(event,context,cfnresponse.Failed,{},None)
          def lambda_handler(event,context):
              print('Received event: %s' % json.dumps(event))
              # make sure we send a failure to CloudFormation if the function is going to timeout
              timer = threading.Timer((context.get_remaining_time_in_millis()
                      / 1000.00) - 0.5,timeout,args=[event,context])
              timer.start()
              
              status = cfnresponse.SUCCESS
              try:
                  dynamoItems = event['ResourceProperties']['DynamoItem']
                  dynamoTable = event['ResourceProperties']['DynamoTableName']
                  if event['RequestType'] == 'Delete':
                      print("Not going to remvove yet")
                      # remove_stack(dynamoTable)
                  else:
                      setup_stack(dynamoTable,json.loads(dynamoItems))
              except Exception as e:
                  logging.error('Exception: %s' % e,exc_info=True)
                  status = cfnresponse.Failed
              finally:
                  timer.cancel()
                  cfnresponse.send(event,status,None)

Lambda:

    from __future__ import print_function
import boto3
from boto3.dynamodb.conditions import Key,Attr
import json
dynamodb = boto3.resource('dynamodb')

def lambda_handler(event,context):
    #print(event)
    PhoneNumber=event['Details']['ContactData']['Attributes'].get('PhoneNumber',"Not Available")
    table = dynamodb.Table('ClientOrders')
    try:
      response = table.query(
        KeyConditionExpression=Key('PhoneNumber').eq(PhoneNumber)
        )
    except ClientError as e:
        print(e.response['Error']['Message'])
        return {
                "Success":"False","Reason":e.response['Error']['Message']
               }
    else:
        #item = response['Item']
        print("GetItem succeeded:")
        print(json.dumps(response))
        print(response['Items'])
        if "Items" in response:
            return{
                "Success":"True","PhoneNumber":response["Items"][0]["PhoneNumber"]
                }
        else:
            return {
                "Success":"False","Reason":"No Records Found"
            }

提前致谢!

解决方法

我解决了,您需要使用 ZipFile 并保留 CF 模板中的格式。我正在通过 CF 设计器构建器检查它是否有效,但我建议无论如何都要尝试运行它,并在出现错误时对其进行分析。