nutanix / terraform-provider-nutanix

Terraform Nutanix Provider
https://www.terraform.io/docs/providers/nutanix/
Mozilla Public License 2.0
95 stars 111 forks source link

nutanix_virtual_machine disk_size_* should be `(known after apply)` during plan when deploying from a template image #511

Open jantari opened 1 year ago

jantari commented 1 year ago

Nutanix Cluster Information

Terraform Version

Terraform v1.3.4 Nutanix Provider 1.7.1

Affected Resource(s)

Terraform Configuration Files

resource "nutanix_virtual_machine" "vm" {
  count                = var.vm_count_vm
  name                 = local.vm_names_vm[count.index]
  description          = <<EOF
                         Server purpose.
                         Repository: https://git.domain.tld/some/path
                         EOF
  num_sockets          = 1
  num_vcpus_per_socket = 2
  memory_size_mib      = 8 * 1024

  cluster_uuid = local.cluster_a

  nic_list {
    subnet_uuid = data.nutanix_subnet.subnet_a.id
  }

  disk_list {
    data_source_reference = {
      kind = "image"
      uuid = data.nutanix_image.win2022-desktop-de.id
    }
    device_properties {
      disk_address = {
        device_index = 0
        adapter_type = "SCSI"
      }
      device_type = "DISK"
    }
  }

  disk_list {
    device_properties {
      disk_address = {
        device_index = 1
        adapter_type = "IDE"
      }
      device_type = "CDROM"
    }
  }

  nutanix_guest_tools = {
    state           = "ENABLED"
    iso_mount_state = "MOUNTED"
  }

  guest_customization_sysprep = {
    install_type = "PREPARED"
    unattend_xml = base64encode(templatefile("sysprep.xml", {
      hostname = local.vm_names_vm[count.index]
    }))
  }  

  lifecycle {
    ignore_changes = [
      nutanix_guest_tools,
      disk_list.0.data_source_reference.uuid
    ]
  }
}

resource "netbox_virtual_machine" "vm" {
  count        = var.vm_count_vm
  name         = nutanix_virtual_machine.vm[count.index].name
  cluster_id   = data.netbox_cluster.cluster_ntnx-a.id
  disk_size_gb = sum([ for disk in nutanix_virtual_machine.vm[count.index].disk_list : disk.disk_size_mib if contains(disk.device_properties[*].device_type, "DISK") ]) / 1024
  memory_mb    = nutanix_virtual_machine.vm[count.index].memory_size_mib
  vcpus        = nutanix_virtual_machine.vm[count.index].num_sockets * nutanix_virtual_machine.vm[count.index].num_vcpus_per_socket
  comments     = nutanix_virtual_machine.vm[count.index].description
}

Debug Output

Panic Output

No panic.

Expected Behavior

The terraform plan should show the disk_size_bytes and disk_size_mib values as (known after apply) when deploying a VM from a template (data_source_reference). Instead it shows both as 0 which is wrong.

Actual Behavior

The terraform plan shows the disk_size values of the VM to be created as 0:

 # nutanix_virtual_machine.vm[0] will be created
  + resource "nutanix_virtual_machine" "vm" {
      + api_version                                      = (known after apply)
      + availability_zone_reference                      = (known after apply)
      + boot_device_disk_address                         = (known after apply)
      + boot_device_mac_address                          = (known after apply)
      + boot_device_order_list                           = (known after apply)
      + boot_type                                        = (known after apply)
      + cloud_init_cdrom_uuid                            = (known after apply)
      + cluster_name                                     = (known after apply)
      + cluster_uuid                                     = "<REDACTED>"
      + description                                      = <<-EOT
                                     Server purpose.
                                     Repository: https://git.domain.tld/some/path
        EOT
      + enable_cpu_passthrough                           = false
      + enable_script_exec                               = (known after apply)
      + guest_customization_cloud_init_custom_key_values = (known after apply)
      + guest_customization_cloud_init_meta_data         = (known after apply)
      + guest_customization_cloud_init_user_data         = (known after apply)
      + guest_customization_is_overridable               = (known after apply)
      + guest_customization_sysprep                      = (known after apply)
      + guest_customization_sysprep_custom_key_values    = (known after apply)
      + guest_os_id                                      = (known after apply)
      + hardware_clock_timezone                          = (known after apply)
      + host_reference                                   = (known after apply)
      + hypervisor_type                                  = (known after apply)
      + id                                               = (known after apply)
      + is_vcpu_hard_pinned                              = false
      + machine_type                                     = (known after apply)
      + memory_size_mib                                  = 8192
      + metadata                                         = (known after apply)
      + name                                             = (known after apply)
      + ngt_credentials                                  = (known after apply)
      + ngt_enabled_capability_list                      = (known after apply)
      + nic_list_status                                  = (known after apply)
      + num_sockets                                      = 1
      + num_vcpus_per_socket                             = 2
      + num_vnuma_nodes                                  = (known after apply)
      + nutanix_guest_tools                              = {
          + "iso_mount_state" = "MOUNTED"
          + "state"           = "ENABLED"
        }
      + owner_reference                                  = (known after apply)
      + parent_reference                                 = (known after apply)
      + power_state                                      = (known after apply)
      + power_state_mechanism                            = (known after apply)
      + project_reference                                = (known after apply)
      + should_fail_on_script_failure                    = (known after apply)
      + state                                            = (known after apply)
      + use_hot_add                                      = true
      + vga_console_enabled                              = (known after apply)
      + categories {
          + name  = (known after apply)
          + value = (known after apply)
        }
      + disk_list {
          + data_source_reference  = {
              + "kind" = "image"
              + "uuid" = "<REDACTED>"
            }
          + disk_size_bytes        = 0
          + disk_size_mib          = 0
          + uuid                   = (known after apply)
          + volume_group_reference = (known after apply)
          + device_properties {
              + device_type  = "DISK"
              + disk_address = {
                  + "adapter_type" = "SCSI"
                  + "device_index" = "0"
                }
            }
        }
      + disk_list {
          + data_source_reference  = (known after apply)

[ ... truncated ... ]

and the netbox documentation entry we create with terraform of course shows the same 0 size in the plan:

  # netbox_virtual_machine.vm[0] will be created
  + resource "netbox_virtual_machine" "vm" {
      + cluster_id   = 1
      + comments     = <<-EOT
                                     Server purpose.
                                     Repository: https://git.domain.tld/some/path
        EOT
      + disk_size_gb = 0
      + id           = (known after apply)
      + memory_mb    = 8192
      + name         = (known after apply)
      + primary_ipv4 = (known after apply)
      + primary_ipv6 = (known after apply)
      + status       = "active"
      + vcpus        = 2
    }

However, the apply then fails because:

╷
│ Error: Provider produced inconsistent final plan
│ 
│ When expanding the plan for netbox_virtual_machine.vm[0] to
│ include new values learned so far during apply, provider
│ "registry.terraform.io/e-breuninger/netbox" produced an invalid new value
│ for .disk_size_gb: was cty.NumberIntVal(0), but now cty.NumberIntVal(50).
│ 
│ This is a bug in the provider, which should be reported in the provider's
│ own issue tracker.
╵

This is a bug with the nutanix terraform provider 1.7.1, it should know that a disk_size is known_after_apply when deploying from a VM template. Declaring it as known and 0 bytes in size is wrong and because the value changes unexpectedly after the apply, the above error happens.

Steps to Reproduce

Deploy a VM from a data_source_reference (VM template disk image). Run terraform plan. See how the disk_image_bytes and disk_image_mib are supposedly "0". This is a bug and causes further errors with other resources as shown above.

Important Factors

We are using and running terraform against Prism Central. ​

References

I found a similar bug report for the AWS provider where they declared a tag value as known during plan, but then it changed after the apply causing this same error. Values that aren't known until after the apply must be declared (known after apply) in terraform. https://github.com/hashicorp/terraform-provider-aws/issues/19583