cloudFormation Template Validation Error: how to split serverless.yml file

Viewed 617

I ran into the notorious pain in the A$$ error: The CloudFormation template is invalid: Template format error: Number of resources, 202, is greater than maximum allowed, 200.

how do I split this into two, and cross reference the resources?

Could someone possibly share an example with me or show me how to split mine? I've been looking at aws docs and a tons of forums over the past few days to figure this out but I cant quite grasp what I need to do. I just need to be able to add more functions/api calls.

Serverless.yml

service: p-app-api

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

plugins:
  - serverless-bundle # Package our functions with Webpack
  - serverless-offline
  - serverless-dotenv-plugin

provider:
  name: aws
  runtime: nodejs10.x
  stage: dev
  region: us-east-2
  environment:
    stripeSecretKey: ${env:STRIPE_SECRET_KEY}
  # 'iamRoleStatements' defines the permission policy for the Lambda function.
  # In this case Lambda functions are granted with permissions to access DynamoDB.
  iamRoleStatements:
    - Effect: Allow
      Action:
        - dynamodb:DescribeTable
        - dynamodb:Query
        - dynamodb:Scan
        - dynamodb:GetItem
        - dynamodb:PutItem
        - dynamodb:UpdateItem
        - dynamodb:DeleteItem
      Resource: "arn:aws:dynamodb:us-east-2:433684495079:table/data"
    - Effect: Allow
      Action:
        - dynamodb:Query
        - dynamodb:Scan
      Resource: "arn:aws:dynamodb:us-east-2:433684495079:table/data/index/zipCode-packageSelected-index"
    - Effect: Allow
      Action:
        - dynamodb:Query
        - dynamodb:Scan
      Resource: "arn:aws:dynamodb:us-east-2:433684495079:table/data/index/jobId-index"
    - Effect: Allow
      Action:
        - dynamodb:DescribeTable
        - dynamodb:Query
        - dynamodb:Scan
        - dynamodb:GetItem
        - dynamodb:PutItem
        - dynamodb:UpdateItem
        - dynamodb:DeleteItem
      Resource: "arn:aws:dynamodb:us-east-2:433684495079:table/Service"
    - Effect: Allow
      Action:
        - dynamodb:Query
        - dynamodb:Scan
      Resource: "arn:aws:dynamodb:us-east-2:433684495079:table/Service/index/index"
    - Effect: Allow
      Action:
        - s3:*
      Resource: "arn:aws:s3:::service/public/*"
    - Effect: Allow
      Action:
        - dynamodb:DescribeTable
        - dynamodb:Query
        - dynamodb:Scan
        - dynamodb:GetItem
        - dynamodb:PutItem
        - dynamodb:UpdateItem
        - dynamodb:DeleteItem
      Resource: "arn:aws:dynamodb:us-east-2:433684495079:table/Service"
    - Effect: Allow
      Action:
        - dynamodb:Query
        - dynamodb:Scan
      Resource: "arn:aws:dynamodb:us-east-2:433684495079:table/data/index/packageSelected"

functions:
  # Defines an HTTP API endpoint that calls the main function in create.js
  # - path: url path is /notes
  # - method: POST request
  # - cors: enabled CORS (Cross-Origin Resource Sharing) for browser cross
  #     domain api call
  # - authorizer: authenticate using the AWS IAM role
  create:
    handler: create.main
    events:
      - http:
          path: data
          method: post
          cors: true
          authorizer: aws_iam
          arn: aws:cognito-idp:us-east-2:433684495079:userpool/us-east-2_Q0sUvw4Qy
  get:
    # Defines an HTTP API endpoint that calls the main function in get.js
    # - path: url path is /notes/{id}
    # - method: GET request
    handler: get.main
    events:
      - http:
          path: data/{id}
          method: get
          cors: true
          authorizer: aws_iam
          arn: aws:cognito-idp:us-east-2:433684495079:userpool/us-east-2_Q0sUvw4Qy
  list:
    # Defines an HTTP API endpoint that calls the main function in list.js
    # - path: url path is /notes
    # - method: GET request
    handler: list.main
    events:
      - http:
          path: data
          method: get
          cors: true
          authorizer: aws_iam
          arn: aws:cognito-idp:us-east-2:433684495079:userpool/us-east-2_Q0sUvw4Qy
  update:
    # Defines an HTTP API endpoint that calls the main function in update.js
    # - path: url path is /notes/{id}
    # - method: PUT request
    handler: update.main
    events:
      - http:
          path: data/{id}
          method: put
          cors: true
          authorizer: aws_iam
          arn: aws:cognito-idp:us-east-2:433684495079:userpool/us-east-2_Q0sUvw4Qy
  delete:
    # Defines an HTTP API endpoint that calls the main function in delete.js
    # - path: url path is /notes/{id}
    # - method: DELETE request
    handler: delete.main
    events:
      - http:
          path: data/{id}
          method: delete
          cors: true
          authorizer: aws_iam
          arn: aws:cognito-idp:us-east-2:433684495079:userpool/us-east-2_Q0sUvw4Qy
  createCustomer:
    # Defines an HTTP API endpoint that calls the main function in billing.js
    # - path: url path is /billing
    # - method: POST request
    handler: createCustomer.main
    events:
      - http:
          path: createCustomer
          method: post
          cors: true
          authorizer:
          arn: aws:cognito-idp:us-east-2:433684495079:userpool/us-east-2_Q0sUvw4Qy
  updateCustomer:
    # Defines an HTTP API endpoint that calls the main function in billing.js
    # - path: url path is /billing
    # - method: POST request
    handler: updateCustomer.main
    events:
      - http:
          path: updateCustomer
          method: post
          cors: true
          authorizer: aws_iam
          arn: aws:cognito-idp:us-east-2:433684495079:userpool/us-east-2_Q0sUvw4Qy
  listCustomerCard:
    # Defines an HTTP API endpoint that calls the main function in billing.js
    # - path: url path is /billing
    # - method: POST request
    handler: listCustomerCard.main
    events:
      - http:
          path: listCustomerCard/{id}
          method: get
          cors: true
          authorizer: aws_iam
          arn: aws:cognito-idp:us-east-2:433684495079:userpool/us-east-2_Q0sUvw4Qy
  deleteCard:
    # Defines an HTTP API endpoint that calls the main function in billing.js
    # - path: url path is /billing
    # - method: POST request
    handler: DeleteCard.main
    events:
      - http:
          path: deleteCard/{id}/{card}
          method: delete
          cors: true
          authorizer: aws_iam
          arn: aws:cognito-idp:us-east-2:433684495079:userpool/us-east-2_Q0sUvw4Qy
  getCustomerInfo:
    # Defines an HTTP API endpoint that calls the main function in billing.js
    # - path: url path is /billing
    # - method: POST request
    handler: getCustomerInfo.main
    events:
      - http:
          path: getCustomerInfo/{id}
          method: get
          cors: true
          authorizer: aws_iam
          arn: aws:cognito-idp:us-east-2:433684495079:userpool/us-east-2_Q0sUvw4Qy
  updateCustomerCard:
    # Defines an HTTP API endpoint that calls the main function in billing.js
    # - path: url path is /billing
    # - method: POST request
    handler: updateCustomerCard.main
    events:
      - http:
          path: updateCustomerCard/{id}
          method: post
          cors: true
          authorizer: aws_iam
          arn: aws:cognito-idp:us-east-2:433684495079:userpool/us-east-2_Q0sUvw4Qy
  createInvoice:
    # Defines an HTTP API endpoint that calls the main function in billing.js
    # - path: url path is /billing
    # - method: POST request
    handler: createInvoice.main
    events:
      - http:
          path: createInvoice
          method: post
          cors: true
          authorizer: aws_iam
          arn: aws:cognito-idp:us-east-2:433684495079:userpool/us-east-2_Q0sUvw4Qy
  deleteInvoice:
    # Defines an HTTP API endpoint that calls the main function in billing.js
    # - path: url path is /billing
    # - method: POST request
    handler: deleteInvoice.main
    events:
      - http:
          path: deleteInvoice/{id}
          method: delete
          cors: true
          authorizer: aws_iam
          arn: aws:cognito-idp:us-east-2:433684495079:userpool/us-east-2_Q0sUvw4Qy
  listInvoices:
    # Defines an HTTP API endpoint that calls the main function in billing.js
    # - path: url path is /billing
    # - method: POST request
    handler: listInvoices.main
    events:
      - http:
          path: listInvoices/{id}
          method: get
          cors: true
          authorizer: aws_iam
          arn: aws:cognito-idp:us-east-2:433684495079:userpool/us-east-2_Q0sUvw4Qy
  ListNewJobs:
    # Defines an HTTP API endpoint that calls the main function in billing.js
    # - path: url path is /billing
    # - method: POST request
    handler: ListNewJobs.main
    events:
      - http:
          path: data/ListNewJobs
          method: get
          cors: true
          authorizer: aws_iam
          arn: aws:cognito-idp:us-east-2:433684495079:userpool/us-east-2_Q0sUvw4Qy
  jobIndex:
    # Defines an HTTP API endpoint that calls the main function in billing.js
    # - path: url path is /billing
    # - method: POST request
    handler: jobIndex.main
    events:
      - http:
          path: data/jobIndex
          method: get
          cors: true
          authorizer: aws_iam
          arn: aws:cognito-idp:us-east-2:433684495079:userpool/us-east-2_Q0sUvw4Qy
  updateJobStatus:
    # Defines an HTTP API endpoint that calls the main function in billing.js
    # - path: url path is /billing
    # - method: POST request
    handler: updateJobStatus.main
    events:
      - http:
          path: data/jobStatus
          method: put
          cors: true
          authorizer: aws_iam
          arn: aws:cognito-idp:us-east-2:433684495079:userpool/us-east-2_Q0sUvw4Qy
  createNewJob:
    # Defines an HTTP API endpoint that calls the main function in billing.js
    # - path: url path is /billing
    # - method: POST request
    handler: createNewJob.main
    events:
      - http:
          path: ServiceJobs/createNewJob
          method: post
          cors: true
          authorizer: aws_iam
          arn: aws:cognito-idp:us-east-2:433684495079:userpool/us-east-2_Q0sUvw4Qy
  listMyNewJobs:
    # Defines an HTTP API endpoint that calls the main function in billing.js
    # - path: url path is /billing
    # - method: POST request
    handler: listMyNewJobs.main
    events:
      - http:
          path: ServiceJobs/listMyNewJobs
          method: get
          cors: true
          authorizer: aws_iam
          arn: aws:cognito-idp:us-east-2:433684495079:userpool/us-east-2_Q0sUvw4Qy
  DeleteMyNewJob:
    # Defines an HTTP API endpoint that calls the main function in billing.js
    # - path: url path is /billing
    # - method: POST request
    handler: DeleteMyNewJob.main
    events:
      - http:
          path: ServiceJobs/DeleteMyNewJob/{id}
          method: delete
          cors: true
          authorizer: aws_iam
          arn: aws:cognito-idp:us-east-2:433684495079:userpool/us-east-2_Q0sUvw4Qy
  UpdateServiceJobList:
    # Defines an HTTP API endpoint that calls the main function in update.js
    # - path: url path is /notes/{id}
    # - method: PUT request
    handler: UpdateServiceJobList.main
    events:
      - http:
          path: ServicesJobs/Update
          method: put
          cors: true
          authorizer: aws_iam
          arn: aws:cognito-idp:us-east-2:433684495079:userpool/us-east-2_Q0sUvw4Qy
  ServiceIndex:
    # Defines an HTTP API endpoint that calls the main function in billing.js
    # - path: url path is /billing
    # - method: POST request
    handler: ServiceIndex.main
    events:
      - http:
          path: ServiceJobs/ServiceIndex
          method: get
          cors: true
          authorizer: aws_iam
          arn: aws:cognito-idp:us-east-2:433684495079:userpool/us-east-2_Q0sUvw4Qy
  UpdateMyJob:
    # Defines an HTTP API endpoint that calls the main function in update.js
    # - path: url path is /notes/{id}
    # - method: PUT request
    handler: UpdateMyJob.main
    events:
      - http:
          path: ServiceJobs/UpdateMyJob
          method: put
          cors: true
          authorizer: aws_iam
          arn: aws:cognito-idp:us-east-2:433684495079:userpool/us-east-2_Q0sUvw4Qy
  PayInvoiceStripe:
    # Defines an HTTP API endpoint that calls the main function in billing.js
    # - path: url path is /billing
    # - method: POST request
    handler: PayInvoiceStripe.main
    events:
      - http:
          path: stripe/PayInvoice
          method: post
          cors: true
          authorizer: aws_iam
          arn: aws:cognito-idp:us-east-2:433684495079:userpool/us-east-2_Q0sUvw4Qy
  StripeNewContractorAccount:
    # Defines an HTTP API endpoint that calls the main function in billing.js
    # - path: url path is /billing
    # - method: POST request
    handler: StripeNewContractorAccount.main
    events:
      - http:
          path: stripe/NewContractorAccount
          method: post
          cors: true
          authorizer:
          arn: aws:cognito-idp:us-east-2:433684495079:userpool/us-east-2_Q0sUvw4Qy
  serviceInfoPut:
    # Defines an HTTP API endpoint that calls the main function in billing.js
    # - path: url path is /billing
    # - method: POST request
    handler: serviceInfoPut.main
    events:
      - http:
          path: serviceInfo/post
          method: post
          cors: true
          authorizer:
          arn: aws:cognito-idp:us-east-2:433684495079:userpool/us-east-2_Q0sUvw4Qy
  ListJobsForEdit:
    # Defines an HTTP API endpoint that calls the main function in billing.js
    # - path: url path is /billing
    # - method: POST request
    handler: ListJobsForEdit.main
    events:
      - http:
          path: data/index/packageSelected
          method: get
          cors: true
          authorizer: aws_iam
          arn: aws:cognito-idp:us-east-2:433684495079:userpool/us-east-2_Q0sUvw4Qy
# Create our resources with separate CloudFormation templates
resources:
  # API Gateway Errors
  - ${file(resources/api-gateway-errors.yml)}
2 Answers

What you want is using CloudFormation Nested Stacks, they allow you to reference another CloudFormation stack using the AWS::CloudFormation::Stack resource type.

You can then provide parameters as an input to your nested stacks and retrieve their outputs once they are deployed, this is how you communicate between main and sub stacks.

Below is an example of a nested stack reference.

AWSTemplateFormatVersion: "2010-09-09"
Resources: 
  MyNestedStack: 
    Type: AWS::CloudFormation::Stack
    Properties: 
      TemplateURL: "https://s3.amazonaws.com/cloudformation-templates-us-east-2/EC2ChooseAMI.template"
      Parameters:
        Param1: "a-value"
        Param2: "another-value"

Note that TemplateURL can point to S3 Bucket links or to a file on your filesystem. Once you want to deploy your stacks, they need to be packaged using the AWS CLI.

serverless-plugin-split-stacks is the plugin to be use.

Docs is here : serverless split stack

it will help you to split the stack into nested stacks, max limit is 20.

Related