Terraform not deploying api gateway stage

2020-06-16 02:46发布

问题:

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?

回答1:

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



回答2:

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.



回答3:

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"))
}


回答4:

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



回答5:

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()}"
      }
    }