Terraform-provider-aws: Error creating API Gateway Stage: ConflictException: Stage already exists

Created on 10 Jan 2018  ·  22Comments  ·  Source: hashicorp/terraform-provider-aws

(See #1153. Since this issue was closed by the submitter and I can't re-open it, I'm duplicating it.)

Using resource "aws_api_gateway_deployment" together with a resource "aws_api_gateway_stage" of the same name results in a Error creating API Gateway Stage: ConflictException: Stage already exists.

Apart from the obvious issues with the documentation (as discussed in #1153), this seems to be caused by AWS creating a new stage for each create-deployment, rather than referencing it. I take this from the documentation:

--stage-name (string)

The name of the Stage resource for the Deployment resource to create.

--stage-description (string)

The description of the Stage resource for the Deployment resource to create.

Together with a stage of the same name (which may be required e.g. to assign a certificate to the stage), this leads to a conflict.

According to the documentation, the --stage-name and --stage-description parameters are optional. Terraform, however, treats them as required parameters. The stage_name parameter of the aws_api_gateway_deployment resource should be optional.

Minimal example to reproduce the problem:

resource "aws_api_gateway_rest_api" "my_api" {
  name = "My API"
}

resource "aws_api_gateway_stage" "prod" {
  stage_name            = "prod"
  rest_api_id           = "${aws_api_gateway_rest_api.my_api.id}"
  deployment_id         = "${aws_api_gateway_deployment.my_deployment.id}"
  client_certificate_id = "${var.client_cert_id}" // This is why I need the explicit resource and cannot rely on the one implicitly created by `aws_api_gateway_deployment.my_deployment`.
  description           = "foo"
}

resource "aws_api_gateway_deployment" "my_deployment" {
  rest_api_id = "${aws_api_gateway_rest_api.my_api.id}"
  stage_name  = "prod" // This tries to *create* a stage, which then conflicts with `aws_api_gateway_stage.prod`. This parameter should be optional!
}
enhancement servicapigateway

Most helpful comment

@Puneeth-n Interesting, I haven't tried via the AWS CLI, just had a look at the docs. However, I have found a workaround: Just leave stage_name empty (i.e. stage_name = ""), and aws_api_gateway_deployment will not create an additional stage.

Full example:

resource "aws_api_gateway_rest_api" "my_api" {
  name = "My API"
}

resource "aws_api_gateway_stage" "prod" {
  stage_name            = "prod"
  rest_api_id           = "${aws_api_gateway_rest_api.my_api.id}"
  deployment_id         = "${aws_api_gateway_deployment.my_deployment.id}"
  client_certificate_id = "${var.client_cert_id}"
  description           = "foo"
}

resource "aws_api_gateway_deployment" "my_deployment" {
  rest_api_id = "${aws_api_gateway_rest_api.my_api.id}"
  stage_name  = "" // Works for me: No error, does not create a stage
}

So even if the AWS API (I'm talking about the Go SDK) indeed requires the StageName to be present, it apparently can still be left empty and have the desired effect.

So I'm still thinking that the field should be optional, maybe by defaulting a missing stage_name to an empty string in https://github.com/terraform-providers/terraform-provider-aws/blob/ddd2205c6b6cc547ce5a940f9a16bf66f3276c3a/aws/resource_aws_api_gateway_deployment.go#L84

All 22 comments

@fmthoma I think the aws documentation is misleading. I tried it on an existing RESTAPI I had in a test environment and deployment failed. Meaning, cannot deploy without specifying stage name.

====> aws apigateway create-deployment --rest-api-id jhefbjhwfbcw

An error occurred (BadRequestException) when calling the CreateDeployment operation: Invalid deployment content specified.CreateDeploymentInput should not be null.

====> aws apigateway create-deployment --rest-api-id jhefbjhwfbcw --stage-name foo

{
    "id": "jhbfrhrb",
    "createdDate": 1515598231
}

@fmthoma I encountered this issue few months ago. The way I handled it is to deploy to an intermediate stage and use the deployment id to create the final stage.

Elaborating my answer here

resource "aws_api_gateway_deployment" "zendesk-deployment" {
  rest_api_id       = "${aws_api_gateway_rest_api.zendesk.id}"
  stage_name        = "intermediate"
  stage_description = "Deployed at: ${timestamp()}"

  depends_on = ["aws_api_gateway_integration.zendesk-lambda-integration", "aws_api_gateway_method.zendesk-log-method"]
}

resource "aws_api_gateway_stage" "stage" {
  stage_name    = "${var.environment}"
  rest_api_id   = "${aws_api_gateway_rest_api.zendesk.id}"
  deployment_id = "${aws_api_gateway_deployment.zendesk-deployment.id}"
}

@Puneeth-n Interesting, I haven't tried via the AWS CLI, just had a look at the docs. However, I have found a workaround: Just leave stage_name empty (i.e. stage_name = ""), and aws_api_gateway_deployment will not create an additional stage.

Full example:

resource "aws_api_gateway_rest_api" "my_api" {
  name = "My API"
}

resource "aws_api_gateway_stage" "prod" {
  stage_name            = "prod"
  rest_api_id           = "${aws_api_gateway_rest_api.my_api.id}"
  deployment_id         = "${aws_api_gateway_deployment.my_deployment.id}"
  client_certificate_id = "${var.client_cert_id}"
  description           = "foo"
}

resource "aws_api_gateway_deployment" "my_deployment" {
  rest_api_id = "${aws_api_gateway_rest_api.my_api.id}"
  stage_name  = "" // Works for me: No error, does not create a stage
}

So even if the AWS API (I'm talking about the Go SDK) indeed requires the StageName to be present, it apparently can still be left empty and have the desired effect.

So I'm still thinking that the field should be optional, maybe by defaulting a missing stage_name to an empty string in https://github.com/terraform-providers/terraform-provider-aws/blob/ddd2205c6b6cc547ce5a940f9a16bf66f3276c3a/aws/resource_aws_api_gateway_deployment.go#L84

@fmthoma you are right there. I just checked it from the awscli

apigateway create-deployment --rest-api-id jhgrvfhjrbfhj --stage-name ""

{
    "id": "kjdsbf",
    "createdDate": 1515662092
}

I think too that the stage_name should be optional!

@fmthoma I'm working on a PR to fix this.

@Puneeth-n @fmthoma It's a chicken and egg situation.

A stage depends on a deployment and a deployment (despite the misleading docs) depends on a stage.

AWS suggest to use a _dummy stage_ (the conclusion you reached eventually using an empty name) because if the deployment is deleted (not unlikely, it's just a snapshot of your API in time) the stage will go with it.

@ilazakis

AWS suggest to use a dummy stage (the conclusion you reached eventually using an empty name) because if the deployment is deleted (not unlikely, it's just a snapshot of your API in time) the stage will go with it.

Do you have a source for this?

The documentation for the CLI suggests that the --stage-name parameter is optional, although it does not seem to be in reality. However, the difference between --stage-name dummy and --stage-name "" is that the former creates a stage called dummy, while the latter does not create a stage at all. So for me this suggests that

[…] a deployment (despite the misleading docs) depends on a stage.

is not true, although I'm only inferring that from circumstantial evidence, not from exact knowledge.

I'd really be interested in the source where AWS itself suggests to use a dummy stage.

@fmthoma

Do you have a source for this?

Yes, the docs are quoted here and on the AWS forums . Removed from the docs since, but maybe possible to retrieve somehow.

Nice catch on the empty string; I have been creating dummy stages since forever, thanks!

The empty string doesn't work anymore, but I've seen that you can enter a different stage name in the "aws_api_gateway_deployment" section than in the "aws_api_gateway_stage" section. For instance "stagename-temp" in the "aws_api_gateway_deployment' section, and "stagename" in the "aws_api_gateway_stage" section. This works fine, in fact it works so fine that it creates a "stagename-temp" stage, which seems that it's deleted afterwards; after the entire terraform script is run, I have only the "stagename" section.

So, that looks like a workaround to this bug. Of course, it would be nicer if the bug had been fixed and we could use the same stage name for both sections.

@vlad2 could you post a complete working example of your workaround ? thank you

This is currently broken for me. I did not find a better workaround than importing the aws_api_gateway_stage resource after the error:

aws_api_gateway_stage.stage: Error creating API Gateway Stage: ConflictException: Stage already exists

The next terraform runs after importing the resource will work.
Please fix in the provider upstream.

If I set the stage_name in the source as Optional, it work like a charm for me.

@sousmangoosta thanks for this feedback. Did you push your patch anywhere ? Would you submit a PR ? thank you

@zioproto : I opened a PR for my line change :)

The change to make stage_name optional has been merged and will release with version 2.3.0 of the Terraform AWS Provider, likely middle of next week.

This has been released in version 2.3.0 of the Terraform AWS provider. Please see the Terraform documentation on provider versioning or reach out if you need any assistance upgrading.

This doesn't appear to be fixed in the latest 2.3.0 provider release, we receive an error that stage_name does not exist:
Downloading plugin for provider "aws" (2.3.0)
...
Resource 'aws_api_gateway_deployment.app' does not have attribute 'stage_name' for variable 'aws_api_gateway_deployment.app.stage_name'

@clocked0ne if I was to offer a guess without seeing your configuration and plan output, you cannot currently reference the stage_name as an attribute if it is not defined as an argument or specified as an empty string (e.g. stage_name = ""). Support for this will require an additional lookup of the stage name based on the deployment ID, which the resource should have been doing before anyways for drift detection.

Or put more thoroughly for someone who might want to fix this, we need to get acceptance tests passing with resource.TestCheckResourceAttr() (if the value is known) or resource.TestCheckResourceAttrSet() (if the value is unknown) instead of resource.TestCheckNoResourceAttr() in the acceptance tests here:

https://github.com/terraform-providers/terraform-provider-aws/blob/b4d6106a4e17f428c137c3cf9ccc3abc229c1f00/aws/resource_aws_api_gateway_deployment_test.go#L125-L171

Can you please open a new GitHub issue filling out all the details so we can ensure we can appropriately triage your situation? Thanks.

Thanks for the suggestion, I think you are right and I will open a new ticket referencing this one. 👍

The workaround of creating a deployment with no stage name, then a stage with the desired stage name that references the initial deployment doesn't work for me, for the following reasons:

  • the stage of the desired name gets created, but the API doesn't get deployed in a workable form under that name - this needs to be corrected with a deploy action in the CLI or the console, outside of terraform. In particular, when browsing the API in the console, the stage tree is devoid of the expected resource path nodes - these only reappear with a separate deployment action
  • the next time terraform apply runs, terraform resets the stage's deployment id to refer to the original deployment id which doesn't have a workable deployment of the API.

The workaround that did work for me was to apply the deployment resource first, then import the stage resource.

I also experience the same problem @jonseymour had.

If I use aws_api_gateway_deployment then I cant use aws_api_gateway_stage to enable access logging. If I use all the workarounds listed above like setting the deployment stage name to "" then terraform deploys fine but all requests to the API gateway result in 403's.

Even deploying the stage again from CLI or Console doesn't fix this for me.

@bflad

I'm going to lock this issue because it has been closed for _30 days_ ⏳. This helps our maintainers find and focus on the active issues.

If you feel this issue should be reopened, we encourage creating a new issue linking back to this one for added context. Thanks!

Was this page helpful?
0 / 5 - 0 ratings