vmware / terraform-provider-vcd

Terraform VMware Cloud Director provider
https://www.terraform.io/docs/providers/vcd/
Mozilla Public License 2.0
152 stars 112 forks source link

vcd_vapp_vm: recognize if the VM's power_on state has changed and reconcile #537

Open lvirbalas opened 4 years ago

lvirbalas commented 4 years ago

Affected Resource(s)

Terraform Configuration Files

resource "vcd_vapp_vm" "demo_vm_wordpress" {
  vapp_name     = vcd_vapp.demo_vapp.name
  name          = "demo-vm-wordpress"
  catalog_name  = "shared-catalog"
  template_name = "bitnami-wordpress-5.3.2-2-r01-linux-centos-7-x86_64"
  memory        = 512
  cpus          = 1

  power_on = true

  network {
    type               = "org"
    name               = vcd_vapp_org_network.demo_vapp_net_org.org_network_name
    ip_allocation_mode = "POOL"
    is_primary         = true
  }

  accept_all_eulas = "true"
}

Steps to Reproduce

  1. Power off the VM from VCD UI.
  2. Run terraform plan.

Expected Behavior

The plan should show that the actual VM is powered off and suggest to reconcile the state (power it back on).

Actual Behavior

Terraform doesn't notice the change in VM:

Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

References

Here's a similar example where it does work. Change VM CPU count in UI and run Terraform. It will reconcile the state:

 # vcd_vapp_vm.demo_vm_wordpress will be updated in-place
  ~ resource "vcd_vapp_vm" "demo_vm_wordpress" {
        accept_all_eulas               = true
        catalog_name                   = "shared-catalog"
        computer_name                  = "bitnami-wordpress-532-2-r01-linux-centos-7-x8664-001"
        cpu_cores                      = 1
        cpus                           = 1
        expose_hardware_virtualization = false
        guest_properties               = {
            "demo.setting" = "Guest property set by Terraform vCD Provider"
        }
        hardware_version               = "vmx-08"
        href                           = "https://..."
        id                             = "urn:vcloud:vm:a60a0c5f-0498-4610-8f48-27c7c9de8f5b"
        internal_disk                  = [
            {
                bus_number       = 0
                bus_type         = "parallel"
                disk_id          = "2000"
                iops             = 0
                size_in_mb       = 10240
                storage_profile  = "*"
                thin_provisioned = true
                unit_number      = 0
            },
        ]
        memory                         = 512
        metadata                       = {
            "demo_data" = "Terraform vCD Provider"
        }
        name                           = "demo-vm-wordpress"
        os_type                        = "otherLinux64Guest"
      ~ power_on                       = false -> true
        storage_profile                = "*"
        template_name                  = "bitnami-wordpress-5.3.2-2-r01-linux-centos-7-x86_64"
        vapp_name                      = "demo-web"

        customization {
            admin_password                      = (sensitive value)
            allow_local_admin_password          = true
            auto_generate_password              = true
            change_sid                          = false
            enabled                             = true
            force                               = false
            join_domain                         = false
            join_org_domain                     = false
            must_change_password_on_first_login = false
            number_of_auto_logons               = 0
        }

        network {
            adapter_type       = "VMXNET3"
            ip                 = "192.168.0.2"
            ip_allocation_mode = "POOL"
            is_primary         = true
            mac                = "00:50:56:29:00:04"
            name               = "demo-net-web"
            type               = "org"
        }
    }

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

vcd_vapp_vm.demo_vm_wordpress: Modifying... [id=urn:vcloud:vm:a60a0c5f-0498-4610-8f48-27c7c9de8f5b]
vcd_vapp_vm.demo_vm_wordpress: Still modifying... [id=urn:vcloud:vm:a60a0c5f-0498-4610-8f48-27c7c9de8f5b, 10s elapsed]
vcd_vapp_vm.demo_vm_wordpress: Still modifying... [id=urn:vcloud:vm:a60a0c5f-0498-4610-8f48-27c7c9de8f5b, 20s elapsed]
vcd_vapp_vm.demo_vm_wordpress: Still modifying... [id=urn:vcloud:vm:a60a0c5f-0498-4610-8f48-27c7c9de8f5b, 30s elapsed]
vcd_vapp_vm.demo_vm_wordpress: Still modifying... [id=urn:vcloud:vm:a60a0c5f-0498-4610-8f48-27c7c9de8f5b, 40s elapsed]
vcd_vapp_vm.demo_vm_wordpress: Modifications complete after 49s [id=urn:vcloud:vm:a60a0c5f-0498-4610-8f48-27c7c9de8f5b]

Apply complete! Resources: 0 added, 1 changed, 0 destroyed.
dataclouder commented 4 years ago

The field power_on is not state. It's a directive for create and update. If we want to detect state, we need to add a new field state (and eventually state_text) as we did for vApp.

The reason for such implementation is that the "powered on" corresponds to several status codes. If we tie the current power_on field to status 4 (= POWERED_ON) we will get a mismatch when the VM is in intermediate states that are not OFF, but not ON either, and we will have a request to update while the VM is reaching the online state.

This is a (possibly incomplete) list of the statuses available to vApp and VM

    -1: "FAILED_CREATION",
    0:  "UNRESOLVED",
    1:  "RESOLVED",
    2:  "DEPLOYED",
    3:  "SUSPENDED",
    4:  "POWERED_ON",
    5:  "WAITING_FOR_INPUT",
    6:  "UNKNOWN",
    7:  "UNRECOGNIZED",
    8:  "POWERED_OFF",
    9:  "INCONSISTENT_STATE",
    10: "MIXED",
    11: "DESCRIPTOR_PENDING",
    12: "COPYING_CONTENTS",
    13: "DISK_CONTENTS_PENDING",
    14: "QUARANTINED",
    15: "QUARANTINE_EXPIRED",
    16: "REJECTED",
    17: "TRANSFER_TIMEOUT",
    18: "VAPP_UNDEPLOYED",
    19: "VAPP_PARTIALLY_DEPLOYED",

If we map 1-to-1 the power_on field to the VM status, most likely we get a state comparison failure, because the VM could be in an intermediate state before reaching the wanted one. Notice that the status field is overloaded by meanings that have nothing to do with the VM being online or not.

This is not similar to what happens when we modify,, say, the amount of memory. If we change the memory outside of Terraform, at the next read we will get the exact memory that is now assigned, not an intermediate value, and a reconciliation is immediately possible.

With the VM status, this is not feasible. If we make, for example, a wanted_status="POWERED_ON", the state comparison will return an error if the status is in an intermediate phase, meaning that it will eventually be online, but not just yet. If we act on such state discrepancy and try to force a power on operation, we would get a further error because we can't power on an already online VM.

I suggest two actions:

  1. add the fields status and status_text like we have in vApp
  2. Possibly improve the wording of the documentation to explain that power_on does not collect state, but is only a request for action.