From 2728e198fd7cabab753ea1876f817d7703e4c45c Mon Sep 17 00:00:00 2001 From: Ali Rizvi-Santiago Date: Fri, 14 Aug 2020 11:23:56 -0500 Subject: [PATCH] Fixed SetHardwareOptions to fetch the hardware version from QueryConfigOption instead of the default properties (#1159) * Implemented the ConfigOptions function in the virtual machine helpers. * Fixed SetHardwareVersion to query the version directly from the ConfigOptions of the machine rather than the machine's properties. --- .../virtualmachine/virtual_machine_helper.go | 53 ++++++++++++++++--- 1 file changed, 45 insertions(+), 8 deletions(-) diff --git a/vsphere/internal/helper/virtualmachine/virtual_machine_helper.go b/vsphere/internal/helper/virtualmachine/virtual_machine_helper.go index 938882c9d..23ae324a6 100644 --- a/vsphere/internal/helper/virtualmachine/virtual_machine_helper.go +++ b/vsphere/internal/helper/virtualmachine/virtual_machine_helper.go @@ -23,6 +23,7 @@ import ( "github.com/vmware/govmomi/object" "github.com/vmware/govmomi/property" "github.com/vmware/govmomi/view" + "github.com/vmware/govmomi/vim25/methods" "github.com/vmware/govmomi/vim25/mo" "github.com/vmware/govmomi/vim25/types" ) @@ -213,6 +214,32 @@ func Properties(vm *object.VirtualMachine) (*mo.VirtualMachine, error) { return &props, nil } +// ConfigOptions is a convenience method that wraps fetching the VirtualMachine ConfigOptions +// as returned by QueryConfigOption. +func ConfigOptions(vm *object.VirtualMachine) (*types.VirtualMachineConfigOption, error) { + + // First grab the properties so that we can sneak the EnvironmentBrowser out of it + props, err := Properties(vm) + if err != nil { + return nil, err + } + + // Make a context so we can timeout according to the provider configuration + ctx, cancel := context.WithTimeout(context.Background(), provider.DefaultAPITimeout) + defer cancel() + + // Build a request for the config option, and then query for configuration options + log.Printf("[DEBUG] Fetching configuration options for VM %q", vm.InventoryPath) + request := types.QueryConfigOption{This: props.EnvironmentBrowser} + + response, err := methods.QueryConfigOption(ctx, vm.Client(), &request) + if err != nil { + return nil, err + } + + return response.Returnval, nil +} + // WaitForGuestIP waits for a virtual machine to have an IP address. // // The timeout is specified in minutes. If zero or a negative value is passed, @@ -889,25 +916,35 @@ func GetHardwareVersionNumber(vstring string) int { // SetHardwareVersion sets the virtual machine's hardware version. The virtual // machine must be powered off, and the version can only be increased. func SetHardwareVersion(vm *object.VirtualMachine, target int) error { - // First get current and target versions and validate - tv := GetHardwareVersionID(target) - vprops, err := Properties(vm) + + // First query for the configuration options of the vm + copts, err := ConfigOptions(vm) if err != nil { return err } - cv := vprops.Config.Version - // Skip the rest if there is no version change. - if cv == tv || tv == "" { + + // Now we can grab its version to compare against the target + current := int(copts.HardwareOptions.HwVersion) + log.Printf("[DEBUG] Found current hardware version: %d", current) + + // If the hardware version matches, then we're done here and can leave. + if current == target || target == 0 { return nil } - if err := ValidateHardwareVersion(GetHardwareVersionNumber(cv), target); err != nil { + + // Otherwise we need to validate it to ensure we're not downgrading + // the hardware version. + log.Printf("[DEBUG] Validating the target hardware version: %d", target) + if err := ValidateHardwareVersion(current, target); err != nil { return err } + // We can now proceed to upgrade the hardware version on the vm ctx, cancel := context.WithTimeout(context.Background(), provider.DefaultAPITimeout) defer cancel() - task, err := vm.UpgradeVM(ctx, tv) + log.Printf("[DEBUG] Upgrading VM from hw version %d to hw version %d", current, target) + task, err := vm.UpgradeVM(ctx, GetHardwareVersionID(target)) _, err = task.WaitForResult(ctx, nil) return err }