aws/serverless-application-model

SAM Creates stage named "Stage" by default?

Closed this issue ยท 70 comments

sdole commented

I have a template like this:

AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Resources:
  Api:
    Properties:
      StageName: dv01
      DefinitionUri: api_spec_SAM.json
    Type: AWS::Serverless::Api

After package and deploy with the cli, it creates an API with two stages named "Stage" and "dv01". In reality, I do not want to create either stages. The StageName property is "required". Not sure why. My intention is to create a separate set of templates to create the stages, deployments, lambda function versions etc.

The reason I need separation is because we have multiple code pipelines that are owned by different people (dev, build teams). I would like these templates to live in separate git repos.

Is there a way to create an API without any stages?

Else, the work around is to simply ignore this one default stage created via SAM. Thanks!

I am also seeing this issue, however I do require a stage set in the AWS::Serverless::Api resource but I am seeing a second stage created as "Stage". I validated in the "processed" cfn template the resource AWS::ApiGateway::Stage is referencing a AWS::ApiGateway::Deployment but the stage name in the deployment is "Stage" not "qic" as set in the stage resource.

SAM Template:

ARSAPIGateway:
    Type: AWS::Serverless::Api
    Properties:
      DefinitionUri: apigateway/swagger.yaml
      StageName: qic
      Variables:
        LambdaFunctionName: !Ref LambdaFunction17

Processed CFN Template:

"APIGatewayDeploymenta727bb8729": {
      "Type": "AWS::ApiGateway::Deployment",
      "Properties": {
        "RestApiId": {
          "Ref": "APIGateway"
        },
        "Description": "RestApi deployment id: a727bb872967fd6e7bd621271f597376226329ee",
        "StageName": "Stage"
      }
    },
"APIGatewayStage": {
      "Type": "AWS::ApiGateway::Stage",
      "Properties": {
        "Variables": {
          "LambdaFunctionName": {
            "Ref": "LambdaFunction17"
          }
        },
        "RestApiId": {
          "Ref": "APIGateway"
        },
        "DeploymentId": {
          "Ref": "APIGatewayDeploymenta727bb8729"
        },
        "StageName": "qic"
      }
    }

Looks like the same/similar issue as here #176

I am having a related problem.

I am defining my swagger template inline and in it, the stage name "prod". During the deployment of the stack, I get an error regarding the stage name when another resource (api key and usage plan) tries to reference it. It appears that it doesn't exist (yet the Stage stage exists). It appears that the the processed template includes the "Stage" stage but the creation of the prod stage happens in the wrong order and there is no way to set a "DependsOn"

You see similar (undesired?) behavior when defining AWS::Serverless:Function with API events and not using AWS::Serverless::Api. You end up getting an API gateway resource defined both stage and prod stages, when in reality only a single stage was really desired in that the stacks are being deployed using CodePipeline, where I was hoping the ownership over "Stage". At each stage in this pipeline an instance of the stack defined by the SAM template is deployed. As such, it seems odd to have two API gateway stages (stage/prod) deployed for each on my three CodePipeline-defined stages. Should default behavior be to only create a single single on API gateway rather than two?

I'm curious if any of the maintainers of this repo are ever going to weigh-in on this. It makes zero sense to me that both a stage and prod stage are created by default. @sanathkr

jfuss commented

@davewoodward To my knowledge this was and is a bug in SAM. We attempted to remove this behavior but that caused #168 and the fixed was needed to rollback.

The short answer is yes we are aware this happens but right now do not have a good way to fix it that would not cause a regression to all existing stacks that use SAM. There are a couple issue spread throughout this repo on this. We will be working towards cleaning these up into one issue soon. These are the ones that seem related at first glance: #176 #67 #78

@jfuss it would seem that perhaps addition of a property on the resource to determine desired deployment behavior would be feasible, so long as in absence of such a property, the current stage/prod deployments would be the default behavior to maintain backwards compatibility. Of course adding new properties, especially ones that would in essence disappear during the transformation step, might not be desirable either.

jfuss commented

@mikecbrant I personally don't like that approach because you are adding in some property that has no true meaning, other than to hide a bug. This seems like the wrong way to approach a problem like this. The other issue I foresee, is with new customers adopting SAM. Without context of the issue, it is easy to leave this new property out and get into the state we currently are in. Maybe if done correctly, we could do something like this but requires a much deeper discussion and investigation.

Yes, having this stage there is annoying but is it really that harmful? Are there more issues with this other than it is created and is not updatable? Understanding this will help us in trying to prioritize it and give us a bigger reason to dig into it further. When we tried to roll out a fix for this in the past, we caused a regression for customers (#168). Until we have a good solution, the best advice is to just ignore this 'Stage' stage. This is no way ideal by any means but the best I can offer, as of now.

The version of the transform is in the name (AWS::Serverless-2016-10-31). The purpose of versioning is to allow you to introduce backwards-incompatible changes, right?

While I can see not wanting to increase the version for a seemingly inconsequential bug, it is nevertheless a bug until such time that it's documented as expected behavior.

jfuss commented

@jarruda I have brought this up with the team in the past. I forget how that conversation went but there was some reason we didn't want to do that right now, if I remember correctly.

Regardless, I think we need to invest more time into this issue before taking this approach. We want to make sure we don't have another option to solve this but may be our only option. I will try to drive a conversation with the team, to see if we can get something moving on this. Or at very least communicate to everyone clearly what is going on and where we are at on it.

I'm going through the same issue. It doesn't make sense to me to have this "Stage" stage being created in parallel with the stage I specified. Could you provide us with any update regarding this?

Any progress on this?
For now, I developed using only 'test' in StageName. However I need to test on production mode soon.

sdole commented

We don't use transform for API GW at all because of this issue. For Lambdas we do use Transforms, however, there too, I feel like we really do not need to. All our deployment is via CloudFormation and this transform is simply an unnecessary step in a codebuild for us.

I feel like this SAM thing might be intended for some other purpose in the future. If one is intimately familiar with cloudformation, SAM seems to be just a different (and non-working) way of deploying.

jfuss commented

@xkguq007 The team has been focusing on other areas, mainly filling the gaps we have in API Gateway support. So unfortunately, we have not been able to make process on this issue just yet. We have had hallway/ one off converstations about this issue and still feeling out how best to handle this without causing a back breaking change for all customers.

@sdole "SAM seems to be just a different (and non-working) way of deploying."

  • That is pretty harsh. Are we prefect? No. But saying 'non-working'...
    If we are missing the mark that far, cut us an issue. Let's have an open conversation about what is missing, what areas need further improvement, etc. The team is very open to this kinds of things and we love honest feedback. :)
sdole commented

@jfuss, sorry about making you feel that way. My comment was in context of this specific issue. It does not work if it creates an unnecessary stage. I am a big fan of AWS, I am a standard partner of AWS and have many happy customers because of AWS. At one customer I have created a global web app based on aws lambda and api gateway alone. Doing that work led me to try and fail at SAM and open this GitHub issue. We have AWS codepipelines in which there's an AWS codebuild step just to transform from SAM to regular Cloudformation. I could have had the devs just as effectively use a non SAM template. That was my second point. Finally, in the context of services such as Serverless Application Repository, I think SAM may play a role in defining reusable shareable templates etc. That was my last point in the previous post.

I definitely do not intend to disparage the entirety of SAM. I apologize.

Let me explain why this bug is tricky to fix. When you deploy an API with SAM, it will create a AWS::ApiGateway::Stage resource to setup the actual stage, and an AWS::ApiGateway::Deployment resource to deploy the APIs to the stage.

Here is an example Deployment resource.

"ServerlessRestApiDeployment127e3fb911": {
      "Type": "AWS::ApiGateway::Deployment", 
      "Properties": {
        "RestApiId": {
          "Ref": "ServerlessRestApi"
        }, 
        "Description": "RestApi deployment id: 127e3fb91142ab1ddc5f5446adb094442581a90d", 

        "StageName": "Stage"  <------ NOTE THIS LINE
      }

Notice the "StageName" property on this resource. API Gateway creates a Deployment, and creates a new stage called "Stage". This is in addition to the regular ("Prod") stage you wanted SAM to create.

So the fix is easy. Remove this one line from Deployment resource, right? Not so easy after all!

ApiGateway::Deployment is an immutable resource. Removing this line will have one of two outcomes next time you deploy the stack:

  1. If your stack has a change to API configuration, it will roll forward and remove the extra Stage. This is because when API configuration changes, SAM detects it using a hash of the Swagger JSON, and appends the hash to ApiGateway::Deployment resource, essentially creating a new resource and deleting the old one.

  2. If your stack does not change the API configuration, stack deployment will fail because CloudFormation tries remove the StageName property from existing Deployment resource, which is immutable. So ApiGateway rejects this request, and CloudFormation subsequently fails the deployment.

Unfortunately SAM is implemented as a stateless system. It does not know the current state of any of your resources. It is simply a stateless converter from SAM to CloudFormation. So SAM cannot do cool things like "remove StageName if and only if API configuration is changing".

Possible Solutions

  1. Version Bump: Create a new SAM Transform 2.0 version that is backwards incompatible with 1.0. The only difference would be removing the StageName property. Customers have to upgrade to 2.0 only when changing the API Configuration.

  2. Internal Property: Provide a property like ___REMOVE_STAGE_NAME, which when set to True will remove this StageName for you. But then your template is stuck with this property forever. This is really ugly and not customer obsessed.

We don't like any of the above solutions. Both of them make you, template author, to do more work. This is the reason we haven't fixed this bug yet.

We are working with folks internally to try and find a different solution to this problem. If you prefer either of the above solutions, or have other wild ideas, do let us know!

jfuss commented

@sdole Your statements make more sense to me now. Thank you for clarifying it.

Having this 'Stage Stage' being deployed is not ideal at all, no one likes it... Hopefully @sanathkr explanation clarifies a little deeper on what we have been thinking about and where we kind of stand on this (today).

Your statement about "I could have had the devs just as effectively use a non SAM template.". We want the opposite to be true. In many cases, we actually do reduce this effort but there are still some sharp edges to SAM we are trying to smooth out. It makes me sad, but I do understand where you are coming from. I would love to hear if there is actually more things that cause this feeling of "just use vanilla CloudFormation". I would like to keep this issue scoped to the Stage Stage discussion but welcome a deeper discussion on the pains you have encounter (or anyone for that matter) with using SAM.

sdole commented

@jfuss. For one example, when using SAM transform, it appears that the only way to get the transformed output is to local hard disk. That imposes a limit of 51,200 bytes on the template size. Granted that that is a lot of bytes, but, in our enterprise scenario, there are many units to consider. API GW, Lambda Resource Permissions, Headers, Versions, Aliases. Sometimes developers like to release more than one function in one template. All this adds up fairly quickly. We have 14 different environments (I know that sounds a bit crazy). If transform uploads template to S3, the size limit is 460,800 bytes. Much better.

For two: Before SAM came (or around the same time), I had written a GitHub hosted boto script to do what SAM does in terms of uploading code to S3, getting the new zip's version number and replacing it inside the template so that new code is deployed (without the version number - or a different file name - Cloudformation cannot know that code has changed). We use that extensively. It takes stack name, template parameters, create arguments and all such "never-changing" information from a yaml file we call "project" file. My script uses boto to read the project file, read the template and it's parameters to do packaging followed by creating a change set. The reason to state this is that the developer experience with this script is simple - create a "project" file, create a template and it's parameters and run 1 or 2 commands each time you want to deploy. This is simpler than when I use SAM on the AWS CLI. I need to write a long command string and get it right each time. Even if I used the generated cli skeleton to manage a few things, I still need to write long commands. So, neither SAM nor CF really are easy to use here.

Third, We use exports and imports extensively to deploy APIs and Lambda versions from stage to stage. So, create something in one API Stage, Test it in another stage, Release to prod in another stage (14 such stages). At the time of our testing SAM did not support all export/import. Then there was this very bug.

So, all in all, we don't use SAM much. Also, I doubt that large companies such as my clients will see the value of a developer focused workflow. We have had tremendous success with completely automating all aspects of releasing a serverless app using codepipeline. Our developers do not have any write permission in AWS except for checking in code. We will probably never go back to deploying anything AWS serverless by hand.

I do feel like I will find new value in SAM later, as more people adopt it. SAM may work well somehow with the AWS Cloud9 IDE. It might also find a place in re-usable/shareable constructs such as serverless application repository. But, that is from my narrow point of view.

Thank you for the invitation to discuss. I do find value in discussing with peers and leaders such as yourself. I truly hope not to offend or dishearten anyone.

I've simply added a delete-stage call to my CD setup removing the default "Stage" stage. @sanathkr am I understanding your comment correct in that this is something I should not be doing?

It seems to have worked without issues so far, but perhaps I'm asking for trouble..

@kadrach You are in dangerous territory if you modify resources created by CloudFormation, outside of the stack. But because Deployment is immutable, you should probably be fine.

Thank you @sanathkr, but the additional stage doesn't actually show in CF. Using SAM to deploy a single stage "master" into CF, I end up with a CF stack that has a single RestAPI resource with a single stage ("master"), but the RestAPI actually has two stages - the default stage "Stage" also exists, without being listed as part of the CloudFormation stack resources. How does that come about?

That is a side effect of APIGW::Deployment resource. When creating the Deployment resource, API Gateway creates a stage and associates this deployment to the stage. Since CloudFormation does not actively create the stage, it does not show up in the CFN Stack.

Is there any way to help with this issue? It has transformed into a dealbreaker for my context ..

Just in case, my own template that works great for my needs (2 stages, staging + prod):

Resources:

  CheckStatusFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: nway-CheckStatus
      # <assembly file>::<namespace.classname>::<method name>
      Handler: nwayapi::nWAY.API::CheckStatus   
      Role: !Sub "arn:aws:iam::${AWS::AccountId}:role/nway-lambdas"
  

  CheckStatusFunctionAPIMethod:
    Type: AWS::ApiGateway::Method
    Properties:
      RestApiId: !Ref nWAYApi
      ResourceId: !Ref ResourceChecks
      HttpMethod: POST
      AuthorizationType: NONE
      Integration:
        Type: AWS_PROXY
        IntegrationHttpMethod: POST
        Uri: !Sub "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${CheckStatusFunction.Arn}:${!stageVariables.lambdaAlias}/invocations"


  ################################
  # API Gateway definition                                                                                 
  ################################

  nWAYApi: 
    Type: "AWS::ApiGateway::RestApi"
    Properties:
      Description: "nWAY API"
      Name: "nway-api"

  ################################
  # API resources                                    
  #   /checks                                        
  ################################

  ResourceChecks: 
    Type: AWS::ApiGateway::Resource
    Properties: 
      RestApiId: !Ref nWAYApi
      ParentId: 
        Fn::GetAtt: 
          - nWAYApi
          - RootResourceId
      PathPart: "checks"

  ################################
  # deployment 'environments'                                  
  #   staging                                                   
  #   prod                                                        
  ################################

  # staging deployment
  Staging:
    Type: 'AWS::ApiGateway::Stage'
    DependsOn: nWAYApi
    Properties:
      StageName: staging
      Description: API Staging
      RestApiId: !Ref nWAYApi
      DeploymentId: !Ref StagingDeployment
      Variables:
        lambdaAlias: staging
  
  StagingDeployment: 
    DependsOn: 
      - CheckStatusFunctionAPIMethod
    Type: AWS::ApiGateway::Deployment
    Properties: 
      RestApiId: !Ref nWAYApi
  
  # prod deployment
  Prod:
    Type: 'AWS::ApiGateway::Stage'
    DependsOn: nWAYApi
    Properties:
      StageName: prod
      Description: API Production
      RestApiId: !Ref nWAYApi
      DeploymentId: !Ref StagingDeployment
      Variables:
        lambdaAlias: prod

  ProdDeployment: 
    DependsOn: 
      - CheckStatusFunctionAPIMethod
    Type: AWS::ApiGateway::Deployment
    Properties: 
      RestApiId: !Ref nWAYApi

@NachoColl Does this not create an extra 'Stage Stage' for you?

My issue is that not only do these "Stage" and "Prod" stages get created by default (I'm scaffolding the project with codestar btw), but if I try to delete one of these stages it prevents all future deploys from succeeding. :/

@JimTheMan , It shouldn't.- I use "staging" and "prod" stages on the same account (I generate the templates dynamically, and leave always 2 lambda versions per stage...), I used for dotnet but maybe you can get some ideas: https://github.com/NachoColl/aws-labs/tree/master/templates/dotNETCore-Lambdas-DevOps-Pipeline

if I try to delete one of these stages it prevents all future deploys from succeeding

That doesn't happen with me. I can delete it manually just fine.

So @sanathkr if this is a side effect of AWS::ApiGateway::Deployment, can the stages not be created differently with AWS::ApiGateway::Stage? If you could create the prod and stage stages this way, would it "override" this behavior of AWS::ApiGateway::Deployment? My thought process here is that if so, it may be possible to work around this behavior by doing first the creation of the stages, and then as the last step an "update stack" that removes the unneeded stage.

Just an idea, Its ugly and I don't know if it would work

Hi, is there an ETA for this fix? It's annoying this rouge stage gets created and we have to remove it manually. It's a recurring dev question and pain point across dev organization. Thanks

@JimTheMan Thanks for being part of the SAM community. The example you posted in your last comment is valuable, but it contained terms that violate our code of conduct so I removed it. Feel free to edit and re-post!

Any news about this? I use stages to discriminate API major versions, so my stages are v1, v2 and so on. Not being able to change this is really a show stopper.

@alethia for managing multiple versions of an API it is best to create this as 2 separate APIs rather than use Stages.

Just ran into this as well. Between this and the lack of conditionals, it feels like every time I turn to SAM to save some work, I end up having to go back to just using vanilla CloudFormation objects plus some Jinja2 templating to get what I want without a bunch of broken extra stuff.

I've been using SAM for about a month now. Kudos to the team and contributors for this wonderful tool!

Adding my 2 cents.

When AWS::Serverless::Api is explicitly defined and StageName (a required attribute) is set to Stage, deployment fails with Stage already exists when trying to create AWS::ApiGateway::Stage resource.

sam-stage-already-exists

The fix: Name the stage anything other than Stage (Staging in my case)

@jfuss @sanathkr I think it is highly likely that everyone will try to create Stage and Prod stages for staging and production stacks respectively. I'm not sure if makes sense to rename Stage stage to Default until we can remove the default stage.

#787

@jfuss @sanathkr Does this default Stage stage also explain the creation of the two AWS::Lambda::Permission resources in the transformed template named [FunctionName][EventName]Permission[StageName] (eg HelloWorldFunctionHelloWorldTestPermissionProd) and [FunctionName][EventName]PermissionTest (eg HelloWorldFunctionHelloWorldTestPermissionTest)?

@drvdijk yes, and IIRC the PermissionTest one is excessively broad and actually grants any stage access to invoke your function. It's insane to me that this hasn't been cleaned up yet.

I'm also having this issue and looking forward the fix.

Released with v1.13.0

To get around this bug, we added the fix for it behind the OpenApiVersion flag. To opt into this fix, you would need to specify OpenApiVersion flag like here. Regardless of the value (2.0, 3.0.1, etc), the stage stage fix will be applied if the flag is present.

stojy commented

It's not working for me. When I apply the flag to my existing working SAM templated stack I receive this error..

StageName cannot be updated

The only change to my template is to add the flag in my globals section..

Globals:
  Api:
    OpenApiVersion: '2.0'

When I remove the flag everything is fine again.

I investigated this issue (and this is a miss on our part):

Since adding that flag does not change the swagger, SAM runs into the old issue that a change is not detected in the API and a new deployment resource is not created. Any change that results in a new deployment of the API will contain this update.

Note: when the update happens, the Stage Stage will still be present in the API (cloudformation does not automatically delete it). However, this stage stops receiving updates from cloudformation and is safe to delete (it will not be added back in any future deployments as long as the OpenApiVersion flag is still present). Any API deployed for the first time with the OpenApiVersion flag set will not have the Stage Stage present.

A feature like that proposed in #660 to always deploy the API on every stack deployment would fix this issue and many others like it that SAM encounters.

@stojy Thanks so much for reporting this issue, and I'm sorry you're experiencing this error. We're working on a patch to address this bug.

To be clear, here is the exact scenario where this bug presents itself:

  1. You have an existing stack that was created from a template containing at least one function with at least one API event.
  2. You update the template to add OpenApiVersion: '2.0' and make no other changes that would modify the API definition.
  3. You attempt to update the deployed stack.

Until we get the fix deployed, here are 2 workarounds to remove the extra Stage Stage and not hit this deployment failure:

  1. Add the OpenApiVersion property with a value other than 2.0, e.g., 3.0.0, 3.0.1, etc. Note, this will change SAM's behavior to write an OpenAPI document with the version you specified instead of the default 2.0 value.
  2. Add the OpenApiVersion property with a value of 2.0 and make some other change to your template that would result in the swagger being modified. For example, you could add a new API event to one of your Lambda functions. As long as these two changes get deployed together, the deployment should succeed.
stojy commented

I can confirm that's the correct scenario steps and the workaround to explicitly change the swagger definition works.

Judging by the #1056, it looks like the fix for supporting openapi version changes is imminent? Do you know what the ETA might be?

Also, would it be possible to have the additional deployment stage 'Stage' deleted automatically? i.e. is the 'usual' case I believe when resources are not longer defined in a cf template.

@stojy We are cutting a patch fix for this (1.13.2), it will start rolling out to all regions soon. We will post again here once it is available in all regions.

About automatically deleting the stage: it looks like CloudFormation + ApiGateway don't delete that extra stage automatically, and since SAM is stateless, it doesn't know if there is a "Stage stage" already existing in the rest API. I also don't think it would be a good idea to add permissions and custom logic to delete stages in a customer's account.

stojy commented

Thanks for rolling out the patch so quickly.

Fair enough not wanting to write some custom logic to remove the obsolete stage 'Stage' deployment. We'll delete ours manually.

sdole commented

How do you install these latest versions? When I install SAM with pip, I get 0.19.0. PyPi shows that as the latest version. I am eager to try this out. Thanks!

Guess I really got lucky with timing! Thanks, my default "Stage" has been removed!
bitmoji

@sdole SAM is made up of two components: SAM translator and SAM CLI.

SAM translator is a CloudFormation transform managed by AWS. For fixes to the SAM translator (maintained in this GitHub repository), you do not need to install/upgrade any software to pick up the latest deployed changes.

SAM CLI is a client-side tool that you install on your local client. It is maintained in a separate GitHub repository, and you do have to update it to pick up new features/fixes. You can find more information on how to install SAM CLI here:

https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html

Hope this helps!

Hi there, I have added the OpenApiVersion flag to my globals and I'm getting this error when running sam validate: 'OpenApiVersion' is not a supported property of 'Api'.

Here's some of my template.yaml:

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
  api-gateway-test

Globals:
  Api:
    OpenApiVersion: '2.0'

Resources:
  GetUsersFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: src/
      Handler: app.lambdaHandler
      Runtime: nodejs10.x

  CustomAuthorizerFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: src/
      Handler: authorizer.handler
      Runtime: nodejs10.x
      Role:
        Fn::Sub: ${CustomAuthorizerFunctionRole.Arn}
  
  ServerlessRestAPI:
    Type: AWS::Serverless::Api
    Properties:
      Auth:
        DefaultAuthorizer: LambdaTokenAuthorizer 
        Authorizers:
          LambdaTokenAuthorizer:
            FunctionPayloadType: TOKEN
            FunctionArn: !GetAtt CustomAuthorizerFunction.Arn
            FunctionInvokeRole: !GetAtt CustomAuthorizerFunctionRole.Arn
            Identity:
              Headers:
                - Authorization
              ReauthorizeEvery: 30
      StageName: dev
      EndpointConfiguration: REGIONAL
      DefinitionBody:
        swagger: '2.0' 
        ...

Is this something to do with using a swagger definition, or have I missed something? I have updated the CLI to v0.19.0 as well.

Any help would be appreciated! Thanks.

@adam-roweit This is due to the SAM CLI performing the validation on your template when you run sam validate using an old release of the SAM Translator (which does not have this OpenApiVersion property yet). The SAM CLI hasn't been updated to use this new version of the SAM Translator as of yet.

The SAM Translator service sits within the CloudFormation service in AWS, rather than within the SAM CLI. If you were to take this template and use it directly in CloudFormation when updating your stack, it should work as expected.

There appears to be an issue created for the SAM CLI here which addresses the CLI not using the most up-to-date version of the SAM Translator.

Hope this helps!

@Daniel-Redmond Ah that makes perfect sense, thanks for your help!

Yes, this is a known issue with SAM CLI and should be addressed in the next SAM CLI release. @Daniel-Redmond Thanks for the great explanation!

To get around this bug, we added the fix for it behind the OpenApiVersion flag. To opt into this fix, you would need to specify OpenApiVersion flag like here. Regardless of the value (2.0, 3.0.1, etc), the stage stage fix will be applied if the flag is present.

Thanks. I tried it. This solutions works ONLY when one creates API from scratch. If an API was created before, and user adds OpenApiVersion: '2.0' to it, it doesn't remove "Stage" stage. It needs to be added from the beginning. Here is my code:

  MyApi:
    Type: AWS::Serverless::Api
    Properties:
      StageName: dev
      Cors:
        AllowMethods: "'GET,POST,DELETE,OPTIONS'"
        AllowHeaders: "'authorization'"
        AllowOrigin: "'*'"
      OpenApiVersion: '2.0'

Correct, I noticed this as well. CFN doesn't delete the extra stage, but that extra stage does stop getting updates from your CFN stack. To get rid of the extra stage, you have to manually delete it in ApiGateway (using either the CLI or console) and then it won't be created/updated any more if you have the OpenApiVersion flag set.

I've found the solution thanks to @azarboon and #191 (comment)

To avoid the unwanted "Stage" stage AND not get errors if you've already ended up with one, add the following to your SAM template at the top level AND be sure you have defined a stage using "StageName" on your AWS::Serverless:Api resource or otherwise.

I had to [for now] exclude the CORS options shown in the template provided in that post (this one).

Globals:
  Api:
    OpenApiVersion: 3.0.1

Thanks a lot! This worked perfectly.

wesgt commented

Thanks a lot! This solved my doubts.

Another (and perhaps the "better" approach) is to use AutoPublishAlias to control the name of the alias that will be used and automatically get new code. Below is an example of how to use this AND another alias to maintain a "staging" alias (latest code, will always point to the newest version deployed through SAM deploy) and a "live" alias (production code that must be updated to a newer version by some other mechanism). Note, this does depend on a custom resource to get the latest version (how I maintain the staging alias version). That's out of the scope here, but I'll share that code on request. More good info at sam-function-autopublishalias and automating-updates-to-serverless-apps.

SampleLambdaFunction:
    Type: AWS::Serverless::Function
    Properties:
        FunctionName: SampleLambda
        AutoPublishAlias: staging
        CodeUri: src/
        Handler: SampleLambda.handler
        Runtime: nodejs12.x
SampleLambdaLiveAlias:
    Type: AWS::Lambda::Alias
    Properties:
        FunctionName: !Ref SampleLambdaFunction
        FunctionVersion: !GetAtt SampleLambdaGetMaxVersionFunction.version
        Name: live

I've also setup a stackoverflow question to see if anyone has a better approach: how-to-use-sam-deploy-to-get-a-lambda-with-autopublishalias-and-additional-alises

To get around this bug, we added the fix for it behind the OpenApiVersion flag. To opt into this fix, you would need to specify OpenApiVersion flag like here. Regardless of the value (2.0, 3.0.1, etc), the stage stage fix will be applied if the flag is present.

Thanks. I tried it. This solutions works ONLY when one creates API from scratch. If an API was created before, and user adds OpenApiVersion: '2.0' to it, it doesn't remove "Stage" stage. It needs to be added from the beginning. Here is my code:

  MyApi:
    Type: AWS::Serverless::Api
    Properties:
      StageName: dev
      Cors:
        AllowMethods: "'GET,POST,DELETE,OPTIONS'"
        AllowHeaders: "'authorization'"
        AllowOrigin: "'*'"
      OpenApiVersion: '2.0'

Thanks for this.

Still facing the same issue - they all end in Stage or Prod, no matter my input parameter

image

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: SAM Template for annotator

Globals:
  Function:
    Timeout: 600
    MemorySize: 512
    Runtime: nodejs12.x
  Api:
    OpenApiVersion: '3.0.1'
    # See https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessapi
    BinaryMediaTypes:
      - "*~1*"

Parameters:
  StageName:
    Type: String
    Default: dev
    Description: (Required) Enter dev, test, stag, prod. Default is dev.
    AllowedValues:
      - dev
      - test
      - stag
      - prod

Resources:
  AnnotatorApi:
    Type: AWS::Serverless::Api
    Properties:
      StageName: !Ref StageName
      Auth:
        DefaultAuthorizer: JWTCustomAuthorizer
        Authorizers:
          JWTCustomAuthorizer:
            FunctionArn: !GetAtt AnnotatorApiAuthorizerFunction.Arn

I just opened issue aws/aws-sam-cli#3247 because StageName: !Ref Stage is being treated as an empty stage name (albeit template validation passes because the 'required' StageName property is technically present).

@iongion, what you're describing where whichever value you choose for your StageName parameter seems to take no effect sounds like running into the same issue.

StageName: !Ref Stage

Which will be weird because doing StageName: !Ref Stage actually deploys two stages, the actual value of !Ref Stage (say dev), and another one called "Stage".

  API:
    Type: AWS::Serverless::Api
    Properties:
      Name: myapp-api
      StageName: !Ref Stage

It creates a stage for whatever I provided in !Ref Stage and then it creates another one called Stage.

image

and !Ref Stage was resolved to dev but as you can see, there's an extra Stage in there, who created that? where that came from? Is still a mystery left unsolve.

My apologies, I misinterpreted what was happening because StageName: !Ref Stage creates an AWS::ApiGateway::Stage resource with logical id <gateway-resource-id>Stage rather than <gateway-resource-id><StageName>Stage, which is the case when StageName is hard-coded.

My stages are being deployed correctly, however it may be so because I've been using:

Properties:
  OpenApiVersion: 3.0.3

hmm...
When I use OpenApiVersion: 3.0.3 in my SAM template, I can deploy to one stage only. If I try to deploy to a new stage, the previous stage gets deleted. Is there a way to tell SAM not to delete a previously created stage?
If I create the second stage manually, then sam refuses to deploy to that new stage because it already exists...

How do you guys configure sam so that it can keep two stages and deploy to a specified stage?

@simplyi
See https://stackoverflow.com/questions/68826108/how-to-deploy-to-different-environments-with-aws-sam
You basically need to have different stacks. You can't control multiple API Gateways Stages from a sam template.

perfectly works (no stage created), but i have a strange issue #2377

This seems like a fundamental flaw of the SAM approach that this has been left open for years without being properly solved. I will use terraform based approach because of this as it seems more stable.