terraform-provider-aws: aws_api_gateway_deployment doesn't get updated after changes

This issue was originally opened by @blalor as hashicorp/terraform#6613. It was migrated here as part of the provider split. The original body of the issue is below.


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. Since that doesn’t happen, the stage specified in the deployment continues to use the old configuration. depends_on doesn’t seem to be sufficient; I tried capturing that dependency and it didn’t work, and as I understand it, depends_on only captures ordering.

A workaround is to taint the aws_api_gateway_deployment resource after a successful apply and re-running apply.

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 122
  • Comments: 18 (1 by maintainers)

Commits related to this issue

Most upvoted comments

Sharing our workaround for this issue. Initially we tried hashing the whole API definition file but then we ran into the issue that changes to variable values did not trigger a new deployment. For example, we had a lambda integration where the function name changed. The aws_api_gateway_integration resource got updated correctly with the new invocation ARN but a new aws_api_gateway_deployment was not created since the API tf file had not changed. The same would go for any parametrised value that the API uses.

Currently we follow the pattern below for our APIs. Here we build a hash from the full JSON representations of all the resources that would affect the deployment, which means resource, methods, integrations, the various response types and the models. Maybe there are more types that need to go in here, but these are the ones we have found necessary.

We need to keep this list updated when we add resources and that opens up for mistakes, but this is the approach that gives us new deployments at the right time without creating them unnecessarily.

resource "aws_api_gateway_deployment" "demo" {
  rest_api_id = aws_api_gateway_rest_api.demo.id

  variables = {
    // For new changes to the API to be correctly deployed, they need to
    // be detected by terraform as a trigger to recreate the aws_api_gateway_deployment.
    // This is because AWS keeps a "working copy" of the API resources which does not
    // go live until a new aws_api_gateway_deployment is created.
    // Here we use a dummy stage variable to force a new aws_api_gateway_deployment.
    // We want it to detect if any of the API-defining resources have changed so we
    // hash all of their configurations.
    // IMPORTANT: This list must include all API resources that define the "content" of
    // the rest API. That means anything except for aws_api_gateway_rest_api,
    // aws_api_gateway_stage, aws_api_gateway_base_path_mapping, that are higher-level
    // resources. Any change to a part of the API not included in this list might not
    // trigger creation of a new aws_api_gateway_deployment and thus not fully deployed.
    trigger_hash = sha1(join(",", [
      jsonencode(aws_api_gateway_resource.demo),
      jsonencode(aws_api_gateway_method.demo_get),
      jsonencode(aws_api_gateway_integration.demo_get),
      jsonencode(aws_api_gateway_integration_response.demo_get_200),
      jsonencode(aws_api_gateway_integration_response.demo_get_400),
      jsonencode(aws_api_gateway_integration_response.demo_get_500),
      jsonencode(aws_api_gateway_method_response.demo_get_200),
      jsonencode(aws_api_gateway_method_response.demo_get_400),
      jsonencode(aws_api_gateway_method_response.demo_get_500),
      jsonencode(aws_api_gateway_model.demo_request_body),
      jsonencode(aws_api_gateway_model.demo_api_response),
      jsonencode(aws_api_gateway_model.demo_error_response),
      //
      // Etc. ...
      //
    ]))
  }

  lifecycle {
    create_before_destroy = true
  }
}

+1 😃

A workaround we use:

  • Use a swagger template to create the API body
  • Use a json template to create the API policy
  • concatenate the rendered values of the two templates and run the builtin base64sha256() function on the resultant string to create an “API hash”
  • set that hash as the value of a aws_api_gateway_deployment variables property

The effect is that when the API changes, the deployment is replaced and the stage updated. When the API doesn’t change, the deployment doesn’t change (a disadvantage of using timestamp() for the deployment variable value)

One more “astuce”: use

lifecycle {
    create_before_destroy = true
}

in the aws_api_gateway_deployment resource to avoid “Active stages” errors.

Sharing this here as well since the original was closed:

Using stage_description seems like a good work-around to solve this issue in the short term.

resource "aws_api_gateway_deployment" "example" {
  rest_api_id = "${aws_api_gateway_rest_api.example.id}"
  stage_name  = "test"

  # Force re-deployments if any dependencies change
  # https://github.com/hashicorp/terraform/issues/6613
  # https://github.com/terraform-providers/terraform-provider-aws/issues/162
  stage_description = <<DESCRIPTION
${aws_api_gateway_resource.example.id}
${aws_api_gateway_method.example.id}
${aws_api_gateway_integration.example.id}
DESCRIPTION

  depends_on = [
    "aws_api_gateway_integration.example",
  ]
}

Hi folks 👋

Since it does not appear there will be functionality added anytime soon in Terraform core to support a form of resource configuration that will automatically triggers resource recreation when referenced resources are updated, the aws_api_gateway_deployment resource has been enhanced with a triggers map argument similar to those utilized by the null, random, and time providers. This can be used by operators to automatically force a new resource (redeployment) using key/value criteria of their choosing. Its usage is fairly advanced, so caveats are added to the documentation. This functionality will release with version 2.61.0 of the Terraform AWS Provider, later next week.

If this type of enhancement does not fit your needs, we would encourage you to file a new issue (potentially upstream in Terraform core since there’s not much else we can do at the provider level). Please also note that we do not intend to add this class of argument to all Terraform AWS Provider resources due to its complexity and potentially awkward configuration.

Hitting this right now as well, took me a long time to realise I had to deploy the API in the console to see all my changes 😉

@bassmanitram’s solution works just fine when using an OpenAPI Spec file.

However, I couldn’t use base64sha256 as it outputs characters that are invalid for the stage’s variable values. I used this sha1(file("./api/spec.yaml")) instead, a shorter value and only hex chars

A seemingly decent suggestion from the comments on the original ticket was to add a ‘triggers’ map on the deployment resource: https://github.com/hashicorp/terraform/issues/6613#issuecomment-252275369 - this seems like maybe the least painful quick fix to the issue.