Serverless - TypeError: Невозможно прочитать свойство 'Fn :: GetAtt' из неопределенного - PullRequest
1 голос
/ 23 января 2020

У нас есть набор микросервисов, созданных старой командой с помощью Serverless. Сейчас я пытаюсь обновить версию сервисов узла (без каких-либо других изменений) и получаю сообщение об ошибке TypeError: Cannot read property 'Fn::GetAtt' of undefined.

Я не вижу очевидной причины для этого. В качестве примечания, задача фактически выполняется Lerna, но я получаю одинаковые результаты, независимо от того, выполняется ли она через Lerna или напрямую с sls

Вот мой слегка отредактированный файл serverless.yml:

service: email-service

plugins:
  - serverless-step-functions
  - serverless-pseudo-parameters
  - serverless-domain-manager
  - serverless-plugin-browserifier

package:
  exclude: ${file(../../config/package-exclude.yml):exclude}
  individually: true

custom:
  stage: ${opt:stage, 'dev'}
  authorizerServiceStackName: ${file(../zzzz--authorizer/serverless.yml):service}-${self:custom.stage}
  authorizerArn: ${cf:${self:custom.authorizerServiceStackName}.AuthorizerArn}
  pdfServiceStackName: ${file(../zzzz--pdf/serverless.yml):service}-${self:custom.stage}
  tabularPDFServiceStackName: ${file(../zzzz--tabular-pdf/serverless.yml):service}-${self:custom.stage}
  generatePDFLambdaArn: ${cf:${self:custom.pdfServiceStackName}.GeneratePDFLambdaArn}
  generateTabularPDFLambdaArn: ${cf:${self:custom.tabularPDFServiceStackName}.GenerateHTMLLambdaFunctionArn}
  savePDFToBucketLambdaArn: ${cf:${self:custom.pdfServiceStackName}.SavePDFToBucketLambdaArn}
  saveAttachmentHtmlToTmpBucketLambdaArn: ${cf:${self:custom.pdfServiceStackName}.SaveAttachmentHtmlToTmpBucketLambdaArn}
  pdfTmpBucketArn: ${cf:${self:custom.pdfServiceStackName}.PdfTmpBucketArn}
  customDomain:
    domainName: ${file(../../config/domains.yml):domains.${self:custom.stage}} # Change this to your domain.
    basePath: 'email' # This will be prefixed to all routes
    stage: ${self:custom.stage}
    createRoute53Record: true
  ssm:
    kmsKey: alias/aws/ssm
    postmarkKey: /api-keys/postmark

provider:
  name: aws
  runtime: nodejs10.x
  stage: ${self:custom.stage}
  region: us-west-2
  stackTags:
    Owner: zzzz@zzzz.com
    CostCenter: zzzzzz
    DeploymentDate: ${file(../../config/now.js)}
    ServiceName: ${self:service}
    Expiry: never
  environment:
    STAGE: ${self:custom.stage}

functions:
  attachmentIterator:
    handler: handlers/attachment-iterator.handler
    memorySize: 128
  isolateNextAttachment:
    handler: handlers/isolate-next-attachment.handler
    memorySize: 128
  isolateNextTable:
    handler: handlers/isolate-next-table.handler
    memorySize: 128
  pushGeneratedPdfToArray:
    handler: handlers/push-generated-pdf-to-array.handler
    memorySize: 128
  attachmentCount:
    handler: handlers/attachment-count.handler
    memorySize: 128
  tableCount:
    handler: handlers/table-count.handler
    memorySize: 128
  sendEmail:
    role: ${self:resources.Outputs.ExecuteSaveAttachmentLambdaExecuteRoleArn.Value}
    memorySize: 128
    timeout: 30 # limited by api gateway
    handler: handlers/send-email.handler
    environment:
      SendEmailStateMachineNameARN: ${self:resources.Outputs.SendEmailStateMachineNameARN.Value}
      SaveAttachmentHtmlToTmpBucketLambdaArn: ${self:custom.saveAttachmentHtmlToTmpBucketLambdaArn}
    events:
      - http:
          path: /send
          method: POST
          private: true
          authorizer:
            arn: ${self:custom.authorizerArn}
            resultTtlInSeconds: 0
            identitySource: method.request.header.x-zzzz-api-key
            identityValidationExpression: .*
          cors: ${file(../../config/cors.yml)}
  sendToPostmark:
    role: ${self:resources.Outputs.SendEmailToProviderExecutionRoleArn.Value}
    handler: handlers/postmark/send-template.handler
    memorySize: 128
    timeout: 60
    environment:
      SSM_POSTMARKKEY: ${self:custom.ssm.postmarkKey}
      EMAIL_TO: mailtrap-${self:custom.stage}@email.zzzz.io
      EMAIL_ARCHIVE_ADDRESS: mail-archive-${self:custom.stage}@email.zzzz.io
  emailDeliveryStatus:
    role: ${self:resources.Outputs.GetEmailStatusFromProviderExecutionRoleArn.Value}
    handler: handlers/postmark/delivery-status.handler
    memorySize: 128
    environment:
      SSM_POSTMARKKEY: ${self:custom.ssm.postmarkKey}
  attachmentUploadStatus:
    role: ${self:resources.Outputs.GetAttachmentStatusFromProviderExecutionRoleArn.Value}
    handler: handlers/attachment-upload-status.handler
    memorySize: 128


stepFunctions:
  stateMachines:
    sendEmailWithTabularPDF:
      name: sendEmailWithTabularPDF-${self:service}-${self:custom.stage}
      definition:
        Comment: "Sends an email, with a tabular pdf by passing details to a transactional email API"
        StartAt: CountTables
        States:
          CountTables:
            Type: Task
            Resource: arn:aws:lambda:#{AWS::Region}:#{AWS::AccountId}:function:${self:service}-${self:custom.stage}-tableCount
            ResultPath: $.count
            InputPath: $
            Next: ChoiceHasTable
          ChoiceHasTable:
            Type: Choice
            Choices:
            - Variable: $.count
              NumericGreaterThanEquals: 1
              Next: ConfigureIterator
            - Variable: $.count
              NumericEquals: 0
              Next: SendEmail
            Default: FailUnableCountTables
          ConfigureIterator:
            Type: Pass
            Result:
                index: "-1"
                step: 1
            ResultPath: $.iterator
            Next: Iterator
          Iterator:
            Type: Task
            Resource: arn:aws:lambda:#{AWS::Region}:#{AWS::AccountId}:function:${self:service}-${self:custom.stage}-attachmentIterator
            ResultPath: $.iterator
            Next: IterateRecords
          IterateRecords:
            Type: Choice
            Choices:
              - Variable: $.iterator.continue
                BooleanEquals: true
                Next: IsolateNextAttachment
            Default: SendEmail
          IsolateNextAttachment:
            Type: Task
            Resource: arn:aws:lambda:#{AWS::Region}:#{AWS::AccountId}:function:${self:service}-${self:custom.stage}-isolateNextAttachment
            ResultPath: $.nextAttachment
            OutputPath: $
            Next: GenerateTabularPDF
          GenerateTabularPDF:
            Type: Task
            Resource: ${self:custom.generateTabularPDFLambdaArn}
            InputPath: $.nextAttachment
            ResultPath: $.execArnInformation
            OutputPath: $
            Next: AttachmentStatus
            Catch:
              - ErrorEquals: ['WkhtmltopdfError']
                Next: FailCouldNotGeneratePDF
              - ErrorEquals: ['States.Timeout']
                Next: FailPDFGenerateTimeOut
          AttachmentStatus:
            Type: Task
            Resource: arn:aws:lambda:#{AWS::Region}:#{AWS::AccountId}:function:${self:service}-${self:custom.stage}-attachmentUploadStatus
            InputPath: $.execArnInformation
            ResultPath: $.generatedPdf
            Retry:
              - ErrorEquals: ["AttachmentWaiting"]
                IntervalSeconds: 2
                MaxAttempts: 5
                BackoffRate: 2.0
              - ErrorEquals: ["AttachmentError"]
                IntervalSeconds: 2
                MaxAttempts: 5
                BackoffRate: 2.0
            Next: PushGeneratedPdfToArray
          PushGeneratedPdfToArray:
            Type: Task
            Resource: arn:aws:lambda:#{AWS::Region}:#{AWS::AccountId}:function:${self:service}-${self:custom.stage}-pushGeneratedPdfToArray
            Next: Iterator
          SendEmail:
            Type: Task
            Resource: arn:aws:lambda:#{AWS::Region}:#{AWS::AccountId}:function:${self:service}-${self:custom.stage}-sendToPostmark
            ResultPath: $.emailDetails
            Next: DelayDeliveryStatus
            Catch:
              - ErrorEquals: ['PostmarkError']
                Next: FailCouldNotSendEmail
          DelayDeliveryStatus:
            Type: Wait
            Seconds: 2
            Next: DeliveryStatus
          DeliveryStatus:
            Type: Task
            Resource: arn:aws:lambda:#{AWS::Region}:#{AWS::AccountId}:function:${self:service}-${self:custom.stage}-emailDeliveryStatus
            InputPath: $.emailDetails.MessageID
            ResultPath: $.emailDetails.DeliveryStatus
            Retry:
              - ErrorEquals: ["EmailQueued"]
                IntervalSeconds: 2
                MaxAttempts: 5
                BackoffRate: 2.0
              - ErrorEquals: ["PostmarkError"]
                IntervalSeconds: 2
                MaxAttempts: 5
                BackoffRate: 2.0
            End: true
          # FailSendingEmail:
          #   Type: Fail
          #   Cause: Unable to send email via service.
          FailUnableCountTables:
            Type: Pass
            End: true
          FailPDFGenerateTimeOut:
            Type: Pass
            End: true
          FailCouldNotGeneratePDF:
            Type: Pass
            End: true
          FailCouldNotSendEmail:
            Type: Pass
            End: true
      events:
        - http:
            path: send/template
            method: POST
            authorizer:
              type: CUSTOM
              authorizerId:
                Ref: AuthorizerApiGatewayAuthorizer
    sendEmail:
      name: sendEmail-${self:service}-${self:custom.stage}
      definition:
        Comment: "Sends an email, by passing details to a transactional email API"
        StartAt: CountAttachments
        States:
          CountAttachments:
            Type: Task
            Resource: arn:aws:lambda:#{AWS::Region}:#{AWS::AccountId}:function:${self:service}-${self:custom.stage}-attachmentCount
            ResultPath: $.count
            InputPath: $
            Next: ChoiceHasPDF
          ChoiceHasPDF:
            Type: Choice
            Choices:
            - Variable: $.count
              NumericGreaterThanEquals: 1
              Next: ConfigureIterator
            - Variable: $.count
              NumericEquals: 0
              Next: SendEmail
            Default: FailUnableCountAttachments
          ConfigureIterator:
            Type: Pass
            Result:
                index: "-1"
                step: 1
            ResultPath: $.iterator
            Next: Iterator
          Iterator:
            Type: Task
            Resource: arn:aws:lambda:#{AWS::Region}:#{AWS::AccountId}:function:${self:service}-${self:custom.stage}-attachmentIterator
            ResultPath: $.iterator
            Next: IterateRecords
          IterateRecords:
            Type: Choice
            Choices:
              - Variable: $.iterator.continue
                BooleanEquals: true
                Next: IsolateNextAttachment
            Default: SendEmail
          IsolateNextAttachment:
            Type: Task
            Resource: arn:aws:lambda:#{AWS::Region}:#{AWS::AccountId}:function:${self:service}-${self:custom.stage}-isolateNextAttachment
            ResultPath: $.nextAttachment
            OutputPath: $
            Next: GeneratePDF
          GeneratePDF:
            Type: Task
            Resource: ${self:custom.generatePDFLambdaArn}
            InputPath: $.nextAttachment
            ResultPath: $.generatedPdf
            OutputPath: $
            Next: PushGeneratedPdfToArray
            Catch:
              - ErrorEquals: ['WkhtmltopdfError']
                Next: FailCouldNotGeneratePDF
              - ErrorEquals: ['States.Timeout']
                Next: FailPDFGenerateTimeOut
          PushGeneratedPdfToArray:
            Type: Task
            Resource: arn:aws:lambda:#{AWS::Region}:#{AWS::AccountId}:function:${self:service}-${self:custom.stage}-pushGeneratedPdfToArray
            Next: Iterator
          SendEmail:
            Type: Task
            Resource: arn:aws:lambda:#{AWS::Region}:#{AWS::AccountId}:function:${self:service}-${self:custom.stage}-sendToPostmark
            ResultPath: $.emailDetails
            Next: DelayDeliveryStatus
            Catch:
              - ErrorEquals: ['PostmarkError']
                Next: FailCouldNotSendEmail
          DelayDeliveryStatus:
            Type: Wait
            Seconds: 2
            Next: DeliveryStatus
          DeliveryStatus:
            Type: Task
            Resource: arn:aws:lambda:#{AWS::Region}:#{AWS::AccountId}:function:${self:service}-${self:custom.stage}-emailDeliveryStatus
            InputPath: $.emailDetails.MessageID
            ResultPath: $.emailDetails.DeliveryStatus
            Retry:
              - ErrorEquals: ["EmailQueued"]
                IntervalSeconds: 2
                MaxAttempts: 5
                BackoffRate: 2.0
              - ErrorEquals: ["PostmarkError"]
                IntervalSeconds: 2
                MaxAttempts: 5
                BackoffRate: 2.0
            End: true
          # FailSendingEmail:
          #   Type: Fail
          #   Cause: Unable to send email via service.
          FailUnableCountAttachments:
            Type: Pass
            End: true
          FailPDFGenerateTimeOut:
            Type: Pass
            End: true
          FailCouldNotGeneratePDF:
            Type: Pass
            End: true
          FailCouldNotSendEmail:
            Type: Pass
            End: true

resources:
  Resources:
    ApiGatewayRestApi:
      Properties:
        ApiKeySourceType: AUTHORIZER

    WriteLambdaLogsPolicy:
      Type: AWS::IAM::Policy
      Properties:
        Roles:
          - Ref: ExecuteSaveAttachmentLambdaExecuteRole
          - Ref: SendEmailToProviderExecutionRole
          - Ref: GetEmailStatusFromProviderExecutionRole
          - Ref: GetAttachmentStatusFromProviderExecutionRole
        PolicyName: canWriteToCloudwatchLogs
        PolicyDocument:
          Version: '2012-10-17'
          Statement:
            - Effect: Allow
              Action:
                - logs:CreateLogGroup
                - logs:CreateLogStream
                - logs:PutLogEvents
              Resource:
                - 'Fn::Join':
                  - ':'
                  -
                    - 'arn'
                    - Ref: 'AWS::Partition'
                    - 'logs'
                    - Ref: 'AWS::Region'
                    - Ref: 'AWS::AccountId'
                    - 'log-group:/aws/lambda/*:*:*'
    GetValuesfromSSMStoreAndDecryptPolicy:
      Type: AWS::IAM::Policy
      Properties:
        Roles:
          - Ref: SendEmailToProviderExecutionRole
          - Ref: GetEmailStatusFromProviderExecutionRole
        PolicyName: getAndDecodePostmarkSSMKeys
        PolicyDocument:
          Version: '2012-10-17'
          Statement:
            - Effect: Allow
              Action:
                - ssm:GetParameter
                - ssm:GetParameters
              Resource:
                # Note: No '/' between parameter and key name, as the keyname starts with a '/'
                - "arn:aws:ssm:#{AWS::Region}:#{AWS::AccountId}:parameter${self:custom.ssm.postmarkKey}"
            - Effect: "Allow"
              Action:
                - kms:Decrypt
              Resource: "arn:aws:kms:#{AWS::Region}:#{AWS::AccountId}:key/${self:custom.ssm.kmsKey}"
    ExecuteSaveAttachmentLambdaExecuteRole:
      Type: AWS::IAM::Role
      Properties:
        Path: /zzzz/service/email/
        AssumeRolePolicyDocument:
          Version: '2012-10-17'
          Statement:
            - Effect: Allow
              Principal:
                Service:
                  - lambda.amazonaws.com
              Action: sts:AssumeRole
        Policies:
          - PolicyName: executeSaveAttachmentLambdaExecuteRole
            PolicyDocument:
              Version: '2012-10-17'
              Statement:
                - Effect: Allow
                  Action:
                    - lambda:InvokeFunction
                  Resource: ${self:custom.saveAttachmentHtmlToTmpBucketLambdaArn}
                - Effect: Allow
                  Action:
                    - "states:StartExecution"
                  Resource: ${self:resources.Outputs.SendEmailStateMachineNameARN.Value}
    SendEmailToProviderExecutionRole:
      Type: AWS::IAM::Role
      Properties:
        Path: /zzzz/service/email/
        AssumeRolePolicyDocument:
          Version: '2012-10-17'
          Statement:
            - Effect: Allow
              Principal:
                Service:
                  - lambda.amazonaws.com
              Action: sts:AssumeRole
        Policies:
          - PolicyName: retrievePDFFromBucket
            PolicyDocument:
              Version: '2012-10-17'
              Statement:
                - Effect: "Allow"
                  Action:
                    - s3:GetObject # getObject is Resource Level - ensure your resource ends in '/*'
                    # - s3:GetObjectAcl
                    # - s3:GetObjectVersion # this should nto be needed...
                    # - s3:*
                  Resource:
                    - 'Fn::Join':
                      - '/'
                      -
                        - ${self:custom.pdfTmpBucketArn}
                        - '*'
    GetEmailStatusFromProviderExecutionRole:
      Type: AWS::IAM::Role
      Properties:
        Path: /zzzz/service/email/
        AssumeRolePolicyDocument:
          Version: '2012-10-17'
          Statement:
            - Effect: Allow
              Principal:
                Service:
                  - lambda.amazonaws.com
              Action: sts:AssumeRole
    GetAttachmentStatusFromProviderExecutionRole:
      Type: AWS::IAM::Role
      Properties:
        Path: /zzzz/service/email/
        AssumeRolePolicyDocument:
          Version: '2012-10-17'
          Statement:
            - Effect: Allow
              Principal:
                Service:
                  - lambda.amazonaws.com
              Action: sts:AssumeRole
        Policies:
          - PolicyName: readExecutionArnStatus
            PolicyDocument:
              Version: '2012-10-17'
              Statement:
                - Effect: "Allow"
                  Action:
                    - states:DescribeExecution
                  Resource:
                    - 'Fn::Join':
                      - ':'
                      -
                        - 'arn:aws:states'
                        - Ref: 'AWS::Region'
                        - Ref: 'AWS::AccountId'
                        - 'execution'
                        - 'Fn::ImportValue': ${self:custom.pdfServiceStackName}:SavePDFStateMachineName
                        - '*'
  Outputs:
    SendEmailStateMachineNameARN:
      Value:
        # SendEmailDashemailDashserviceDash${self:custom.stage} should be
        # SendEmailDash${self:service}Dash${self:custom.stage} however servicename has a dash in it.
        Ref: SendEmailDashemailDashserviceDash${self:custom.stage}

    SendEmailStateMachineName:
      Value:
        'Fn::GetAtt':
          # SendEmailDashemailDashserviceDash${self:custom.stage} should be
          # SendEmailDash${self:service}Dash${self:custom.stage} however servicename has a dash in it.
          - SendEmailDashemailDashserviceDash${self:custom.stage}
          - Name
      Export:
        Name: ${self:service}-${self:custom.stage}:SendEmailStateMachineName
    SendEmailWithTabularPDFStateMachineName:
      Value:
        'Fn::GetAtt':
          - SendEmailWithTabularPDFDashemailDashserviceDash${self:custom.stage}
          - Name
      Export:
        Name: ${self:service}-${self:custom.stage}:SendEmailWithTabularPDFStateMachineName
    ExecuteSaveAttachmentLambdaExecuteRoleArn:
      Value:
        'Fn::GetAtt': [ExecuteSaveAttachmentLambdaExecuteRole, Arn]
    SendEmailToProviderExecutionRoleArn:
      Value:
        'Fn::GetAtt': [SendEmailToProviderExecutionRole, Arn]
    GetEmailStatusFromProviderExecutionRoleArn:
      Value:
        'Fn::GetAtt': [GetEmailStatusFromProviderExecutionRole, Arn]
    GetAttachmentStatusFromProviderExecutionRoleArn:
      Value:
        'Fn::GetAtt': [GetAttachmentStatusFromProviderExecutionRole, Arn]

...