Terraform: Resource saved to state after `ValidateResourceTypeConfig` fails

Created on 30 Jan 2020  ยท  6Comments  ยท  Source: hashicorp/terraform

Terraform Version

Terraform v0.12.20
+ provider.aws v2.46.0
+ provider.local v1.4.0
+ provider.null v2.1.2
+ provider.random v2.2.1

Affected Resource(s)

  • random_password
  • aws_elasticache_replication_group

Terraform Configuration Files

resource "random_password" "cache-auth-token" {
  length = 64
  # Error: only alphanumeric characters or symbols (excluding @, ", and /) allowed in "auth_token"
  #override_special = "!#$%&*()-_=+[]{}<>:?"
}

module "cache" {
  source  = "cloudposse/elasticache-redis/aws"
  version = "0.14.0"

  # insert the 3 required variables here
  name = "nep"
  namespace = data.terraform_remote_state.main.outputs.namespace
  vpc_id = data.terraform_remote_state.main.outputs.vpc_id
  subnets = data.terraform_remote_state.main.outputs.subnet-ids["data"]

  auth_token = random_password.cache-auth-token.result
...
}

Debug Output

I'm including an excerpt of the debug logs which I believe indicates the issue.

137 2020/01/30 13:19:06 [DEBUG] ReferenceTransformer: "module.cache.aws_elasticache_replication_group.default" references: [module.cache.var.enabled module.cache.var.availability_zones module.cache.var.cluster_size module.cache.var.port module.cache.aws_elasticache_parameter_group.default module.cache.var.maintenance_window module.cache.module.label.output.tags module.cache.var.at_rest_encryption_enabled module.cache.var.cluster_size module.cache.local.elasticache_subnet_group_name module.cache.var.notification_topic_arn module.cache.var.replication_group_id module.cache.module.label.output.id module.cache.var.replication_group_id module.cache.var.transit_encryption_enabled module.cache.var.auth_token module.cache.var.automatic_failover_enabled module.cache.var.snapshot_retention_limit module.cache.var.snapshot_window module.cache.var.engine_version module.cache.var.instance_type module.cache.var.use_existing_security_groups module.cache.var.existing_security_groups module.cache.aws_security_group.default module.cache.var.transit_encryption_enabled module.cache.module.label.output.id module.cache.var.cluster_mode_enabled module.cache.var.cluster_mode_replicas_per_node_group module.cache.var.cluster_mode_num_node_groups]
...
2020/01/30 13:19:14 [DEBUG] Resource instance state not found for node "module.cache.aws_elasticache_replication_group.default[0]", instance module.cache.aws_elasticache_replication_group.default[0]
2020/01/30 13:19:14 [DEBUG] ReferenceTransformer: "module.cache.aws_elasticache_replication_group.default[0]" references: []
2020/01/30 13:19:14 [ERROR] module.cache: eval: *terraform.EvalDiff, err: only alphanumeric characters or symbols (excluding @, ", and /) allowed in "auth_token"
2020/01/30 13:19:14 [ERROR] module.cache: eval: *terraform.EvalSequence, err: only alphanumeric characters or symbols (excluding @, ", and /) allowed in "auth_token"

Panic Output

n/a

Expected Behavior

$ terraform apply
random_password.cache-auth-token: Refreshing state... [id=none]
data.terraform_remote_state.main: Refreshing state...
module.cache.aws_elasticache_parameter_group.default[0]: Refreshing state... [id=stg-nep]
data.aws_availability_zones.this: Refreshing state...
module.cache.aws_elasticache_subnet_group.default[0]: Refreshing state... [id=stg-nep]
module.cache.aws_security_group.default[0]: Refreshing state... [id=sg-007b5478f6f48fe8a]
module.cache.aws_security_group_rule.egress[0]: Refreshing state... [id=sgrule-124035523]
module.cache.aws_cloudwatch_metric_alarm.cache_cpu[0]: Refreshing state... [id=stg-nep-cpu-utilization]
module.cache.aws_cloudwatch_metric_alarm.cache_memory[0]: Refreshing state... [id=stg-nep-freeable-memory]

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create
-/+ destroy and then create replacement

Terraform will perform the following actions:

  # random_password.cache-auth-token must be replaced
-/+ resource "random_password" "cache-auth-token" {
      ~ id               = "none" -> (known after apply)
        length           = 64
        lower            = true
        min_lower        = 0
        min_numeric      = 0
        min_special      = 0
        min_upper        = 0
        number           = true
      + override_special = "!#$%&*()-_=+[]{}<>:?" # forces replacement
      ~ result           = (sensitive value)
        special          = true
        upper            = true
    }

  # module.cache.aws_elasticache_replication_group.default[0] must be replaced
-/+ resource "aws_elasticache_replication_group" "default" {
      + apply_immediately              = (known after apply)
        at_rest_encryption_enabled     = true
      + auth_token                     = (sensitive value)
        auto_minor_version_upgrade     = true
        automatic_failover_enabled     = false
        availability_zones             = [
            "us-east-2a",
            "us-east-2b",
        ]
      + configuration_endpoint_address = (known after apply)
        engine                         = "redis"
        engine_version                 = "5.0.6"
      ~ id                             = "stg-nep" -> (known after apply)
        maintenance_window             = "wed:03:00-wed:04:00"
      ~ member_clusters                = [
          - "stg-nep-001",
          - "stg-nep-002",
        ] -> (known after apply)
        node_type                      = "cache.t3.micro"
        number_cache_clusters          = 2
        parameter_group_name           = "stg-nep"
        port                           = 6379
      ~ primary_endpoint_address       = "master.stg-nep.qnprfz.use2.cache.amazonaws.com" -> (known after apply)
        replication_group_description  = "stg-nep"
        replication_group_id           = "stg-nep"
        security_group_ids             = [
            "sg-007b5478f6f48fe8a",
        ]
      ~ security_group_names           = [] -> (known after apply)
        snapshot_retention_limit       = 7
        snapshot_window                = "06:30-07:30"
        subnet_group_name              = "stg-nep"
        tags                           = {
            "Name"      = "stg-nep"
            "Namespace" = "stg"
        }
        transit_encryption_enabled     = true

      + cluster_mode {
          + num_node_groups         = (known after apply)
          + replicas_per_node_group = (known after apply)
        }
    }

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

Do you want to perform these actions in workspace "stg"?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

Actual Behavior

First attempt at adding a randomly generated password:

$ terraform apply
data.terraform_remote_state.main: Refreshing state...
data.aws_availability_zones.this: Refreshing state...
module.cache.aws_elasticache_parameter_group.default[0]: Refreshing state... [id=stg-nep]
module.cache.aws_elasticache_subnet_group.default[0]: Refreshing state... [id=stg-nep]
module.cache.aws_security_group.default[0]: Refreshing state... [id=sg-007b5478f6f48fe8a]
module.cache.aws_security_group_rule.egress[0]: Refreshing state... [id=sgrule-124035523]
module.cache.aws_elasticache_replication_group.default[0]: Refreshing state... [id=stg-nep]
module.cache.aws_cloudwatch_metric_alarm.cache_memory[0]: Refreshing state... [id=stg-nep-freeable-memory]
module.cache.aws_cloudwatch_metric_alarm.cache_cpu[0]: Refreshing state... [id=stg-nep-cpu-utilization]

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create
-/+ destroy and then create replacement

Terraform will perform the following actions:

  # random_password.cache-auth-token will be created
  + resource "random_password" "cache-auth-token" {
      + id          = (known after apply)
      + length      = 64
      + lower       = true
      + min_lower   = 0
      + min_numeric = 0
      + min_special = 0
      + min_upper   = 0
      + number      = true
      + result      = (sensitive value)
      + special     = true
      + upper       = true
    }

  # module.cache.aws_elasticache_replication_group.default[0] must be replaced
-/+ resource "aws_elasticache_replication_group" "default" {
      + apply_immediately              = (known after apply)
        at_rest_encryption_enabled     = true
      + auth_token                     = (sensitive value)
        auto_minor_version_upgrade     = true
        automatic_failover_enabled     = false
        availability_zones             = [
            "us-east-2a",
            "us-east-2b",
        ]
      + configuration_endpoint_address = (known after apply)
        engine                         = "redis"
        engine_version                 = "5.0.6"
      ~ id                             = "stg-nep" -> (known after apply)
        maintenance_window             = "wed:03:00-wed:04:00"
      ~ member_clusters                = [
          - "stg-nep-001",
          - "stg-nep-002",
        ] -> (known after apply)
        node_type                      = "cache.t3.micro"
        number_cache_clusters          = 2
        parameter_group_name           = "stg-nep"
        port                           = 6379
      ~ primary_endpoint_address       = "master.stg-nep.qnprfz.use2.cache.amazonaws.com" -> (known after apply)
        replication_group_description  = "stg-nep"
        replication_group_id           = "stg-nep"
        security_group_ids             = [
            "sg-007b5478f6f48fe8a",
        ]
      ~ security_group_names           = [] -> (known after apply)
        snapshot_retention_limit       = 7
        snapshot_window                = "06:30-07:30"
        subnet_group_name              = "stg-nep"
        tags                           = {
            "Name"      = "stg-nep"
            "Namespace" = "stg"
        }
        transit_encryption_enabled     = true

      + cluster_mode {
          + num_node_groups         = (known after apply)
          + replicas_per_node_group = (known after apply)
        }
    }

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

Do you want to perform these actions in workspace "stg"?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

random_password.cache-auth-token: Creating...
random_password.cache-auth-token: Creation complete after 0s [id=none]
module.cache.aws_elasticache_replication_group.default[0]: Destroying... [id=stg-nep]
module.cache.aws_elasticache_replication_group.default[0]: Still destroying... [id=stg-nep, 10s elapsed]
module.cache.aws_elasticache_replication_group.default[0]: Still destroying... [id=stg-nep, 20s elapsed]
module.cache.aws_elasticache_replication_group.default[0]: Still destroying... [id=stg-nep, 30s elapsed]
module.cache.aws_elasticache_replication_group.default[0]: Still destroying... [id=stg-nep, 40s elapsed]
module.cache.aws_elasticache_replication_group.default[0]: Still destroying... [id=stg-nep, 50s elapsed]
module.cache.aws_elasticache_replication_group.default[0]: Still destroying... [id=stg-nep, 1m0s elapsed]
module.cache.aws_elasticache_replication_group.default[0]: Still destroying... [id=stg-nep, 1m10s elapsed]
module.cache.aws_elasticache_replication_group.default[0]: Still destroying... [id=stg-nep, 1m20s elapsed]
module.cache.aws_elasticache_replication_group.default[0]: Still destroying... [id=stg-nep, 1m30s elapsed]
module.cache.aws_elasticache_replication_group.default[0]: Still destroying... [id=stg-nep, 1m40s elapsed]
module.cache.aws_elasticache_replication_group.default[0]: Still destroying... [id=stg-nep, 1m50s elapsed]
module.cache.aws_elasticache_replication_group.default[0]: Still destroying... [id=stg-nep, 2m0s elapsed]
module.cache.aws_elasticache_replication_group.default[0]: Still destroying... [id=stg-nep, 2m10s elapsed]
module.cache.aws_elasticache_replication_group.default[0]: Still destroying... [id=stg-nep, 2m20s elapsed]
module.cache.aws_elasticache_replication_group.default[0]: Still destroying... [id=stg-nep, 2m30s elapsed]
module.cache.aws_elasticache_replication_group.default[0]: Still destroying... [id=stg-nep, 2m40s elapsed]
module.cache.aws_elasticache_replication_group.default[0]: Still destroying... [id=stg-nep, 2m50s elapsed]
module.cache.aws_elasticache_replication_group.default[0]: Still destroying... [id=stg-nep, 3m0s elapsed]
module.cache.aws_elasticache_replication_group.default[0]: Still destroying... [id=stg-nep, 3m10s elapsed]
module.cache.aws_elasticache_replication_group.default[0]: Still destroying... [id=stg-nep, 3m20s elapsed]
module.cache.aws_elasticache_replication_group.default[0]: Still destroying... [id=stg-nep, 3m30s elapsed]
module.cache.aws_elasticache_replication_group.default[0]: Still destroying... [id=stg-nep, 3m40s elapsed]
module.cache.aws_elasticache_replication_group.default[0]: Still destroying... [id=stg-nep, 3m50s elapsed]
module.cache.aws_elasticache_replication_group.default[0]: Still destroying... [id=stg-nep, 4m0s elapsed]
module.cache.aws_elasticache_replication_group.default[0]: Still destroying... [id=stg-nep, 4m10s elapsed]
module.cache.aws_elasticache_replication_group.default[0]: Still destroying... [id=stg-nep, 4m20s elapsed]
module.cache.aws_elasticache_replication_group.default[0]: Still destroying... [id=stg-nep, 4m30s elapsed]
module.cache.aws_elasticache_replication_group.default[0]: Still destroying... [id=stg-nep, 4m40s elapsed]
module.cache.aws_elasticache_replication_group.default[0]: Still destroying... [id=stg-nep, 4m50s elapsed]
module.cache.aws_elasticache_replication_group.default[0]: Still destroying... [id=stg-nep, 5m0s elapsed]
module.cache.aws_elasticache_replication_group.default[0]: Still destroying... [id=stg-nep, 5m10s elapsed]
module.cache.aws_elasticache_replication_group.default[0]: Still destroying... [id=stg-nep, 5m20s elapsed]
module.cache.aws_elasticache_replication_group.default[0]: Still destroying... [id=stg-nep, 5m30s elapsed]
module.cache.aws_elasticache_replication_group.default[0]: Still destroying... [id=stg-nep, 5m40s elapsed]
module.cache.aws_elasticache_replication_group.default[0]: Still destroying... [id=stg-nep, 5m50s elapsed]
module.cache.aws_elasticache_replication_group.default[0]: Still destroying... [id=stg-nep, 6m0s elapsed]
module.cache.aws_elasticache_replication_group.default[0]: Still destroying... [id=stg-nep, 6m10s elapsed]
module.cache.aws_elasticache_replication_group.default[0]: Still destroying... [id=stg-nep, 6m20s elapsed]
module.cache.aws_elasticache_replication_group.default[0]: Destruction complete after 6m23s

Error: only alphanumeric characters or symbols (excluding @, ", and /) allowed in "auth_token"

  on .terraform/modules/cache/cloudposse-terraform-aws-elasticache-redis-d27d632/main.tf line 79, in resource "aws_elasticache_replication_group" "default":
  79: resource "aws_elasticache_replication_group" "default" {

$ terraform apply
Acquiring state lock. This may take a few moments...
random_password.cache-auth-token: Refreshing state... [id=none]
data.terraform_remote_state.main: Refreshing state...
data.aws_availability_zones.this: Refreshing state...
module.cache.aws_elasticache_parameter_group.default[0]: Refreshing state... [id=stg-nep]
module.cache.aws_elasticache_subnet_group.default[0]: Refreshing state... [id=stg-nep]
module.cache.aws_security_group.default[0]: Refreshing state... [id=sg-007b5478f6f48fe8a]
module.cache.aws_security_group_rule.egress[0]: Refreshing state... [id=sgrule-124035523]

Error: only alphanumeric characters or symbols (excluding @, ", and /) allowed in "auth_token"

  on .terraform/modules/cache/cloudposse-terraform-aws-elasticache-redis-d27d632/main.tf line 79, in resource "aws_elasticache_replication_group" "default":
  79: resource "aws_elasticache_replication_group" "default" {

Steps to Reproduce

Please list the steps required to reproduce the issue, for example:

  1. terraform apply (without setting an auth_token value)
  2. add random_password resource, point auth_token to it
  3. terraform apply (generates new password, destorys old cache instance, errors out trying to create new one)
  4. fix by adding override_special and excluding @.
  5. terraform_apply (fails to refresh, still sees old values)
  6. change auth_token to be constant string
  7. terraform apply (plans cleanly)

Important Factoids

Though I'm passing in value for auth_token=random_password.cache-auth-token.result, the fact its now needs to be replaced doesn't seem to be detected and erroring about the old issue (@ was in the generated password) even though that resource should be re-created. If I change the value to a constant value, such as auth_token="1234567890abcdef", the correct plan is emitted.

Tainting the module.cache.aws_elasticache_parameter_group.default[0] resource doesn't seem to have any effect either.

I suspect this has something to do with the way there is a count on the elasticache resource and the if statement in the module may be confusing the dependency walker. See https://github.com/cloudposse/terraform-aws-elasticache-redis/blob/master/main.tf#L82

Note. Attempting to destroy the resources still throws an error. I have to set a constant value for the auth_token before destroy will plan correctly. Strange (maybe an aws provider issue at the core?)

References

None

bug core v0.12

All 6 comments

Hi @dekimsey,

Thanks for filing the issue. The dependencies are being handled correctly, but an artifact of the resource config is being stored in the state, which will continually fail validation. Since this is only going to happen during the refresh phase before the state is updated, you can work around this for now with
-refresh=false

Note for future investigation, a repro with a test provider is writing the state with "id": "none", so something may be getting coerced improperly after this error.

Thank you @jbardin, that's good to know! Do you need more details from the debug log? I still have it if needed.

Thanks @dekimsey, we can replicate this internally for investigation.

Closing this since 0.14 will no longer use a separate refresh walk.

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 have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

Was this page helpful?
0 / 5 - 0 ratings