hashicorp / terraform-provider-awscc

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

Provider "registry.terraform.io/hashicorp/awscc" planned an invalid value for awscc_s3_bucket.this[0].tags: planned for absence but config wants existence. #700

Open rchildress87 opened 2 years ago

rchildress87 commented 2 years ago

Community Note

Terraform CLI and Terraform AWS Cloud Control Provider Version

$ terraform -v

Terraform v1.3.3
on darwin_arm64
+ provider registry.terraform.io/hashicorp/aws v4.36.1
+ provider registry.terraform.io/hashicorp/awscc v0.35.0

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.

terraform {
  required_version = ">= 0.13.1"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = ">= 4.9"
    }
    awscc = {
      source  = "hashicorp/awscc"
      version = "0.35.0"
    }
  }
}

variable "tags" {
  description = "(Optional) A mapping of tags to assign to the bucket."
  type        = list(map(string))
  default     = []
}

resource "awscc_s3_bucket" "this" {
  count = 1

  bucket_name = "random-bucket-098afde2"
  tags        = var.tags
}

Debug Output

https://gist.github.com/rchildress87/1fdfe85c8b981bc6809e24fd58733e1d

Expected Behavior

$ terraform plan

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # awscc_s3_bucket.this[0] will be created
  + resource "awscc_s3_bucket" "this" {
      + accelerate_configuration           = {
          + acceleration_status = (known after apply)
        }
      + access_control                     = (known after apply)
      + analytics_configurations           = [
        ] -> (known after apply)
      + arn                                = (known after apply)
      + bucket_encryption                  = {
          + server_side_encryption_configuration = [
            ] -> (known after apply)
        }
      + bucket_name                        = "random-bucket-098afde2"
      + cors_configuration                 = {
          + cors_rules = [
            ] -> (known after apply)
        }
      + domain_name                        = (known after apply)
      + dual_stack_domain_name             = (known after apply)
      + id                                 = (known after apply)
      + intelligent_tiering_configurations = [
        ] -> (known after apply)
      + inventory_configurations           = [
        ] -> (known after apply)
      + lifecycle_configuration            = {
          + rules = [
            ] -> (known after apply)
        }
      + logging_configuration              = {
          + destination_bucket_name = (known after apply)
          + log_file_prefix         = (known after apply)
        }
      + metrics_configurations             = [
        ] -> (known after apply)
      + notification_configuration         = {
          + event_bridge_configuration = {
              + event_bridge_enabled = (known after apply)
            }
          + lambda_configurations      = [
            ] -> (known after apply)
          + queue_configurations       = [
            ] -> (known after apply)
          + topic_configurations       = [
            ] -> (known after apply)
        }
      + object_lock_configuration          = {
          + object_lock_enabled = (known after apply)
          + rule                = {
              + default_retention = {
                  + days  = (known after apply)
                  + mode  = (known after apply)
                  + years = (known after apply)
                }
            }
        }
      + object_lock_enabled                = (known after apply)
      + ownership_controls                 = {
          + rules = [
            ] -> (known after apply)
        }
      + public_access_block_configuration  = {
          + block_public_acls       = (known after apply)
          + block_public_policy     = (known after apply)
          + ignore_public_acls      = (known after apply)
          + restrict_public_buckets = (known after apply)
        }
      + regional_domain_name               = (known after apply)
      + replication_configuration          = {
          + role  = (known after apply)
          + rules = [
            ] -> (known after apply)
        }
      + tags                               = [
        ]
      + versioning_configuration           = {
          + status = (known after apply)
        }
      + website_configuration              = {
          + error_document           = (known after apply)
          + index_document           = (known after apply)
          + redirect_all_requests_to = {
              + host_name = (known after apply)
              + protocol  = (known after apply)
            }
          + routing_rules            = [
            ] -> (known after apply)
        }
      + website_url                        = (known after apply)
    }

Plan: 1 to add, 0 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.

Actual Behavior

$ terraform plan
╷
│ Error: Provider produced invalid plan
│ 
│ Provider "registry.terraform.io/hashicorp/awscc" planned an invalid value for awscc_s3_bucket.this[0].tags: planned for absence but config wants existence.
│ 
│ This is a bug in the provider, which should be reported in the provider's own issue tracker.

Steps to Reproduce

  1. terraform plan

Important Factoids

$ terraform destroy

awscc_s3_bucket.this[0]: Refreshing state... [id=random-bucket-098afde2]
╷
│ Error: Provider produced invalid plan
│ 
│ Provider "registry.terraform.io/hashicorp/awscc" planned an invalid value for awscc_s3_bucket.this[0].tags: planned for absence but config wants existence.
│ 
│ This is a bug in the provider, which should be reported in the provider's own issue tracker.

References

ewbankkit commented 1 year ago

Cloud Control API resources return empty lists of tags ([]) when none have been configured (null):

% aws ec2 describe-vpcs --vpc-ids vpc-07001c5ffc0c12783
{
    "Vpcs": [
        {
            "CidrBlock": "10.0.0.0/16",
            "DhcpOptionsId": "dopt-11ac7e74",
            "State": "available",
            "VpcId": "vpc-07001c5ffc0c12783",
            "OwnerId": "187416307283",
            "InstanceTenancy": "default",
            "CidrBlockAssociationSet": [
                {
                    "AssociationId": "vpc-cidr-assoc-0f4017a7b8f3f3c3a",
                    "CidrBlock": "10.0.0.0/16",
                    "CidrBlockState": {
                        "State": "associated"
                    }
                }
            ],
            "IsDefault": false
        }
    ]
}
% aws cloudcontrol get-resource --type-name AWS::EC2::VPC --identifier vpc-07001c5ffc0c12783
{
    "TypeName": "AWS::EC2::VPC",
    "ResourceDescription": {
        "Identifier": "vpc-07001c5ffc0c12783",
        "Properties": "{\"VpcId\":\"vpc-07001c5ffc0c12783\",\"InstanceTenancy\":\"default\",\"CidrBlockAssociations\":[\"vpc-cidr-assoc-0f4017a7b8f3f3c3a\"],\"CidrBlock\":\"10.0.0.0/16\",\"DefaultNetworkAcl\":\"acl-064bcd06d8cee8724\",\"EnableDnsSupport\":true,\"Ipv6CidrBlocks\":[],\"DefaultSecurityGroup\":\"sg-04a64882152661d6b\",\"EnableDnsHostnames\":false,\"Tags\":[]}"
    }
}

In general Terraform treats null and [] differently (and since we are generating resources generically from CFN schemas, everything is "general"), so https://github.com/hashicorp/terraform-provider-awscc/pull/368 was implemented to map a returned empty list ([]) to null.

So, if the configured value is an empty list ([]) the Terraform will report a diff wanting to convert this to a non-configured value (null).