hashicorp / terraform-provider-awscc

Terraform AWS Cloud Control provider
https://registry.terraform.io/providers/hashicorp/awscc/latest/docs
Mozilla Public License 2.0
255 stars 117 forks source link

awscc_healthlake_fhir_datastore - Modifications to tags force recreation #1355

Open malcolmm83 opened 10 months ago

malcolmm83 commented 10 months ago

Community Note

Terraform CLI and Terraform AWS Cloud Control Provider Version

Terraform Version : 1.5.5 Installed hashicorp/awscc v0.66.0 (signed by HashiCorp)

Affected Resource(s)

Terraform Configuration Files

Please include all Terraform configurations required to reproduce the bug. Bug reports without a functional reproduction may be closed without investigation.

resource "awscc_healthlake_fhir_datastore" "this" {
  count                  = length(var.healthlake_datastores)
  datastore_name         = var.healthlake_datastores[count.index]
  datastore_type_version = "R4"
  sse_configuration = {
    kms_encryption_config = {
      cmk_type   = "CUSTOMER_MANAGED_KMS_KEY"
      kms_key_id = aws_kms_key.cmk_healthlake.key_id
    }
  }
  tags = concat([{ key = "AssetName", value = var.healthlake_datastores[count.index] },
  { key = "Purpose", value = "HealthLake" }], var.tags)
  lifecycle {
    prevent_destroy = true
  }
}

Debug Output

Panic Output

Expected Behavior

Changes in tags should update the datastore not destroy/recreate. AWS resource suppports tag and untag operations.

Actual Behavior

Changes to tags trigger a destroy and recreate. Setting the prevent_destroy lifecycle to true causes plan to fail.

Steps to Reproduce

  1. terraform apply

Important Factoids

References

bruceharrison1984 commented 4 months ago

I just verified the behavior on the AWS side, and adding/removing tags on a HealthLake does not require recreation of the HealthLake itself.

The following simple template can be used to verify adding/removing tags by performing a stack update.

{
  "AWSTemplateFormatVersion": "2010-09-09",

  "Resources": {
    "HealthLakeKey": {
      "Type": "AWS::KMS::Key",
      "Properties": {
        "Description": "An example symmetric encryption KMS key",
        "EnableKeyRotation": true,
        "PendingWindowInDays": 20
      }
    },
    "Healthlake": {
      "Type": "AWS::HealthLake::FHIRDatastore",
      "Properties": {
        "DatastoreName": "my-store-123456",
        "DatastoreTypeVersion": "R4",
        "SseConfiguration": {
          "KmsEncryptionConfig": {
            "CmkType": "CUSTOMER_MANAGED_KMS_KEY",
            "KmsKeyId": {
              "Ref": "HealthLakeKey"
            }
          }
        },
        "Tags": [
          {
            "Key": "tag1",
            "Value": "value1"
          }
        ]
      }
    }
  }
}
ewbankkit commented 3 months ago

With this configuration (equivalent to the one above)

provider "aws" {}
provider "awscc" {}

resource "aws_kms_key" "test" {
  description             = "ewbankkit-test"
  deletion_window_in_days = 7
}

resource "awscc_healthlake_fhir_datastore" "test" {
  datastore_name         = "ewbankkit-test"
  datastore_type_version = "R4"
  sse_configuration = {
    kms_encryption_config = {
      cmk_type   = "CUSTOMER_MANAGED_KMS_KEY"
      kms_key_id = aws_kms_key.test.key_id
    }
  }
  tags = [
    {
      key   = "Name"
      value = "ewbankkit-test"
    }
  ]
}

I see

% terraform plan

aws_kms_key.test: Refreshing state... [id=0bc14a40-8606-4562-bd30-a24f0f3de6ed]
awscc_healthlake_fhir_datastore.test: Refreshing state... [id=f4e299a53f00f2fd719f9963e8be0bd5]

Note: Objects have changed outside of Terraform

Terraform detected the following changes made outside of Terraform since the last "terraform apply":

  # aws_kms_key.test has been changed
  ~ resource "aws_kms_key" "test" {
        id                                 = "0bc14a40-8606-4562-bd30-a24f0f3de6ed"
      + tags                               = {}
        # (13 unchanged attributes hidden)
    }
  # awscc_healthlake_fhir_datastore.test has been changed
  ~ resource "awscc_healthlake_fhir_datastore" "test" {
        id                              = "f4e299a53f00f2fd719f9963e8be0bd5"
      ~ sse_configuration               = {
        ~ kms_encryption_config = {
          ~ kms_key_id = "0bc14a40-8606-4562-bd30-a24f0f3de6ed" -> "arn:aws:kms:us-west-2:123456789012:key/0bc14a40-8606-4562-bd30-a24f0f3de6ed"
            # (1 unchanged attribute hidden)
        }
      }
        tags                            = [
            {          },
          # (1 unchanged element hidden)
        ]
        # (8 unchanged attributes hidden)
    }

Unless you have made equivalent changes to your configuration, or ignored the relevant attributes using ignore_changes, the following plan
may include actions to undo or respond to these changes.

───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
-/+ destroy and then create replacement

Terraform will perform the following actions:

  # awscc_healthlake_fhir_datastore.test must be replaced
-/+ resource "awscc_healthlake_fhir_datastore" "test" {
      ~ created_at                      = {
        ~ nanos   = 441000000 -> (known after apply)
        ~ seconds = "1720462542" -> (known after apply)
      }
      ~ datastore_arn                   = "arn:aws:healthlake:us-west-2:123456789012:datastore/fhir/f4e299a53f00f2fd719f9963e8be0bd5" -> (known after apply)
      ~ datastore_endpoint              = "https://healthlake.us-west-2.amazonaws.com/datastore/f4e299a53f00f2fd719f9963e8be0bd5/r4/" -> (known after apply)
      ~ datastore_id                    = "f4e299a53f00f2fd719f9963e8be0bd5" -> (known after apply)
      ~ datastore_status                = "ACTIVE" -> (known after apply)
      ~ id                              = "f4e299a53f00f2fd719f9963e8be0bd5" -> (known after apply)
      ~ identity_provider_configuration = {
        ~ authorization_strategy             = "AWS_AUTH" -> (known after apply)
        ~ fine_grained_authorization_enabled = false -> (known after apply)
        + idp_lambda_arn                     = (known after apply)
        + metadata                           = (known after apply)
      }
      + preload_data_config             = {
        + preload_data_type = (known after apply)
      }
      ~ sse_configuration               = { # forces replacement
        ~ kms_encryption_config = { # forces replacement
          ~ kms_key_id = "arn:aws:kms:us-west-2:123456789012:key/0bc14a40-8606-4562-bd30-a24f0f3de6ed" -> "0bc14a40-8606-4562-bd30-a24f0f3de6ed"
            # (1 unchanged attribute hidden)
        }
      }
        tags                            = [
            {          },
          # (1 unchanged element hidden)
        ]
        # (2 unchanged attributes hidden)
    }

Plan: 1 to add, 0 to change, 1 to destroy.

───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if you run "terraform
apply" now.

because the API is returning the KMS key ARN when the KMS key ID was configured. If we change the configuration to use the key ARN

provider "aws" {}
provider "awscc" {}

resource "aws_kms_key" "test" {
  description             = "ewbankkit-test"
  deletion_window_in_days = 7
}

resource "awscc_healthlake_fhir_datastore" "test" {
  datastore_name         = "ewbankkit-test"
  datastore_type_version = "R4"
  sse_configuration = {
    kms_encryption_config = {
      cmk_type   = "CUSTOMER_MANAGED_KMS_KEY"
      kms_key_id = aws_kms_key.test.arn
    }
  }
  tags = [
    {
      key   = "Name"
      value = "ewbankkit-test"
    }
  ]
}

then no change is shown on plan:

% terraform plan 

aws_kms_key.test: Refreshing state... [id=7be70260-9b00-44b2-8746-5373b422982b]
awscc_healthlake_fhir_datastore.test: Refreshing state... [id=6e51bb447e3ec70a6480b667ab38c870]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  ~ update in-place

Terraform will perform the following actions:

  # awscc_healthlake_fhir_datastore.test will be updated in-place
  ~ resource "awscc_healthlake_fhir_datastore" "test" {
        id                              = "6e51bb447e3ec70a6480b667ab38c870"
      + preload_data_config             = (known after apply)
        tags                            = [
            {
                key   = "Name"
                value = "ewbankkit-test"
            },
        ]
        # (9 unchanged attributes hidden)
    }

Plan: 0 to add, 1 to change, 0 to destroy.

───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if you run "terraform
apply" now.

Adding a tag now shows an in-place update:

  # awscc_healthlake_fhir_datastore.test will be updated in-place
  ~ resource "awscc_healthlake_fhir_datastore" "test" {
        id                              = "6e51bb447e3ec70a6480b667ab38c870"
      + preload_data_config             = (known after apply)
      ~ tags                            = [
            {
                key   = "Name"
                value = "ewbankkit-test"
            },
          + {
              + key   = "Purpose"
              + value = "testing"
            },
        ]
        # (9 unchanged attributes hidden)
    }
quixoticmonk commented 3 months ago

Added the reference example specifying arn than key_id in https://github.com/hashicorp/terraform-provider-awscc/pull/1867