Change ipv4_address forces VM replacement?!

Hi all, I’ve been playing with Terraform and vSphere, and come across an unexpected surprise. If I create a VM with a static IP, and then want to change it, TF wants to delete the original one and create it anew! This is not very useful. Am I missing something?
This is what I’m talking about:

(...)
    dynamic "network_interface" {
        for_each = [for x in ["1"] : x if var.IP_address != "DHCP"]
        content {
          ipv4_address    = var.IP_address
          ipv4_netmask    = var.netmask
          dns_server_list = (var.OS_type == "Windows" ? var.DNS_server_list : [ ])
          dns_domain      = (var.OS_type == "Windows" ? var.DNS_domain : "")
        }
      }
(...)

And here’s the plan:

Terraform will perform the following actions:
  # module.VM["SF-CCTV5"].vsphere_virtual_machine.vm must be replaced
-/+ resource "vsphere_virtual_machine" "vm" {
      - boot_delay                              = 0 -> null
      - boot_retry_enabled                      = false -> null
      ~ change_version                          = "2023-05-12T20:47:17.648962Z" -> (known after apply)
      - cpu_performance_counters_enabled        = false -> null
      - cpu_reservation                         = 0 -> null
      ~ cpu_share_count                         = 2000 -> (known after apply)
      - custom_attributes                       = {
          - "101" = "Fri May 12 17:47:03 2023 -0300,[spoiler]sf-nbmaster[/spoiler],VMware"
        } -> null
      ~ default_ip_address                      = "10.5.1.178" -> (known after apply)
      - efi_secure_boot_enabled                 = false -> null
      - enable_disk_uuid                        = false -> null
      - enable_logging                          = false -> null
      - extra_config                            = {} -> null
      ~ guest_ip_addresses                      = [
          - "10.5.1.178",
          - "fe80::66f3:c858:8abb:2a8b",
        ] -> (known after apply)
      ~ hardware_version                        = 17 -> (known after apply)
      ~ host_system_id                          = "host-303060" -> (known after apply)
      ~ id                                      = "423880cb-1a64-d152-e813-e92a496d6c38" -> (known after apply)
      + imported                                = (known after apply)
      - memory_reservation                      = 0 -> null
      ~ memory_share_count                      = 81920 -> (known after apply)
      ~ moid                                    = "vm-303933" -> (known after apply)
        name                                    = "SF-CCTV5"
      - nested_hv_enabled                       = false -> null
      - pci_device_id                           = [] -> null
      ~ power_state                             = "on" -> (known after apply)
      ~ reboot_required                         = false -> (known after apply)
      - run_tools_scripts_before_guest_reboot   = false -> null
      + storage_policy_id                       = (known after apply)
      - sync_time_with_host                     = false -> null
      - sync_time_with_host_periodically        = false -> null
      - tags                                    = [] -> null
      ~ uuid                                    = "423880cb-1a64-d152-e813-e92a496d6c38" -> (known after apply)
      ~ vapp_transport                          = [] -> (known after apply)
      - vbs_enabled                             = false -> null
      ~ vmware_tools_status                     = "guestToolsRunning" -> (known after apply)
      ~ vmx_path                                = "SF-CCTV5/SF-CCTV5.vmx" -> (known after apply)
      - vvtd_enabled                            = false -> null
        # (38 unchanged attributes hidden)
      ~ clone {
          - linked_clone    = false -> null
          - ovf_network_map = {} -> null
          - ovf_storage_map = {} -> null
            # (2 unchanged attributes hidden)
          ~ customize {
                # (4 unchanged attributes hidden)
              ~ network_interface {
                  ~ ipv4_address    = "10.5.1.178" -> "10.5.1.30" # forces replacement
                  - ipv6_netmask    = 0 -> null
                    # (3 unchanged attributes hidden)
                }
                # (1 unchanged block hidden)
            }
        }
      ~ disk {
          ~ datastore_id      = "datastore-303279" -> "<computed>"
          ~ device_address    = "scsi:0:0" -> (known after apply)
          ~ io_share_count    = 1000 -> 0
          ~ key               = 2000 -> 0
          ~ path              = "SF-CCTV5/SF-CCTV5_1.vmdk" -> (known after apply)
          + storage_policy_id = (known after apply)
          ~ uuid              = "6000C291-df47-5844-65b0-1c73e6a62abf" -> (known after apply)
            # (14 unchanged attributes hidden)
        }
      ~ network_interface {
          ~ bandwidth_share_count = 50 -> (known after apply)
          ~ device_address        = "pci:0:7" -> (known after apply)
          ~ key                   = 4000 -> (known after apply)
          ~ mac_address           = "00:50:56:b8:c4:b8" -> (known after apply)
          - use_static_mac        = false -> null
            # (5 unchanged attributes hidden)
        }
    }
Plan: 1 to add, 0 to change, 1 to destroy.

Thanks!

Gabriel

Welcome to the forum - please reformat your message - the output above is rather mangled.

Whether to force a replacement on change is entirely up to the individual provider implementation of the resource.

Since the parameter you are changing is apparently part of VMware’s “customization” functionality which takes place during VM creation, it makes sense that VMware would need to re-create the VM to create it with different customization options - so the Terraform provider would appear to just be surfacing the properties of the underlying infrastructure.

You’re right, I trust it looks better now. Thanks for you reply, that’s a very good answer and it makes a lot of sense. And I didn’t expect to get one so soon. Kudos to you!