vmware / terraform-provider-avi

Terraform AVI Networks provider
https://registry.terraform.io/providers/vmware/avi/latest/docs
Mozilla Public License 2.0
31 stars 32 forks source link

`create_before_destroy = false` not working as expected when renaming TF resources #606

Open jakauppila opened 1 month ago

jakauppila commented 1 month ago

Describe the bug

Terraform offers a lifecycle block to customize how a resource is managed.

In attempting to leverage the create_before_destroy = false config since AVI has constraints on resource names, I've found that more often than not the provider is still running into a name conflict. I think it's simply due to timing, but it should be able to handle this appropriately.

Reproduction steps

  1. Use the following TF config:
terraform {
  required_providers {
    avi = {
      source  = "vmware/avi"
      version = "30.2.1"
    }
  }
}

provider "avi" {
}

resource "avi_pool" "pool" {
  name = "foo"

  lifecycle {
    create_before_destroy = false
  }
}
  1. Terraform apply
  2. Modify the TF to name the pool from pool to pool-80
  3. Terraform apply
  4. Error!
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create
  - destroy

Terraform will perform the following actions:

  # avi_pool.pool will be destroyed
  # (because avi_pool.pool is not in configuration)
  - resource "avi_pool" "pool" {
      - analytics_profile_ref                 = "https://AVICONTROLLER/api/analyticsprofile/analyticsprofile-73519e8a-3134-482e-8a30-6a0b826b45dc" -> null
      - append_port                           = "NON_DEFAULT_80_443" -> null
      - capacity_estimation                   = "false" -> null
      - capacity_estimation_ttfb_thresh       = "0" -> null
      - cloud_ref                             = "https://AVICONTROLLER/api/cloud/cloud-13da7a90-8288-4f4a-80d0-5974e52c174b" -> null
      - connection_ramp_duration              = "10" -> null
      - default_server_port                   = "80" -> null
      - delete_server_on_dns_refresh          = "true" -> null
      - enable_http2                          = "false" -> null
      - enabled                               = "true" -> null
      - fewest_tasks_feedback_delay           = "10" -> null
      - graceful_disable_timeout              = "1" -> null
      - graceful_hm_down_disable_timeout      = "-1" -> null
      - host_check_enabled                    = "false" -> null
      - id                                    = "https://AVICONTROLLER/api/pool/pool-2c571284-b144-43e8-b0ea-7ab36246ca0d" -> null
      - ignore_server_port                    = "false" -> null
      - ignore_servers                        = false -> null
      - inline_health_monitor                 = "true" -> null
      - lb_algo_rr_per_se                     = "false" -> null
      - lb_algorithm                          = "LB_ALGORITHM_LEAST_CONNECTIONS" -> null
      - lb_algorithm_core_nonaffinity         = "2" -> null
      - lb_algorithm_hash                     = "LB_ALGORITHM_CONSISTENT_HASH_SOURCE_IP_ADDRESS" -> null
      - lookup_server_by_name                 = "false" -> null
      - max_concurrent_connections_per_server = "0" -> null
      - name                                  = "foo" -> null
      - pool_type                             = "POOL_TYPE_GENERIC_APP" -> null
      - request_queue_depth                   = "128" -> null
      - request_queue_enabled                 = "false" -> null
      - rewrite_host_header_to_server_name    = "false" -> null
      - rewrite_host_header_to_sni            = "false" -> null
      - routing_pool                          = "false" -> null
      - server_disable_type                   = "DISALLOW_NEW_CONNECTION" -> null
      - server_timeout                        = "0" -> null
      - sni_enabled                           = "true" -> null
      - tenant_ref                            = "https://AVICONTROLLER/api/tenant/admin" -> null
      - use_service_port                      = "false" -> null
      - use_service_ssl_mode                  = "false" -> null
      - uuid                                  = "pool-2c571284-b144-43e8-b0ea-7ab36246ca0d" -> null
      - vrf_ref                               = "https://AVICONTROLLER/api/vrfcontext/vrfcontext-b58b3dee-5947-495a-8ad4-ae5b9bf2fe50" -> null

      - http2_properties {
          - max_http2_control_frames_per_connection = "0" -> null
          - max_http2_header_field_size             = "4096" -> null
        }
    }

  # avi_pool.pool-80 will be created
  + resource "avi_pool" "pool-80" {
      + analytics_profile_ref                 = (known after apply)
      + append_port                           = "NON_DEFAULT_80_443"
      + application_persistence_profile_ref   = (known after apply)
      + autoscale_launch_config_ref           = (known after apply)
      + autoscale_policy_ref                  = (known after apply)
      + capacity_estimation                   = "false"
      + capacity_estimation_ttfb_thresh       = "0"
      + cloud_config_cksum                    = (known after apply)
      + cloud_ref                             = (known after apply)
      + connection_ramp_duration              = "10"
      + created_by                            = (known after apply)
      + default_server_port                   = "80"
      + delete_server_on_dns_refresh          = "true"
      + description                           = (known after apply)
      + east_west                             = (known after apply)
      + enable_http2                          = "false"
      + enabled                               = "true"
      + fewest_tasks_feedback_delay           = "10"
      + graceful_disable_timeout              = "1"
      + graceful_hm_down_disable_timeout      = "-1"
      + gslb_sp_enabled                       = (known after apply)
      + host_check_enabled                    = "false"
      + id                                    = (known after apply)
      + ignore_server_port                    = "false"
      + ignore_servers                        = false
      + inline_health_monitor                 = "true"
      + ipaddrgroup_ref                       = (known after apply)
      + lb_algo_rr_per_se                     = "false"
      + lb_algorithm                          = "LB_ALGORITHM_LEAST_CONNECTIONS"
      + lb_algorithm_consistent_hash_hdr      = (known after apply)
      + lb_algorithm_core_nonaffinity         = "2"
      + lb_algorithm_hash                     = "LB_ALGORITHM_CONSISTENT_HASH_SOURCE_IP_ADDRESS"
      + lookup_server_by_name                 = "false"
      + max_concurrent_connections_per_server = "0"
      + min_health_monitors_up                = (known after apply)
      + min_servers_up                        = (known after apply)
      + name                                  = "foo"
      + pki_profile_ref                       = (known after apply)
      + pool_type                             = "POOL_TYPE_GENERIC_APP"
      + request_queue_depth                   = "128"
      + request_queue_enabled                 = "false"
      + resolve_pool_by_dns                   = (known after apply)
      + rewrite_host_header_to_server_name    = "false"
      + rewrite_host_header_to_sni            = "false"
      + routing_pool                          = "false"
      + server_disable_type                   = "DISALLOW_NEW_CONNECTION"
      + server_name                           = (known after apply)
      + server_timeout                        = "0"
      + service_metadata                      = (known after apply)
      + sni_enabled                           = "true"
      + ssl_key_and_certificate_ref           = (known after apply)
      + ssl_profile_ref                       = (known after apply)
      + tenant_ref                            = (known after apply)
      + tier1_lr                              = (known after apply)
      + use_service_port                      = "false"
      + use_service_ssl_mode                  = "false"
      + uuid                                  = (known after apply)
      + vrf_ref                               = (known after apply)
    }

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

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

  Enter a value: yes

avi_pool.pool: Destroying... [id=https://AVICONTROLLER/api/pool/pool-2c571284-b144-43e8-b0ea-7ab36246ca0d]
avi_pool.pool-80: Creating...
avi_pool.pool: Destruction complete after 1s
╷
│ Error: Encountered an error on POST request to URL https://AVICONTROLLER/api/pool: HTTP code: 409; error from Controller: map[error:Pool with this Name, Tenant ref and Cloud ref already exists.]
│
│   with avi_pool.pool-80,
│   on main.tf line 1, in resource "avi_pool" "pool-80":
│    1: resource "avi_pool" "pool-80" {
│
╵

Expected behavior

The provider should properly handle the timing of destroying the old resource and creating the new resource.

I can occasionally get this to work.

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

Terraform will perform the following actions:

  # avi_pool.pool will be destroyed
  # (because avi_pool.pool is not in configuration)
  - resource "avi_pool" "pool" {
      - analytics_profile_ref                 = "https://AVICONTROLLER/api/analyticsprofile/analyticsprofile-73519e8a-3134-482e-8a30-6a0b826b45dc" -> null
      - append_port                           = "NON_DEFAULT_80_443" -> null
      - capacity_estimation                   = "false" -> null
      - capacity_estimation_ttfb_thresh       = "0" -> null
      - cloud_ref                             = "https://AVICONTROLLER/api/cloud/cloud-13da7a90-8288-4f4a-80d0-5974e52c174b" -> null
      - connection_ramp_duration              = "10" -> null
      - default_server_port                   = "80" -> null
      - delete_server_on_dns_refresh          = "true" -> null
      - enable_http2                          = "false" -> null
      - enabled                               = "true" -> null
      - fewest_tasks_feedback_delay           = "10" -> null
      - graceful_disable_timeout              = "1" -> null
      - graceful_hm_down_disable_timeout      = "-1" -> null
      - host_check_enabled                    = "false" -> null
      - id                                    = "https://AVICONTROLLER/api/pool/pool-ee216ef8-6969-44cb-bf87-7bc33918fe6a" -> null
      - ignore_server_port                    = "false" -> null
      - ignore_servers                        = false -> null
      - inline_health_monitor                 = "true" -> null
      - lb_algo_rr_per_se                     = "false" -> null
      - lb_algorithm                          = "LB_ALGORITHM_LEAST_CONNECTIONS" -> null
      - lb_algorithm_core_nonaffinity         = "2" -> null
      - lb_algorithm_hash                     = "LB_ALGORITHM_CONSISTENT_HASH_SOURCE_IP_ADDRESS" -> null
      - lookup_server_by_name                 = "false" -> null
      - max_concurrent_connections_per_server = "0" -> null
      - name                                  = "foo" -> null
      - pool_type                             = "POOL_TYPE_GENERIC_APP" -> null
      - request_queue_depth                   = "128" -> null
      - request_queue_enabled                 = "false" -> null
      - rewrite_host_header_to_server_name    = "false" -> null
      - rewrite_host_header_to_sni            = "false" -> null
      - routing_pool                          = "false" -> null
      - server_disable_type                   = "DISALLOW_NEW_CONNECTION" -> null
      - server_timeout                        = "0" -> null
      - sni_enabled                           = "true" -> null
      - tenant_ref                            = "https://AVICONTROLLER/api/tenant/admin" -> null
      - use_service_port                      = "false" -> null
      - use_service_ssl_mode                  = "false" -> null
      - uuid                                  = "pool-ee216ef8-6969-44cb-bf87-7bc33918fe6a" -> null
      - vrf_ref                               = "https://AVICONTROLLER/api/vrfcontext/vrfcontext-b58b3dee-5947-495a-8ad4-ae5b9bf2fe50" -> null

      - http2_properties {
          - max_http2_control_frames_per_connection = "0" -> null
          - max_http2_header_field_size             = "4096" -> null
        }
    }

  # avi_pool.pool-80 will be created
  + resource "avi_pool" "pool-80" {
      + analytics_profile_ref                 = (known after apply)
      + append_port                           = "NON_DEFAULT_80_443"
      + application_persistence_profile_ref   = (known after apply)
      + autoscale_launch_config_ref           = (known after apply)
      + autoscale_policy_ref                  = (known after apply)
      + capacity_estimation                   = "false"
      + capacity_estimation_ttfb_thresh       = "0"
      + cloud_config_cksum                    = (known after apply)
      + cloud_ref                             = (known after apply)
      + connection_ramp_duration              = "10"
      + created_by                            = (known after apply)
      + default_server_port                   = "80"
      + delete_server_on_dns_refresh          = "true"
      + description                           = (known after apply)
      + east_west                             = (known after apply)
      + enable_http2                          = "false"
      + enabled                               = "true"
      + fewest_tasks_feedback_delay           = "10"
      + graceful_disable_timeout              = "1"
      + graceful_hm_down_disable_timeout      = "-1"
      + gslb_sp_enabled                       = (known after apply)
      + host_check_enabled                    = "false"
      + id                                    = (known after apply)
      + ignore_server_port                    = "false"
      + ignore_servers                        = false
      + inline_health_monitor                 = "true"
      + ipaddrgroup_ref                       = (known after apply)
      + lb_algo_rr_per_se                     = "false"
      + lb_algorithm                          = "LB_ALGORITHM_LEAST_CONNECTIONS"
      + lb_algorithm_consistent_hash_hdr      = (known after apply)
      + lb_algorithm_core_nonaffinity         = "2"
      + lb_algorithm_hash                     = "LB_ALGORITHM_CONSISTENT_HASH_SOURCE_IP_ADDRESS"
      + lookup_server_by_name                 = "false"
      + max_concurrent_connections_per_server = "0"
      + min_health_monitors_up                = (known after apply)
      + min_servers_up                        = (known after apply)
      + name                                  = "foo"
      + pki_profile_ref                       = (known after apply)
      + pool_type                             = "POOL_TYPE_GENERIC_APP"
      + request_queue_depth                   = "128"
      + request_queue_enabled                 = "false"
      + resolve_pool_by_dns                   = (known after apply)
      + rewrite_host_header_to_server_name    = "false"
      + rewrite_host_header_to_sni            = "false"
      + routing_pool                          = "false"
      + server_disable_type                   = "DISALLOW_NEW_CONNECTION"
      + server_name                           = (known after apply)
      + server_timeout                        = "0"
      + service_metadata                      = (known after apply)
      + sni_enabled                           = "true"
      + ssl_key_and_certificate_ref           = (known after apply)
      + ssl_profile_ref                       = (known after apply)
      + tenant_ref                            = (known after apply)
      + tier1_lr                              = (known after apply)
      + use_service_port                      = "false"
      + use_service_ssl_mode                  = "false"
      + uuid                                  = (known after apply)
      + vrf_ref                               = (known after apply)
    }

Plan: 1 to add, 0 to change, 1 to destroy.
avi_pool.pool: Destroying... [id=https://AVICONTROLLER/api/pool/pool-ee216ef8-6969-44cb-bf87-7bc33918fe6a]
avi_pool.pool-80: Creating...
avi_pool.pool: Destruction complete after 1s
avi_pool.pool-80: Creation complete after 2s [id=https://AVICONTROLLER/api/pool/pool-0a17b276-0d00-4300-b95e-4ce384a700ed]

Additional context

No response