Replies: 59 comments 12 replies
-
You can use CloudFormation export and import to pass the parameters from one stack to a different stack: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-stack-exports.html To deal with resource limit issue, CloudFormation recommends to use nested stacks: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-nested-stacks.html
|
Beta Was this translation helpful? Give feedback.
-
@honglu thanks for your reply. We have been doing what you suggested above and now only serverless resources are left in the SAM when we hit the CF limit after transformation. There were 3 options we came up with and tried but all failed:
So at the end we are still blocked in that catch-22 situation due to variety of limits and limitations of SAM and CF. Is there any other way or ideas that can help us overcome it? PS: However I also came across another issue - #335 that indicates the option-1 was working until a few days back, which is really interesting and worth watching progressing on that issue. |
Beta Was this translation helpful? Give feedback.
-
Hi Folks, #149 seems to imply one cannot split the api resource from the function resources. This issue seems to imply it is indeed possible, without giving template examples. I would be forever grateful if someone who's managed to do this would post an actual example that works. Many thanks in advance. |
Beta Was this translation helpful? Give feedback.
-
We managed to split them before, but no longer. It suddenly stopped working so we had to redo all of our stack structure which meant a downtime in production. See #335 |
Beta Was this translation helpful? Give feedback.
-
Does anyone know if this issue is dead? Or does anyone know if there is a way to use the aws lambda update-function-code CLI method to update the code and roll it out with checkpoints? |
Beta Was this translation helpful? Give feedback.
-
It would also be great if |
Beta Was this translation helpful? Give feedback.
-
Nested stacks are now supported in SAM, meaning you can nest resources in other stacks and use the outputs as values in the current stack. |
Beta Was this translation helpful? Give feedback.
-
Even though they are supported, when I created the |
Beta Was this translation helpful? Give feedback.
-
Can you post an example that creates this issue? Is it as simple as defining an API in one stack and referencing a Function in that API that is from a nested stack? |
Beta Was this translation helpful? Give feedback.
-
Sure! These are two stacks that cause an error. template.yml
substack.yml
|
Beta Was this translation helpful? Give feedback.
-
Thanks for the example. SAM currently requires the API and lambda functions invoked by the API Gateway to be in the same template in order to use the implicit API generation functionality of SAM. This is because the swagger is generated in the template and references the serverless functions using Are you saying you are hitting the CFN 200 resource limit when your template only contains the API Gateway resources and lambda function (and IAM roles) directly invoked by API Gateway and all other resources are in nested stacks? This would imply that you have maybe ~70 resource+methods all being serviced by separate Lambda functions. Is that correct? Some alternatives you could try:
Adding SAM support for the same intuitive API mapping within the |
Beta Was this translation helpful? Give feedback.
-
@jlhood: Let med add some more feedback. I am composing serverless applications using the AWS::Serverless::Application resource. In one SAM template I need to nest two applications that both use an API gateway. In this scenario it's not possible to make the two nested applications share the api gateway because:
Any ideas for workarounds? |
Beta Was this translation helpful? Give feedback.
-
@cshenrik Really appreciate the additional context and feedback. Agreed, adding triggers based on resources in your current template to functions defined within a nested application is not made easy by SAM today. Currently, you would have to manage your own API swagger document to add the nested app function as an integration. What do you think about the possibility of being able to specify event sources on the NestedApp:
Type: AWS::Serverless::Application
Properties:
Location:
ApplicationId: <app id>
SemanticVersion: 1.0.0
Events:
GetRoot:
Type: Api
Properties:
Path: /
Method: GET
OutputFunctionName: MyHandlerFunctionName
OutputFunctionArn: MyHandlerFunctionArn So here I have a nested SAR app called Need to flesh out the exact syntax and some more details but wanted to put it out there to get some feedback. |
Beta Was this translation helpful? Give feedback.
-
I think adding a new property to Serverless::Api would solve this problem and more. Maybe we call this |
Beta Was this translation helpful? Give feedback.
-
Just hit the CFN 200 limit today (yes, @jlhood, I am reusing roles) and looking for a workaround led me to this issue. I initially tried to pass the "AWS::Serverless::Api" as a parameter to "AWS::Serverless::Application" but then I got the dreaded "The REST API doesn't contain any methods" error as it seems CFN is trying to deploy the API before it builds the other nested stacks. Any workarounds? EDIT: Looking at my last created CFN stack the problem seems to be the Lambda Permissions is being created 2 times for each lambda function as pointed out in #285. I would love to move to a nested stack solution but #349 prevents me from this. I really don't want to create a different API endpoint for different resources but that's all I that comes to mind right now. |
Beta Was this translation helpful? Give feedback.
-
Same issue here, any update??? |
Beta Was this translation helpful? Give feedback.
-
Also looking for a solution here |
Beta Was this translation helpful? Give feedback.
-
Any updates on this? |
Beta Was this translation helpful? Give feedback.
-
Seriously guys, we really need to pass down RestAPI to child stacks :D |
Beta Was this translation helpful? Give feedback.
-
The number of people and orgs looking for this feature. Is it really that hard to AWS SAM peeps? |
Beta Was this translation helpful? Give feedback.
-
So to explain, yes, this has technical limitations getting in the way. Right now, when you create an
Doing step 2 is the tricky part, because it has to happen right now where the API is defined. You could use One possible option we could explore if there was high demand for this would be to add some sort of route helpers to the |
Beta Was this translation helpful? Give feedback.
-
This doesn't answer the original question exactly (using a single API Gateway), but if you're OK using an API Gateway per project (let's say each project is a microservice made up of multiple lambdas in each project/microservice), then this is how I did it. Posting in case it's useful to anyone. This enables some modularity so you can break your services down across multiple projects. The downside is that you create an API Gateway per project (which may OK for you if you're want to use the "Multiple API Gateway" pattern referenced here: https://docs.aws.amazon.com/prescriptive-guidance/latest/modernization-integrating-microservices/api-gateway-pattern.html#multiple-api-gateways). Details posted here: |
Beta Was this translation helpful? Give feedback.
-
Adding a reproducible example for posterity. Save the following as Transform: AWS::Serverless-2016-10-31
Resources:
MyApi:
Type: AWS::Serverless::Api
Properties:
StageName: prod
MyFunction:
Type: AWS::Serverless::Function
Properties:
Runtime: python3.8
Handler: foo
InlineCode: bar
Events:
ApiEvent:
Type: Api
Properties:
Method: get
Path: /
RestApiId: !Ref MyApi Deploy:
It transforms into the following template: Transformed CloudFormation template
{
"Resources": {
"MyFunction": {
"Type": "AWS::Lambda::Function",
"Metadata": {
"SamResourceId": "MyFunction"
},
"Properties": {
"Code": {
"ZipFile": "bar"
},
"Handler": "foo",
"Role": {
"Fn::GetAtt": [
"MyFunctionRole",
"Arn"
]
},
"Runtime": "python3.8",
"Tags": [
{
"Key": "lambda:createdBy",
"Value": "SAM"
}
]
}
},
"MyFunctionApiEventPermissionprod": {
"Type": "AWS::Lambda::Permission",
"Properties": {
"Action": "lambda:InvokeFunction",
"FunctionName": {
"Ref": "MyFunction"
},
"Principal": "apigateway.amazonaws.com",
"SourceArn": {
"Fn::Sub": [
"arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/",
{
"__ApiId__": {
"Ref": "MyApi"
},
"__Stage__": "*"
}
]
}
}
},
"MyApiprodStage": {
"Type": "AWS::ApiGateway::Stage",
"Properties": {
"DeploymentId": {
"Ref": "MyApiDeployment1e98ccf811"
},
"RestApiId": {
"Ref": "MyApi"
},
"StageName": "prod"
}
},
"MyFunctionRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"sts:AssumeRole"
],
"Effect": "Allow",
"Principal": {
"Service": [
"lambda.amazonaws.com"
]
}
}
]
},
"ManagedPolicyArns": [
"arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
],
"Tags": [
{
"Key": "lambda:createdBy",
"Value": "SAM"
}
]
}
},
"MyApiDeployment1e98ccf811": {
"Type": "AWS::ApiGateway::Deployment",
"Properties": {
"Description": "RestApi deployment id: 1e98ccf811ae5bf67840ade2be6857ddf75298a9",
"RestApiId": {
"Ref": "MyApi"
},
"StageName": "Stage"
}
},
"MyApi": {
"Type": "AWS::ApiGateway::RestApi",
"Metadata": {
"SamResourceId": "MyApi"
},
"Properties": {
"Body": {
"info": {
"version": "1.0",
"title": {
"Ref": "AWS::StackName"
}
},
"paths": {
"/": {
"get": {
"x-amazon-apigateway-integration": {
"httpMethod": "POST",
"type": "aws_proxy",
"uri": {
"Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunction.Arn}/invocations"
}
},
"responses": {}
}
}
},
"swagger": "2.0"
}
}
}
}
} The transformed template shows that "paths": {
"/": {
"get": {
"x-amazon-apigateway-integration": {
"httpMethod": "POST",
"type": "aws_proxy",
"uri": {
"Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunction.Arn}/invocations"
}
},
"responses": {}
}
}
}, The API definition of the And here: But since the API resource is not in the same template as where the event is defined, the SAM transform is unable to edit the API definition. Which is the current technical limitation described in the issue. |
Beta Was this translation helpful? Give feedback.
-
Any plans to fix this? It will be 5 years soon |
Beta Was this translation helpful? Give feedback.
-
There are no simple workarounds or 'quick fixes' due to the circular update (lambda refs API, API refs Lambda) which can only be supported in the same template. It is clear there is interest in separating API and Lambdas across more than one template for a variety of reasons, which seems reasonable. |
Beta Was this translation helpful? Give feedback.
-
Challenge: Our API stack (Plain compute layer & no data stores) have surpassed the limit of max resource count of single cloud formation. To get around this, we have to break our large APIs into smaller groups and nest them down as child stack of the main CloudFormation stack which produces a side effect of having to create multiple API gateways and keys for all this child stacks. Another observation of mine is that, the more resources there is on a CloudFormation stack, the slower the deployment time gets. Solution: We have to remove our API keys from API gateways because there is no way to have a single API gateway on a parent stack and pass its logical ID / reference to lambda functions residing on the nested stacks.
It worked great because:
Why this solution sucks
What we're dreaming of
Probable solution
|
Beta Was this translation helpful? Give feedback.
-
So we have run into this problem and i just split everything up into nested stacks, and then ran into this issue. From reading all of these I understand that the problem is SAM is building the OpenAPI Document for the APIGW, currently it does that from the lambda's registering against the API Gateway, so they need to be in the same stack. Would it not be easier to have a property of the API Gateway that if present stops the complete auto generation and allow us to provide the routes instead? Example below, but with this method if the Routes property is not supplied works as it currently does, if the Routes Property is suppled then the Routes & API Gateway are created after the Lambda and we have removed the need to have the Lambda's point to the RestAPIId removing the circular reference? (this would also match the mentality that AWS Console users would be familiar with create the function then create the API Gateway pointing to the function) E.G AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description: ""
Resources:
FunctionsNested:
Type: AWS::Serverless::Application
Properties:
Location: ./functions.yaml
API:
Type: AWS::Serverless::Api
Properties:
Description: The main API Service
OpenApiVersion: "2.0"
Domain:
DomainName: "some.domain.name"
Routes:
- Type: AWS::Api::Route
Method: "GET"
Path: "/hello"
Function: !GetAtt FunctionsNested.Outputs.GETHelloARN
- Type: AWS::Api::Route
Method: "GET"
Path: "/helloworld"
Function: !GetAtt FunctionsNested.Outputs.GETHelloWorldARN functions.yaml AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description: ""
Resources:
GETHelloFunction:
Type: AWS::Serverless::Function
Properties:
Runtime: nodejs16.x
Description: "A function"
Handler: app.lambdaHandler
CodeUri: ./GET_hello/
GETHelloWorldFunction:
Type: AWS::Serverless::Function
Properties:
Runtime: nodejs16.x
Description: "A function"
Handler: app.lambdaHandler
CodeUri: ./GET_helloWorld/
Outputs:
GETHelloARN:
Value: !GetAtt GETHelloFunction.Arn
GETHelloWorldARN:
Value: !GetAtt GETHelloWorldFunction.Arn |
Beta Was this translation helpful? Give feedback.
-
I just discovered this repository: https://github.com/aws-samples/sam-accelerate-nested-stacks-demo. They resolved this issue by only defining the Lambda functions, then sending them down to an API nested stack which uses Serverless::Api::DefinitionBody to reference function's in (here's the openapi yaml: https://github.com/aws-samples/sam-accelerate-nested-stacks-demo/blob/main/api/definition/openapi.yaml). You are responsible to handle IAM, but apart from that, it seems to be a good workaround. I don't see anyone recommending this. Why? |
Beta Was this translation helpful? Give feedback.
-
I've created a repository demonstrating the discussed work-around: https://github.com/laaksomavrick/aws-sam-apigw-lambda-decomposition-example/tree/refactoring-fix. Alongside this is an accompanying blog post. |
Beta Was this translation helpful? Give feedback.
-
The idea proposed in the description of the discussion here is much much better where an This is much more flexible and avoids the coupling of things in one master template. It also allows for independent deployment of the stacks. Is there a solution that allows us to go with this approach? |
Beta Was this translation helpful? Give feedback.
-
We have got a problem where the resource limit of CF is hit when transformed from our SAM Template file.
Given all our Lambdas are behind APIs and we want to maintain all APIs from Single API Gateway, and that we now have to split the SAM Template into multiples to make them independently deploy-able, is there a way that we define one template that has only
AWS::Serverless::Api
to build out API Gateway with given Swagger file, and then to pass its reference to other template files that will be deploying ourAWS::Serverless::Function
s.We simply want to pass the reference of
RestApiId
to the template files as a CFN Parameter.Is this possible at this moment? As the error on the attempt says otherwise - RestApiId must be a valid reference to an 'AWS::Serverless::Api' resource in same template, which is quite dis-heartening :-(
Beta Was this translation helpful? Give feedback.
All reactions