Reputation: 23045
I am developing an AWS Lambda application. This is a REST API, so i am using AWS Lambda, API Gateway and AWS RDS. I am using aws sam
for the deployment and all.
I have 193 end points in my REST API, which means 193 Lambda functions. When i try to deploy this, I got the following error message.
Waiting for changeset to be created..
Error: Failed to create changeset for the stack: aaa-restapi, ex: Waiter ChangeSetCreateComplete failed:
Waiter encountered a terminal failure state: For expression "Status" we matched expected path:
"FAILED" Status: FAILED. Reason: Template format error:
Number of resources, 583, is greater than maximum allowed, 500
Below is a small part of my template.yaml
. Please note in below code the only thing I am removing is over 100 Lambda functions. All Lambda functions looks the same and no difference except the end point they are opening for the REST API. Everything else is there.
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
aws-restapi
Sample SAM Template for aws-restapi
Globals:
Function:
Timeout: 30
VpcConfig:
SecurityGroupIds:
- sg-041f2459xxx921e8e
SubnetIds:
- subnet-03xxdb2d
- subnet-c4dxx4cb
- subnet-af5xxx8
- subnet-748xxf28
- subnet-d13xxx9c
- subnet-e9exxxx7
Resources:
GetAllAccountingTypesFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: aws-restapi/
Handler: source/accounting-types/accountingtypes-getall.getallaccountingtypes
Runtime: nodejs14.x
Events:
GetAllAccountingTypesAPIEvent:
Type: Api
Properties:
Path: /accountingtypes/getall
Method: get
GetAccountingTypeByIDFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: aws-restapi/
Handler: source/accounting-types/accountingtypes-byid.getbyid
Runtime: nodejs14.x
Events:
GetAllAccountingTypesAPIEvent:
Type: Api
Properties:
Path: /accountingtypes/getbyid
Method: get
GetUserRoleByIDFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: aws-restapi/
Handler: source/user-role/userrole-getbyid.getUserRoleByID
Runtime: nodejs14.x
Events:
GetUserRoleByIDAPIEvent:
Type: Api
Properties:
Path: /userrole/getbyid
Method: get
GetUserRoleByUserFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: aws-restapi/
Handler: source/user-role/userrole-getbyuser.getUserRoleByUser
Runtime: nodejs14.x
Events:
GetUserRoleByUserAPIEvent:
Type: Api
Properties:
Path: /userrole/getbyuser
Method: get
GetUserRoleByRoleFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: aws-restapi/
Handler: source/user-role/userrole-getbyrole.getAllUsersByRole
Runtime: nodejs14.x
Events:
GetUserRoleByRoleAPIEvent:
Type: Api
Properties:
Path: /userrole/getbyrole
Method: get
SaveUserRoleFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: aws-restapi/
Handler: source/user-role/userrole-save.saveUserRole
Runtime: nodejs14.x
Events:
SaveUserRoleAPIEvent:
Type: Api
Properties:
Path: /userrole/save
Method: post
UpdateUserRoleFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: aws-restapi/
Handler: source/user-role/userrole-update.updateeUserRole
Runtime: nodejs14.x
Events:
UpdateUserRoleAPIEvent:
Type: Api
Properties:
Path: /userrole/update
Method: post
LambdaRole:
Type: 'AWS::IAM::Role'
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action:
- 'sts:AssumeRole'
Path: /
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Policies:
- PolicyName: root
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- ec2:DescribeNetworkInterfaces
- ec2:CreateNetworkInterface
- ec2:DeleteNetworkInterface
- ec2:DescribeInstances
- ec2:AttachNetworkInterface
Resource: '*'
Outputs:
HelloWorldApi:
Description: "API Gateway endpoint URL for Prod stage for functions"
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/"
I looked into the internet and figured out I need to do nested stacks. In all the tutorials I watched they are talking about dividing your stack into security, network, administration bla bla bla. I do not need any of them, this is a simple REST API and all what I need is to get this deployed without hitting the AWS Limit errors..
I do not understand how to implement nested stacks with my code. Taking my above code as an example, can someone show me how to implement nested stacks into that? Then I can look at the code, learn from the there and implement this to the complete application.
----------------UPDATE-------------------
As per the Robert's advice, I managed to make nested stacks. However we have a problem. It created different API Gateway URLs for each stack. But I want just a one API Gateway URL. Below is my code.
template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
aws-restapi
Sample SAM Template for aws-restapi
# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
Function:
Timeout: 5
VpcConfig:
SecurityGroupIds:
- sg-041f2459dcd921e8e
SubnetIds:
- subnet-0381db2d
- subnet-c4d5c4cb
- subnet-af5c03c8
- subnet-7487df28
- subnet-d139d69c
- subnet-e9e88bd7
Resources:
GetAllAccountingTypesFunction:
Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
Properties:
CodeUri: aws-restapi/
Handler: source/accounting-types/accountingtypes-getall.getallaccountingtypes
Runtime: nodejs14.x
Events:
GetAllAccountingTypesAPIEvent:
Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
Properties:
Path: /accountingtypes/getall
Method: get
GetAccountingTypeByIDFunction:
Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
Properties:
CodeUri: aws-restapi/
Handler: source/accounting-types/accountingtypes-byid.getbyid
Runtime: nodejs14.x
Events:
GetAllAccountingTypesAPIEvent:
Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
Properties:
Path: /accountingtypes/getbyid
Method: get
# DependsOn: GetAllAccountingTypesFunction
NestedStack:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: template_user.yaml
LambdaRole:
Type: 'AWS::IAM::Role'
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action:
- 'sts:AssumeRole'
Path: /
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Policies:
- PolicyName: root
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- ec2:DescribeNetworkInterfaces
- ec2:CreateNetworkInterface
- ec2:DeleteNetworkInterface
- ec2:DescribeInstances
- ec2:AttachNetworkInterface
Resource: '*'
Outputs:
# ServerlessRestApi is an implicit API created out of Events key under Serverless::Function
# Find out more about other implicit resources you can reference within SAM
# https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api
HelloWorldApi:
Description: "API Gateway endpoint URL for Prod stage for functions"
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/"
template_user.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
aws-restapi
Sample SAM Template for aws-restapi
Globals:
Function:
Timeout: 5
VpcConfig:
SecurityGroupIds:
- sg-041f2****cd921e8e
SubnetIds:
- subnet-03***b2d
- subnet-c4d***cb
- subnet-af5***8
- subnet-74***f28
- subnet-d139***c
- subnet-e9***bd7
Resources:
GetUserRoleByIDFunction:
Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
Properties:
CodeUri: aws-restapi/
Handler: source/user-role/userrole-getbyid.getUserRoleByID
Runtime: nodejs14.x
Events:
GetUserRoleByIDAPIEvent:
Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
Properties:
Path: /userrole/getbyid
Method: get
GetUserRoleByUserFunction:
Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
Properties:
CodeUri: aws-restapi/
Handler: source/user-role/userrole-getbyuser.getUserRoleByUser
Runtime: nodejs14.x
Events:
GetUserRoleByUserAPIEvent:
Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
Properties:
Path: /userrole/getbyuser
Method: get
# DependsOn: GetUserRoleByIDFunction
GetUserRoleByRoleFunction:
Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
Properties:
CodeUri: aws-restapi/
Handler: source/user-role/userrole-getbyrole.getAllUsersByRole
Runtime: nodejs14.x
Events:
GetUserRoleByRoleAPIEvent:
Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
Properties:
Path: /userrole/getbyrole
Method: get
#DependsOn: GetUserRoleByUserFunction
SaveUserRoleFunction:
Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
Properties:
CodeUri: aws-restapi/
Handler: source/user-role/userrole-save.saveUserRole
Runtime: nodejs14.x
Events:
SaveUserRoleAPIEvent:
Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
Properties:
Path: /userrole/save
Method: post
# DependsOn: GetUserRoleByRoleFunction
UpdateUserRoleFunction:
Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
Properties:
CodeUri: aws-restapi/
Handler: source/user-role/userrole-update.updateeUserRole
Runtime: nodejs14.x
Events:
UpdateUserRoleAPIEvent:
Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
Properties:
Path: /userrole/update
Method: post
#DependsOn: SaveUserRoleFunction
In this example I have two stacks and API Gateway did create 2 URLs.
template.yaml
URL - https://ez5khz***.execute-api.us-east-1.amazonaws.com/Prod/template_user.yaml
URL - https://7imy9b6***.execute-api.us-east-1.amazonaws.com/Prod/I want the URL that was made with template.yaml
to be applied to all lambda functions, regardless of which nested stack it is in. I also have a plan to later assign a domain into this.
How I can get this to work under a one URL?
Upvotes: 3
Views: 1907
Reputation: 7028
You can use the Cloudformation Stack Resource to implement nested Stacks in CloudFormation. The template url will be resolved by using the Cloudformation Package command.
CodeExample:
NestedStack:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: ./src/nested-stack/infrastructure.yml
Edit: And maybe you should merge some endpoints into one Lambda and use something like express for the routing.
Upvotes: 3