aws / serverless-application-model

The AWS Serverless Application Model (AWS SAM) transform is a AWS CloudFormation macro that transforms SAM templates into CloudFormation templates.
https://aws.amazon.com/serverless/sam
Apache License 2.0
9.33k stars 2.38k forks source link

BasePathMapping deployment error: Invalid stage identifier specified #192

Open cluggas opened 7 years ago

cluggas commented 7 years ago

I have a SAM template deploying three resources: An ApiGateway, a Lambda Function and a ApiGateway BasePathMapping.

    AWSTemplateFormatVersion: '2010-09-09'
    Transform: AWS::Serverless-2016-10-31
    Parameters:
      StageName:
        Type: String
    Resources:
      api:
        Type: AWS::Serverless::Api
        Properties:
          DefinitionBody: ...
          StageName: !Ref StageName
      apidomain:
        Type: AWS::ApiGateway::BasePathMapping
        Properties:
          DomainName: mydomain.com
          RestApiId: !Ref api
          Stage: !Ref StageName
      lambda:
        Type: AWS::Serverless::Function
        Properties: ...

There is one parameter to the template called StageName, and this is used in two places:

  1. The StageName for the ApiGateway
  2. The Stage value for the BasePathMapping

When this stack is deployed, Cloud Formation deploys things in a strange order. It deploys the Api Gateway before the BasePathMapping, which you would expect, but deploying the ApiGateway stage is a separate step. It tries to deploy the BasePathMapping before the ApiGateway Stage, which results in the error:

Invalid stage identifier specified

This is totally underdtandable given it has not been created yet.

I have tried using the DependsOn property on the BasePathMapping resource to force it to get created after the ApiGateway. It does, but not after the ApiGateway stage.

Does anyone know a way around this? It feels like a bug with the AWS::Serverless::Api resource type. It clearly needs to create a Gateway and a Stage, but the should be done sequentially not not allow the BasePathMapping to be created in between.

Work arounds I don't like include:

  1. A two stage deployment. First without the BasePathMapping, then with it
jvanbrunschot-coolblue commented 6 years ago

I got a workaround for this.. Apparently when using SAM (aws cloudformation deploy) it uses the transform (Transform: AWS::Serverless-2016-10-31) rule set in your template to generate all kind of "extra" resources. One of them is a aws::ApiGateway::stage resource. The name of this resource is ServerlessApiStage where ServerlessApi is the name of the AWS::Serverless::Api resource.

sanathkr commented 6 years ago

This might be a documentation issue. We are using a standard mechanism for constructing resource names. You should be able to use "DependsOn" to chain the resource creation in correct order. I will update the docs to explain how the resource names are created.

JimLynchCodes commented 6 years ago

I really don't understand why it's trying to redeploy my API gateway stages in the first place. If my function that an API gateway resource is using is pointing to ":Latest" then why do we need to redeploy?

darrendao commented 6 years ago

I'm having similar issue.

I tried using DependsOn to specify that the BasePathMapping depends on my AWS::ApiGateway::DomainName and AWS::Serverless::Api resource, but it is still created before Stage is created. I'm guessing that's because Stage is a separate resource outside of AWS::Serverless::Api.

darrendao commented 6 years ago

Thanks to @jvanbrunschot-coolblue 's comment, I was able to find a workaround. It looks like ServerlessApiStage is indeed a separate resource outside of AWS::Serverless::Api, and is generated by the transform function. So my workaround is to figure out what the generated resource name would be for the stage and specify that in the DependsOn section of the AWS::ApiGateway::BasePathMapping resource.

rodmaz commented 6 years ago

Indeed it seems to be a bug, which disregards the dependencies between these resources. I am using SAM CLI 0.4.0 and AWS CLI 1.11.131 and had the same problem. In my case the final template generate by Cloudformation produced the stage name as a concatenation of my API logical name and word Stage: <myApiLogicalName>Stage.

Fixed the problem by adding a DependsOn on AWS::ApiGateway::BasePathMapping as seen below:

  # ########################################################################
  # Mobile API
  apiMobile:
    Type: 'AWS::Serverless::Api'
    Properties:
      Name: mobile-api
      StageName: !FindInMap [ApiStage, !Ref Environment, stage]
      DefinitionBody:
        'Fn::Transform':
          Name: 'AWS::Include'
          Parameters:
            Location: 's3://<redacted>/swagger.yaml'
      EndpointConfiguration: REGIONAL

  # ###################################################################
  # Base Path Mapping
  apiBasePathMapping:
    Type: 'AWS::ApiGateway::BasePathMapping'
    Properties:
      BasePath: v1.0
      Stage: !FindInMap [ApiStage, !Ref Environment, stage]
      DomainName:
        'Fn::Sub':
          - 'mobile-api${Suffix}.<redacted>'
          - Suffix: !FindInMap
            - EnvironmentShort
            - !Ref Environment
            - suffix
      RestApiId: !Ref apiMobile
    DependsOn:
      - apiMobileStage  <------ Added explicit dependency
stijnvanrenterghem commented 6 years ago

Hi, I had to add apiStage and not only Stage.

aws-cli/1.15.66 SAM CLI, version 0.5.0

nikhil1007 commented 5 years ago

Hi, So i was stuck in the same scenario and after a lot of help from the above comments and a little trial and error on my end. The format of the aws::ApiGateway::stage is => (name of the serverless api resource)(stage name)Stage

brettstack commented 5 years ago

Adding a DomainName property to the AWS::Serverless::API resources which configures this all for you is probably what we want here.

ericofusco commented 5 years ago

Having Domain and Certificate parameters makes sense to me. If Certificate is not passed AWS::Serverless::API could create AWS::CertificateManager::Certificate resource too.

tkeeber commented 5 years ago

Any update on this? Would great to make this easier. Ran into this problem again recently. If need to understand the inner of an abstraction (i.e SAM) in order to use it then surely it's not doing its job?

brettstack commented 5 years ago

I added an RFC for this here https://github.com/awslabs/serverless-application-model/issues/783. I'm going to close out this issue as a workaround has been posted, and we have a path forward to a simpler solution.

alfredo-g-zapiola commented 5 years ago

Indeed it seems to be a bug, which disregards the dependencies between these resources. I am using SAM CLI 0.4.0 and AWS CLI 1.11.131 and had the same problem. In my case the final template generate by Cloudformation produced the stage name as a concatenation of my API logical name and word Stage: <myApiLogicalName>Stage.

Fixed the problem by adding a DependsOn on AWS::ApiGateway::BasePathMapping as seen below:

  # ########################################################################
  # Mobile API
  apiMobile:
    Type: 'AWS::Serverless::Api'
    Properties:
      Name: mobile-api
      StageName: !FindInMap [ApiStage, !Ref Environment, stage]
      DefinitionBody:
        'Fn::Transform':
          Name: 'AWS::Include'
          Parameters:
            Location: 's3://<redacted>/swagger.yaml'
      EndpointConfiguration: REGIONAL

  # ###################################################################
  # Base Path Mapping
  apiBasePathMapping:
    Type: 'AWS::ApiGateway::BasePathMapping'
    Properties:
      BasePath: v1.0
      Stage: !FindInMap [ApiStage, !Ref Environment, stage]
      DomainName:
        'Fn::Sub':
          - 'mobile-api${Suffix}.<redacted>'
          - Suffix: !FindInMap
            - EnvironmentShort
            - !Ref Environment
            - suffix
      RestApiId: !Ref apiMobile
    DependsOn:
      - apiMobileStage  <------ Added explicit dependency

THIS IS IT THANKS FOR TAKING ME OUT OF MY DESPERATION PIT

ca0abinary commented 5 years ago

For me the solution was:

Resources:
  Api:
    Type: AWS::Serverless::Api
    Properties:
      StageName: Prod
      Auth:
        DefaultAuthorizer: NONE
  BasePathMapping:
    Type: AWS::ApiGateway::BasePathMapping
    Properties:
      DomainName: !Ref GatewayDomain
      RestApiId: !Ref Api
      Stage: !Ref Api.Stage

Notice the BasePathMapping.Stage is set to !Ref Api.Stage which creates tight coupling and removes potential user errors such as typos.

praneetap commented 5 years ago

@ca0abinary Thanks for the comment! This will be a really good addition to the examples folder. Reopening this issue.

made2591-eb commented 4 years ago

Indeed it seems to be a bug, which disregards the dependencies between these resources. I am using SAM CLI 0.4.0 and AWS CLI 1.11.131 and had the same problem. In my case the final template generate by Cloudformation produced the stage name as a concatenation of my API logical name and word Stage: <myApiLogicalName>Stage. Fixed the problem by adding a DependsOn on AWS::ApiGateway::BasePathMapping as seen below:

  # ########################################################################
  # Mobile API
  apiMobile:
    Type: 'AWS::Serverless::Api'
    Properties:
      Name: mobile-api
      StageName: !FindInMap [ApiStage, !Ref Environment, stage]
      DefinitionBody:
        'Fn::Transform':
          Name: 'AWS::Include'
          Parameters:
            Location: 's3://<redacted>/swagger.yaml'
      EndpointConfiguration: REGIONAL

  # ###################################################################
  # Base Path Mapping
  apiBasePathMapping:
    Type: 'AWS::ApiGateway::BasePathMapping'
    Properties:
      BasePath: v1.0
      Stage: !FindInMap [ApiStage, !Ref Environment, stage]
      DomainName:
        'Fn::Sub':
          - 'mobile-api${Suffix}.<redacted>'
          - Suffix: !FindInMap
            - EnvironmentShort
            - !Ref Environment
            - suffix
      RestApiId: !Ref apiMobile
    DependsOn:
      - apiMobileStage  <------ Added explicit dependency

THIS IS IT THANKS FOR TAKING ME OUT OF MY DESPERATION PIT

Thank you it worked for me SAM 0.22.0 I had the same issue: just refer the object with the same name plus stage. To verify you are referring the right resources compiled by sam, I suggest to run sam validate --debug and verify the name :-) thank you again!

mpvosseller commented 4 years ago

If anyone is using an Http protocol API and the AWS::ApiGatewayV2:ApiMapping I solved this by referencing ServerlessHttpApiApiGatewayDefaultStage for stage.

  ApiMapping:
    Type: AWS::ApiGatewayV2::ApiMapping
    Properties:
      ApiId: !Ref ServerlessHttpApi
      DomainName: !Ref ApiDomainName
      Stage: !Ref ServerlessHttpApiApiGatewayDefaultStage
Delermando commented 4 years ago

@ca0abinary Use "!Ref Api.Stage" as reference works here!! Thanks!!!

knowledgeshare99 commented 4 years ago

it works perfect for me Use "!Ref Api.Stage"

paul-uz commented 3 years ago

I had this issue and not even AWS Support knew the answer 🤦

@ca0abinary 's solution worked perfectly.

tcanady commented 3 years ago

This worked for me: https://github.com/aws/serverless-application-model/issues/192#issuecomment-351527399

Apparently this is still an issue.

SaundersB commented 3 years ago

Worked for me as well. Thank you.

yortch commented 2 years ago

Based on the link below this should have been fixed by adding a DependsOn to <api‑LogicalId><stage‑name>Stage (as documented in this link: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-generated-resources-api.html)

Template format error: Unresolved resource dependencies [RestAPIGatewaydevelopmentStage] in the Resources block of the template

AWSTemplateFormatVersion: 2010-09-09
Transform: AWS::Serverless-2016-10-31
Parameters:
  APIStageName:
    Type: 'AWS::SSM::Parameter::Value<String>'
    Description: The name of the stage to deploy the API to.
    Default: /account/environment
Resources:    
  RestAPIGateway:
    Type: AWS::ApiGateway::RestApi
...
  APICustomDomainMapping:
    Type: AWS::ApiGateway::BasePathMapping
    DependsOn: 
     - RestAPIGatewaydevelopmentStage
    Properties:
      DomainName: !Ref APICustomDomain
      RestApiId: !Ref RestAPIGateway
      Stage: !Ref APIStageName

It is hard to believe that this issue has not been addressed after almost 5 years. It seems that adding an explicit dependson on the stage generated during translation should fix this.

yortch commented 2 years ago

We got this to work by adding a WaitConditionHandle on the suggested stage name. Not clear why this does not work directly on the DependsOn, but in case it matters we are using AWS CLI 2.0 from CodeBuild project using aws/codebuild/standard:5.0 image.

  StageCreated:
    Type: AWS::CloudFormation::WaitConditionHandle
    Metadata:
      Created: !Sub RestAPIGateway${APIStageName}Stage

  APICustomDomainMapping:
    Type: AWS::ApiGateway::BasePathMapping
    DependsOn: 
     - StageCreated

The impact of this issue is that since it's a timing issue it some times work, so imagine it works in dev/test environments and it happens to fail in the production deployment, that would be a very bad experience.

yaminir commented 2 years ago

The workaround does not seem to work for my client. I think the difference is that we're using a RestApi vs Api and maybe that's why the workaround doesn't work for us. Does anybody still have the issue?

yortch commented 2 years ago

Thank you @yaminir, I think we were finally able to fix this permanently by adding an explicit Stage resource, which allowed us to create an explicit dependency:

  RestAPIGateway:
    Type: AWS::ApiGateway::RestApi
    ...
  ApiGatewayDeployment:
    Type: AWS::ApiGateway::Deployment
    Properties:
      RestApiId: !Ref RestAPIGateway
  APIGatewayStage:
    Type: "AWS::ApiGateway::Stage"
    Properties:
      DeploymentId: !Ref ApiGatewayDeployment
      RestApiId: !Ref RestAPIGateway
      StageName: !Ref APIStageName
  APICustomDomainMapping:
    Type: AWS::ApiGateway::BasePathMapping
    DependsOn:
     - APIGatewayStage
    Properties:
      DomainName: !Ref APICustomDomain
      RestApiId: !Ref RestAPIGateway
      Stage: !Ref APIStageName
Leigh-M commented 1 year ago

I ran into this when adding a custom domain name, resolved simply with DependsOn the API like:

  MyCustomDomainName:
    Type: AWS::ApiGateway::DomainName
    Properties:
      RegionalCertificateArn: arn:aws:acm:eu-west-1:2345678:certificate/0000000-11111-2222-3333-444444444
      DomainName: some-api.prd.some-domain.com
      SecurityPolicy: TLS_1_2
      EndpointConfiguration:
        Types:
          - REGIONAL
    DependsOn:
     - yourRestAPIResource
vsimoesbh commented 1 year ago

Hello everyone,

Yes this error is mostly due the stage not being created yet. So youre trying to map the custom domain to something that doesnt exist. In my case i am using serverless framework and i could not find the mapping reference resource. In any case after lot of testing, using dependson with these solved for me.

DependsOn:

maxidorius commented 1 year ago

Indeed it seems to be a bug, which disregards the dependencies between these resources. I am using SAM CLI 0.4.0 and AWS CLI 1.11.131 and had the same problem. In my case the final template generate by Cloudformation produced the stage name as a concatenation of my API logical name and word Stage: <myApiLogicalName>Stage.

Fixed the problem by adding a DependsOn on AWS::ApiGateway::BasePathMapping as seen below:

  # ########################################################################
  # Mobile API
  apiMobile:
    Type: 'AWS::Serverless::Api'
    Properties:
      Name: mobile-api
      StageName: !FindInMap [ApiStage, !Ref Environment, stage]
      DefinitionBody:
        'Fn::Transform':
          Name: 'AWS::Include'
          Parameters:
            Location: 's3://<redacted>/swagger.yaml'
      EndpointConfiguration: REGIONAL

  # ###################################################################
  # Base Path Mapping
  apiBasePathMapping:
    Type: 'AWS::ApiGateway::BasePathMapping'
    Properties:
      BasePath: v1.0
      Stage: !FindInMap [ApiStage, !Ref Environment, stage]
      DomainName:
        'Fn::Sub':
          - 'mobile-api${Suffix}.<redacted>'
          - Suffix: !FindInMap
            - EnvironmentShort
            - !Ref Environment
            - suffix
      RestApiId: !Ref apiMobile
    DependsOn:
      - apiMobileStage  <------ Added explicit dependency

@rodmaz You saved my life, I was also hit by this

rgplvr commented 7 months ago

This was fixed for me by adding a Depends on

like follows


RestApi:
    Type: AWS::Serverless::Api
ApiBasePathMapping
   Type: AWS::ApiGateway::BasePathMapping
   DependsOn: 
     -RestApiStage // the name of the AWS::Serverless::Api appeneded with Stage here the name is RestApi(line No 1) and the stage is appended