Terraform not deploying api gateway stage

terraform api gateway stage
terraform api gateway resource policy
terraform api gateway example
terraform api gateway stage already exists
terraform api gateway not deploying
badrequestexception: active stages pointing to this deployment must be moved or deleted
terraform api gateway tags
error creating api gateway deployment: badrequestexception: no integration defined for method

I have been trying to create an API Gateway endpoint using terraform. Everything seems to be working except the last part of deploying a stage.

After I run terraform apply I go into the console and I find that the deployment has not happened. I need to manually click on Deploy Api in order to get it working.

Here's the terraform file for the api gateway.

variable "region" {}
variable "account_id" {}

resource "aws_api_gateway_rest_api" "online_tax_test_client_report_endpoint_api" {
  name = "online_tax_test_client_report_endpoint_api"
  description = "The endpoint that test has to hit when new client reports are available."
  depends_on = ["aws_lambda_function.onlinetax_test_endpoint_lambda"]
}

resource "aws_api_gateway_resource" "test_client_report_resource" {
  rest_api_id = "${aws_api_gateway_rest_api.online_tax_test_client_report_endpoint_api.id}"
  parent_id = "${aws_api_gateway_rest_api.online_tax_test_client_report_endpoint_api.root_resource_id}"
  path_part = "test_client_report"
}

resource "aws_api_gateway_method" "test_client_report_method" {
  rest_api_id = "${aws_api_gateway_rest_api.online_tax_test_client_report_endpoint_api.id}"
  resource_id = "${aws_api_gateway_resource.test_client_report_resource.id}"
  http_method = "POST"
  authorization = "NONE"
}

resource "aws_api_gateway_integration" "test_client_report_resource_integration" {
  rest_api_id = "${aws_api_gateway_rest_api.online_tax_test_client_report_endpoint_api.id}"
  resource_id = "${aws_api_gateway_resource.test_client_report_resource.id}"
  http_method = "${aws_api_gateway_method.test_client_report_method.http_method}"
  type = "AWS"
  integration_http_method = "${aws_api_gateway_method.test_client_report_method.http_method}"
  uri = "arn:aws:apigateway:${var.region}:lambda:path/2015-03-31/functions/${aws_lambda_function.onlinetax_test_endpoint_lambda.arn}/invocations"
  request_templates = {
    "application/json" = "${file("${path.module}/generic_request_mapping_template.vm")}"
  }
}

resource "aws_api_gateway_method_response" "200" {
  rest_api_id = "${aws_api_gateway_rest_api.online_tax_test_client_report_endpoint_api.id}"
  resource_id = "${aws_api_gateway_resource.test_client_report_resource.id}"
  http_method = "${aws_api_gateway_method.test_client_report_method.http_method}"
  status_code = "200"
}

resource "aws_api_gateway_integration_response" "test_client_report_resource_integration_default_response" {
  rest_api_id = "${aws_api_gateway_rest_api.online_tax_test_client_report_endpoint_api.id}"
  resource_id = "${aws_api_gateway_resource.test_client_report_resource.id}"
  http_method = "${aws_api_gateway_method.test_client_report_method.http_method}"
  status_code = "${aws_api_gateway_method_response.200.status_code}"
  selection_pattern = ""
  depends_on = ["aws_api_gateway_integration.test_client_report_resource_integration"]
}

resource "aws_api_gateway_method_response" "500" {
  rest_api_id = "${aws_api_gateway_rest_api.online_tax_test_client_report_endpoint_api.id}"
  resource_id = "${aws_api_gateway_resource.test_client_report_resource.id}"
  http_method = "${aws_api_gateway_method.test_client_report_method.http_method}"
  status_code = "500"
}

resource "aws_api_gateway_integration_response" "test_client_report_resource_integration_error_response" {
  rest_api_id = "${aws_api_gateway_rest_api.online_tax_test_client_report_endpoint_api.id}"
  resource_id = "${aws_api_gateway_resource.test_client_report_resource.id}"
  http_method = "${aws_api_gateway_method.test_client_report_method.http_method}"
  status_code = "${aws_api_gateway_method_response.500.status_code}"
  selection_pattern = ".*?Error.*"
  depends_on = ["aws_api_gateway_integration.test_client_report_resource_integration"]
}

resource "aws_lambda_permission" "allow_api_gateway" {
    statement_id = "AllowExecutionFromAPIGateway"
    action = "lambda:InvokeFunction"
    function_name = "${aws_lambda_function.onlinetax_test_endpoint_lambda.arn}"
    principal = "apigateway.amazonaws.com"
    source_arn = "arn:aws:execute-api:${var.region}:${var.account_id}:${aws_api_gateway_rest_api.online_tax_test_client_report_endpoint_api.id}/*/${aws_api_gateway_integration.test_client_report_resource_integration.integration_http_method}${aws_api_gateway_resource.test_client_report_resource.path}"
    depends_on = ["aws_api_gateway_rest_api.online_tax_test_client_report_endpoint_api"]
}

#This is the part that doesn't seem to work. 
resource "aws_api_gateway_deployment" "qa5" {
  rest_api_id = "${aws_api_gateway_rest_api.online_tax_test_client_report_endpoint_api.id}"
  stage_name = "qa5"
  depends_on = ["aws_api_gateway_method.test_client_report_method"]
}
Edit

Added the graph in :

    digraph {
        compound = "true"
        newrank = "true"
        subgraph "root" {
            "[root] module.lambda.aws_api_gateway_deployment.qa5" [label = "aws_api_gateway_deployment.qa5", shape = "box"]
            "[root] module.lambda.aws_api_gateway_integration.sbr_client_report_resource_integration" [label = "aws_api_gateway_integration.sbr_client_report_resource_integration", shape = "box"]
            "[root] module.lambda.aws_api_gateway_integration_response.sbr_client_report_resource_integration_default_response" [label = "aws_api_gateway_integration_response.sbr_client_report_resource_integration_default_response", shape = "box"]
            "[root] module.lambda.aws_api_gateway_integration_response.sbr_client_report_resource_integration_error_response" [label = "aws_api_gateway_integration_response.sbr_client_report_resource_integration_error_response", shape = "box"]
            "[root] module.lambda.aws_api_gateway_method.sbr_client_report_method" [label = "aws_api_gateway_method.sbr_client_report_method", shape = "box"]
            "[root] module.lambda.aws_api_gateway_method_response.200" [label = "aws_api_gateway_method_response.200", shape = "box"]
            "[root] module.lambda.aws_api_gateway_method_response.500" [label = "aws_api_gateway_method_response.500", shape = "box"]
            "[root] module.lambda.aws_api_gateway_resource.sbr_client_report_resource" [label = "aws_api_gateway_resource.sbr_client_report_resource", shape = "box"]
            "[root] module.lambda.aws_api_gateway_rest_api.online_tax_sbr_client_report_endpoint_api" [label = "aws_api_gateway_rest_api.online_tax_sbr_client_report_endpoint_api", shape = "box"]
            "[root] module.lambda.aws_iam_role.onlinetax_sbr_endpoint_role" [label = "aws_iam_role.onlinetax_sbr_endpoint_role", shape = "box"]
            "[root] module.lambda.aws_iam_role_policy.publish_to_sns_policy" [label = "aws_iam_role_policy.publish_to_sns_policy", shape = "box"]
            "[root] module.lambda.aws_iam_role_policy.write_to_cloudwatch_policy" [label = "aws_iam_role_policy.write_to_cloudwatch_policy", shape = "box"]
            "[root] module.lambda.aws_lambda_function.onlinetax_sbr_endpoint_lambda" [label = "aws_lambda_function.onlinetax_sbr_endpoint_lambda", shape = "box"]
            "[root] module.lambda.aws_lambda_permission.allow_api_gateway" [label = "aws_lambda_permission.allow_api_gateway", shape = "box"]
            "[root] module.lambda.provider.aws" [label = "provider.aws", shape = "diamond"]
            "[root] module.sns.aws_sns_topic.online_tax_qa5_sbr_client_report" [label = "aws_sns_topic.online_tax_qa5_sbr_client_report", shape = "box"]
            "[root] module.sns.provider.aws" [label = "provider.aws", shape = "diamond"]
            "[root] provider.aws (disabled)" [label = "provider.aws (disabled)", shape = "diamond"]
            "[root] module.lambda.aws_api_gateway_deployment.qa5" -> "[root] module.lambda.aws_api_gateway_method.sbr_client_report_method"
            "[root] module.lambda.aws_api_gateway_deployment.qa5" -> "[root] module.lambda.aws_api_gateway_rest_api.online_tax_sbr_client_report_endpoint_api"
            "[root] module.lambda.aws_api_gateway_deployment.qa5" -> "[root] module.lambda.provider.aws"
            "[root] module.lambda.aws_api_gateway_integration.sbr_client_report_resource_integration" -> "[root] module.lambda.aws_api_gateway_method.sbr_client_report_method"
            "[root] module.lambda.aws_api_gateway_integration.sbr_client_report_resource_integration" -> "[root] module.lambda.aws_api_gateway_resource.sbr_client_report_resource"
            "[root] module.lambda.aws_api_gateway_integration.sbr_client_report_resource_integration" -> "[root] module.lambda.aws_api_gateway_rest_api.online_tax_sbr_client_report_endpoint_api"
            "[root] module.lambda.aws_api_gateway_integration.sbr_client_report_resource_integration" -> "[root] module.lambda.aws_lambda_function.onlinetax_sbr_endpoint_lambda"
            "[root] module.lambda.aws_api_gateway_integration.sbr_client_report_resource_integration" -> "[root] module.lambda.provider.aws"
            "[root] module.lambda.aws_api_gateway_integration_response.sbr_client_report_resource_integration_default_response" -> "[root] module.lambda.aws_api_gateway_integration.sbr_client_report_resource_integration"
            "[root] module.lambda.aws_api_gateway_integration_response.sbr_client_report_resource_integration_default_response" -> "[root] module.lambda.aws_api_gateway_method.sbr_client_report_method"
            "[root] module.lambda.aws_api_gateway_integration_response.sbr_client_report_resource_integration_default_response" -> "[root] module.lambda.aws_api_gateway_method_response.200"
            "[root] module.lambda.aws_api_gateway_integration_response.sbr_client_report_resource_integration_default_response" -> "[root] module.lambda.aws_api_gateway_resource.sbr_client_report_resource"
            "[root] module.lambda.aws_api_gateway_integration_response.sbr_client_report_resource_integration_default_response" -> "[root] module.lambda.aws_api_gateway_rest_api.online_tax_sbr_client_report_endpoint_api"
            "[root] module.lambda.aws_api_gateway_integration_response.sbr_client_report_resource_integration_default_response" -> "[root] module.lambda.provider.aws"
            "[root] module.lambda.aws_api_gateway_integration_response.sbr_client_report_resource_integration_error_response" -> "[root] module.lambda.aws_api_gateway_integration.sbr_client_report_resource_integration"
            "[root] module.lambda.aws_api_gateway_integration_response.sbr_client_report_resource_integration_error_response" -> "[root] module.lambda.aws_api_gateway_method.sbr_client_report_method"
            "[root] module.lambda.aws_api_gateway_integration_response.sbr_client_report_resource_integration_error_response" -> "[root] module.lambda.aws_api_gateway_method_response.500"
            "[root] module.lambda.aws_api_gateway_integration_response.sbr_client_report_resource_integration_error_response" -> "[root] module.lambda.aws_api_gateway_resource.sbr_client_report_resource"
            "[root] module.lambda.aws_api_gateway_integration_response.sbr_client_report_resource_integration_error_response" -> "[root] module.lambda.aws_api_gateway_rest_api.online_tax_sbr_client_report_endpoint_api"
            "[root] module.lambda.aws_api_gateway_integration_response.sbr_client_report_resource_integration_error_response" -> "[root] module.lambda.provider.aws"
            "[root] module.lambda.aws_api_gateway_method.sbr_client_report_method" -> "[root] module.lambda.aws_api_gateway_resource.sbr_client_report_resource"
            "[root] module.lambda.aws_api_gateway_method.sbr_client_report_method" -> "[root] module.lambda.aws_api_gateway_rest_api.online_tax_sbr_client_report_endpoint_api"
            "[root] module.lambda.aws_api_gateway_method.sbr_client_report_method" -> "[root] module.lambda.provider.aws"
            "[root] module.lambda.aws_api_gateway_method_response.200" -> "[root] module.lambda.aws_api_gateway_method.sbr_client_report_method"
            "[root] module.lambda.aws_api_gateway_method_response.200" -> "[root] module.lambda.aws_api_gateway_resource.sbr_client_report_resource"
            "[root] module.lambda.aws_api_gateway_method_response.200" -> "[root] module.lambda.aws_api_gateway_rest_api.online_tax_sbr_client_report_endpoint_api"
            "[root] module.lambda.aws_api_gateway_method_response.200" -> "[root] module.lambda.provider.aws"
            "[root] module.lambda.aws_api_gateway_method_response.500" -> "[root] module.lambda.aws_api_gateway_method.sbr_client_report_method"
            "[root] module.lambda.aws_api_gateway_method_response.500" -> "[root] module.lambda.aws_api_gateway_resource.sbr_client_report_resource"
            "[root] module.lambda.aws_api_gateway_method_response.500" -> "[root] module.lambda.aws_api_gateway_rest_api.online_tax_sbr_client_report_endpoint_api"
            "[root] module.lambda.aws_api_gateway_method_response.500" -> "[root] module.lambda.provider.aws"
            "[root] module.lambda.aws_api_gateway_resource.sbr_client_report_resource" -> "[root] module.lambda.aws_api_gateway_rest_api.online_tax_sbr_client_report_endpoint_api"
            "[root] module.lambda.aws_api_gateway_resource.sbr_client_report_resource" -> "[root] module.lambda.provider.aws"
            "[root] module.lambda.aws_api_gateway_rest_api.online_tax_sbr_client_report_endpoint_api" -> "[root] module.lambda.aws_lambda_function.onlinetax_sbr_endpoint_lambda"
            "[root] module.lambda.aws_api_gateway_rest_api.online_tax_sbr_client_report_endpoint_api" -> "[root] module.lambda.provider.aws"
            "[root] module.lambda.aws_iam_role.onlinetax_sbr_endpoint_role" -> "[root] module.lambda.provider.aws"
            "[root] module.lambda.aws_iam_role_policy.publish_to_sns_policy" -> "[root] module.lambda.aws_iam_role.onlinetax_sbr_endpoint_role"
            "[root] module.lambda.aws_iam_role_policy.publish_to_sns_policy" -> "[root] module.lambda.provider.aws"
            "[root] module.lambda.aws_iam_role_policy.publish_to_sns_policy" -> "[root] module.sns.aws_sns_topic.online_tax_qa5_sbr_client_report"
            "[root] module.lambda.aws_iam_role_policy.write_to_cloudwatch_policy" -> "[root] module.lambda.aws_iam_role.onlinetax_sbr_endpoint_role"
            "[root] module.lambda.aws_iam_role_policy.write_to_cloudwatch_policy" -> "[root] module.lambda.provider.aws"
            "[root] module.lambda.aws_lambda_function.onlinetax_sbr_endpoint_lambda" -> "[root] module.lambda.aws_iam_role.onlinetax_sbr_endpoint_role"
            "[root] module.lambda.aws_lambda_function.onlinetax_sbr_endpoint_lambda" -> "[root] module.lambda.provider.aws"
            "[root] module.lambda.aws_lambda_permission.allow_api_gateway" -> "[root] module.lambda.aws_api_gateway_integration.sbr_client_report_resource_integration"
            "[root] module.lambda.aws_lambda_permission.allow_api_gateway" -> "[root] module.lambda.aws_api_gateway_resource.sbr_client_report_resource"
            "[root] module.lambda.aws_lambda_permission.allow_api_gateway" -> "[root] module.lambda.aws_api_gateway_rest_api.online_tax_sbr_client_report_endpoint_api"
            "[root] module.lambda.aws_lambda_permission.allow_api_gateway" -> "[root] module.lambda.aws_lambda_function.onlinetax_sbr_endpoint_lambda"
            "[root] module.lambda.aws_lambda_permission.allow_api_gateway" -> "[root] module.lambda.provider.aws"
            "[root] module.lambda.provider.aws" -> "[root] provider.aws (disabled)"
            "[root] module.sns.aws_sns_topic.online_tax_qa5_sbr_client_report" -> "[root] module.sns.provider.aws"
            "[root] module.sns.provider.aws" -> "[root] provider.aws (disabled)"
        }
}

The Graph has other resources which I have not provided in the tf file above. Its only the API GW that has issues. By the way, I am able to test the API from the console and it works fine. I am not able to execute it from my localbox or postman.

Any idea on what I am doing wrong?

TF does not deploy the API, this link might help you: https://medium.com/coryodaniel/til-forcing-terraform-to-deploy-a-aws-api-gateway-deployment-ed36a9f60c1a

I've fixed mine by adding the variable deployed_at:

resource "aws_api_gateway_deployment" "api_ingest_deployment" {
  depends_on = ["aws_api_gateway_method.xxx",
                "aws_api_gateway_integration.yyy",
                "aws_api_gateway_integration.zzz",
                "aws_api_gateway_integration.www",
  ]
  rest_api_id = "${aws_api_gateway_rest_api.foo.id}"
  stage_name = "${var.environment}"

  variables {
    deployed_at = "${timestamp()}"
  }
}

the downside is that if done this way it will always deploy, even if there's no change

AWS: aws_api_gateway_deployment, Provides an API Gateway REST Deployment. If the stage does not exist, a new one will be created and point to this deployment. description - (Optional) The� aws_api_gateway_deployment creates a stage, but i faced a issue saying stage does not exist when i don't have depends_on statement. Its working with the following code. Its working with the following code.

Generally the code change is at lambda level. So you may interpolate lambda code version as a variable and add it in same module where you have api deployment. This way it will deploy only when lambda code changes.

AWS: aws_api_gateway_stage, This is by design so that you can have a shared definition of your API across stages, but then do environment/stage specific deployments. deployment_id - (Required) The ID of the deployment that the stage points to access_log_settings - (Optional) Enables access logs for the API stage. Detailed below.

If you are using swagger template and terraform ver >= 0.12 then you can give swagger file for MD5 computation like below. This work perfectly.

resource "aws_api_gateway_deployment" "deploy_stage" {
  rest_api_id = aws_api_gateway_rest_api.product_api.id
  stage_name  = var.stage_name
  stage_description = md5(file("swagger_api.yml"))
}

Forcing Terraform to deploy a aws_api_gateway_deployment, Since that doesn't happen, the stage specified in the deployment But without something, managing API Gateway using Terraform is always� aws_api_gateway_deployment doesn't get updated after a dependent resource changes. For example, if I change a aws_api_gateway_integration resource to modify the request_template property, aws_api_gateway_deployment should be triggered.

None of the other solutions here worked for me as I get this error:

BadRequestException: Active stages pointing to this deployment must be moved or deleted

This is the solution that worked for me:

resource "aws_api_gateway_deployment" "api_deployment" {
  rest_api_id       = aws_api_gateway_rest_api.api.id
  stage_name        = "default"
  stage_description = "Deployed at ${timestamp()}"

  lifecycle {
    create_before_destroy = true
  }
}

Tested on Terraform 0.12.24

Issue #6613 � hashicorp/terraform, some issues at the time we deploy our API Gateway into AWS. on deployments, terraform is deleting the old API stage without creating the� First, use the test button in API Gateway to confirm if you can call your Lambda function from within it. In the Request Body enter the following: Click Test; On the right hand side, we will. Alex Shing, Although it's possible to provision Lambdas and the API Gateway through Terraform, it does not manage the deployment.

There are a couple of things which you need to be careful about.

  1. Mention the depends on properly to make sure the deployment block is executed after the integration and method block is executed(especially when you have any authorizers in place).
  2. Add the timestamp function in variables to deploy it immediately once all the dependent blocks are executed.

      resource "aws_api_gateway_deployment" "mydeployment" {
      depends_on =["aws_api_gateway_method.mymethod","aws_api_gateway_integration.myintegration"]
      rest_api_id = "${aws_api_gateway_rest_api.myapi.id}"
      stage_name = "dev"
      variables = {
         deployed_at = "${timestamp()}"
      }
    }
    

Issue #13 � terraform-providers/terraform-provider-aws, Learn to deploy serverless web applications with Terraform provisioning AWS with Lambda and API Gateway but does not assume any pre-existing deployment . domain name then becomes an alias for a particular deployment stage. For future deployments, after you deploy using CodePipeline, it will only deploy to the stage specified on your yaml file. It will not affect the stage you manually deployed on AWS API Gateway console. 4.1 AWS API Gateway Console. Thus, to deploy to your manually deployed stage, you have to go to API Gateway and repeat step 2. 4.2 AWS API

Serverless Applications with AWS Lambda and API Gateway , Update: Found the bug for this: I'm not all that familiar with API Gateway, so I Is there a way I can get Terraform to redeploy the api stage if the policy On IP ranges update hash will differ and trigger recreation of api gateway deployment. This stage-level rate limit must not be more than the account-level rate limit as specified in API Gateway quotas for configuring and running a REST API. For Burst , enter the maximum number of stage-level concurrent requests that API Gateway can serve without returning a 429 Too Many Requests response.

[AWS] Trigger aws_api_gateway_deployment on , Learn how to work with stage variables in Amazon API Gateway. This is a slightly-opinionated guide, which chooses to ignore the built-in versioning and staged deployment mechanisms in AWS Lambda and API Gateway. In many cases these features are not necessary when using Terraform because changes can be tracked and deployed by keeping the Terraform configuration in a version-control repository.

Setting up stage variables for a REST API deployment, It's hard to think of an HTTP server without access and error logs. When you deploy your first API Gateway on AWS and try to properly set it up� Amazon API Gateway Version 1 resources are used for creating and deploying REST APIs. To create and deploy WebSocket and HTTP APIs, use Amazon API Gateway Version 2 resources.

Comments
  • Is this the case for the first deployment or just future deployments when things change? There's an open issue on GH for the latter: github.com/hashicorp/terraform/issues/6613
  • Even the first deployment didn't work I guess. I destroyed the entire stack and applied it again. Still don't see the deployment. When terraform plan lists all the changes that need to be applied, the deployment resource is listed at the very top. Does that mean that gets deployed first?
  • It absolutely won't be run first because it is dependent on at least 2 resources (aws_api_gateway_rest_api and aws_api_gateway_method) which in turn may well be dependent on other things. I'd have to run your TF to see but that will have to wait until tonight unfortunately. It might be interesting to see the output of terraform graph if you could edit that into your question?
  • Actually, I just checked also this GitHub issue github.com/hashicorp/terraform/issues/6613 Doing it this way: resource "aws_api_gateway_deployment" "default" { ... stage_description = "${md5(file("api_gateway.tf"))}" ... } is more clever and will force you to deploy less
  • I wasted hours on this problem. Thank you for letting me know!
  • Antonio's answer helped me, the solution on this post seems 'better' (workaround, but works). Should be an accepted answer?
  • Thank you, your solution worked for me too on TF 0.12.24