boymeetscode
boymeetscode

Reputation: 825

Serverless deploy fails due to state machine definition error

I am trying to deploy a simple app using Serverless and can't get the deploy to finish. I am getting the following error:

Serverless Error ---------------------------------------

  ✕ State machine "checkAirtableSM" definition is invalid:
  [{"keyword":"additionalProperties","dataPath":".States['CheckAirtable']","schemaPath":"#/additionalProperties","params":{"additionalProperty":"Resource"},"message":"should NOT have additional properties"},{"keyword":"additionalProperties","dataPath":".States['CheckAirtable']","schemaPath":"http://asl-validator.cloud/fail#/additionalProperties","params":{"additionalProperty":"Resource"},"message":"should NOT have additional properties"},{"keyword":"additionalProperties","dataPath":".States['CheckAirtable']","schemaPath":"#/additionalProperties","params":{"additionalProperty":"Resource"},"message":"should NOT have additional properties"},{"keyword":"additionalProperties","dataPath":".States['CheckAirtable']","schemaPath":"http://asl-validator.cloud/pass#/additionalProperties","params":{"additionalProperty":"Resource"},"message":"should NOT have additional properties"},{"keyword":"additionalProperties","dataPath":".States['CheckAirtable']","schemaPath":"http://asl-validator.cloud/succeed#/additionalProperties","params":{"additionalProperty":"Resource"},"message":"should NOT have additional properties"},{"keyword":"pattern","dataPath":".States['CheckAirtable'].Resource","schemaPath":"http://asl-validator.cloud/task#/properties/Resource/oneOf/0/pattern","params":{"pattern":"^arn:aws:([a-z]|-)+:([a-z]|[0-9]|-)*:[0-9]*:([a-z]|-)+:[a-zA-Z0-9-_.]+(:(\\$LATEST|[a-zA-Z0-9-_]+))?$"},"message":"should match pattern \"^arn:aws:([a-z]|-)+:([a-z]|[0-9]|-)*:[0-9]*:([a-z]|-)+:[a-zA-Z0-9-_.]+(:(\\$LATEST|[a-zA-Z0-9-_]+))?$\""},{"keyword":"type","dataPath":".States['CheckAirtable'].Resource","schemaPath":"http://asl-validator.cloud/task#/properties/Resource/oneOf/1/type","params":{"type":"object"},"message":"should be object"},{"keyword":"oneOf","dataPath":".States['CheckAirtable'].Resource","schemaPath":"http://asl-validator.cloud/task#/properties/Resource/oneOf","params":{"passingSchemas":null},"message":"should match exactly one schema in oneOf"},{"keyword":"additionalProperties","dataPath":".States['CheckAirtable']","schemaPath":"http://asl-validator.cloud/wait#/additionalProperties","params":{"additionalProperty":"Resource"},"message":"should NOT have additional properties"},{"keyword":"additionalProperties","dataPath":".States['CheckAirtable']","schemaPath":"#/additionalProperties","params":{"additionalProperty":"Resource"},"message":"should NOT have additional properties"},{"keyword":"oneOf","dataPath":".States['CheckAirtable']","schemaPath":"#/oneOf","params":{"passingSchemas":null},"message":"should match exactly one schema in oneOf"}]

The following is my serverless.yml file:

# NOTE: update this with your service name
service: scheduler-api

# Create an optimized package for our functions 
package:
  individually: true

plugins:
  - serverless-bundle # Package our functions with Webpack
  - serverless-offline
  - serverless-dotenv-plugin # Load .env as environment variables
  - serverless-step-functions
  - serverless-pseudo-parameters

provider:
  name: aws
  runtime: nodejs10.x
  stage: dev
  region: us-east-2
  # To load environment variables externally
  # rename env.example to .env and uncomment
  # the following line. Also, make sure to not
  # commit your .env.
  #
  # These environment variables are made available to our functions
  # under process.env.
  environment:
    airtableBaseId: ${env:AIRTABLE_BASE_ID}
    airtableApiKey: ${env:AIRTABLE_API_KEY}
    STEP_FUNCTION_ARN: "arn:aws:states:#{AWS::Region}:#{AWS::AccountId}:stateMachine:${self:service}-${self:provider.stage}-scheduleTweetSM"
    twitter_consumer_key: ${env:TWITTER_CONSUMER_KEY}
    twitter_consumer_secret: ${env:TWITTER_CONSUMER_SECRET}
    twitter_access_token_key: ${env:TWITTER_ACCESS_TOKEN_KEY}
    twitter_access_token_secret: ${env:TWITTER_ACCESS_TOKEN_SECRET}

functions:
  checkairtable:
    handler: check.main
  pushtweet:
    handler: tweet.main

stepFunctions:
  validate: true
  stateMachines:
    checkAirtableSM:
      name: AirtableChecker
      definition:
        Comment: "Checks for posts that are complete and ready to be scheduled for posting in airtable and schedules them."
        StartAt: CheckAirtable
        States:
          CheckAirtable:
            Type: Task
            Resource: "arn:aws:lambda:#{AWS::Region}:#{AWS::AccountId}:function:${self:service}-${self:provider.stage}-checkairtable"
            End: true
      events:
        - schedule:
            rate: cron(0 0/6 * * ? *)
            enabled: true
    scheduleTweetSM:
      name: TweetScheduler
      definition:
        Comment: "Waits until the post time, then posts the tweet to Twitter."
        StartAt: WaitForPostTime
        States:
          WaitForPostTime:
            Type: Wait
            TimestampePath: $.postTime
            Next: PushPost
          PushPost:
            Type: Task
            Resource: "arn:aws:lambda:#{AWS::Region}:#{AWS::AccountId}:function:${self:service}-${self:provider.stage}-pushtweet"
            End: true

The working theory is that somehow serverless-pseudo-parameters isn't working as expected and is malforming the arn of the resource, which is then complaining of the malformation. Is there anyway to check what the serverless deploy command is making for the serverless.yaml after the strings have been replaced by serverless-pseudo-parameters?

Upvotes: 0

Views: 2440

Answers (1)

Kalev
Kalev

Reputation: 1188

The problem here is actually the validate: true in the state machine definition. If you remove it, everything works fine.

The serverless-step-functions plugin's validation phase operates before the pseudo parameters had been evaluated and replaced with their values. It seems like a compatibility bug between these two plugins.


As an aside, I'll also add that you can actually make do without pseudo parameters in the state machine definition. You can use Fn::GetAtt to get the ARN of the function.

service: scheduler-api

plugins:
  - serverless-step-functions

provider:
  name: aws
  runtime: nodejs10.x
  stage: dev
  region: eu-west-2

functions:
  checkairtable:
    handler: check.main

stepFunctions:
  validate: true
  stateMachines:
    checkAirtableSM:
      name: AirtableChecker
      definition:
        Comment: "Checks for posts that are complete and ready to be scheduled for posting in airtable and schedules them."
        StartAt: CheckAirtable
        States:
          CheckAirtable:
            Type: Task
            Resource:
              Fn::GetAtt: [checkairtable, Arn]
            End: true

Upvotes: 5

Related Questions