From 53a009302abed06b53ff9cee4be54cd04b762bab Mon Sep 17 00:00:00 2001 From: Robert Roland Date: Thu, 2 Feb 2017 08:48:05 -0800 Subject: [PATCH] Fixes #40819 Start looking up the virtual machine by it's UUID in vSphere again. Looking up by IP address is problematic and can either not return a VM entirely, or could return the wrong VM. Retrieves the VM's UUID in one of two methods - either by a `vm-uuid` entry in the cloud config file on the VM, or via sysfs. The sysfs route requires root access, but restores the previous functionality. Multiple VMs in a vCenter cluster can share an IP address - for example, if you have multiple VM networks, but they're all isolated and use the same address range. Additionally, flannel network address ranges can overlap. vSphere seems to have a limitation of reporting no more than 16 interfaces from a virtual machine, so it's possible that the IP address list on a VM is completely untrustworthy anyhow - it can either be empty (because the 16 interfaces it found were veth interfaces with no IP address), or it can report the flannel IP. --- .../providers/vsphere/vsphere.go | 57 +++++++++++-------- .../providers/vsphere/vsphere_test.go | 5 ++ 2 files changed, 37 insertions(+), 25 deletions(-) diff --git a/pkg/cloudprovider/providers/vsphere/vsphere.go b/pkg/cloudprovider/providers/vsphere/vsphere.go index 6b14649b1d6..60522b541a7 100644 --- a/pkg/cloudprovider/providers/vsphere/vsphere.go +++ b/pkg/cloudprovider/providers/vsphere/vsphere.go @@ -20,7 +20,7 @@ import ( "errors" "fmt" "io" - "net" + "io/ioutil" "net/url" "path" "path/filepath" @@ -122,12 +122,17 @@ type VSphereConfig struct { WorkingDir string `gcfg:"working-dir"` // Soap round tripper count (retries = RoundTripper - 1) RoundTripperCount uint `gcfg:"soap-roundtrip-count"` + // VMUUID is the VM Instance UUID of virtual machine which can be retrieved from instanceUuid + // property in VmConfigInfo, or also set as vc.uuid in VMX file. + // If not set, will be fetched from the machine via sysfs (requires root) + VMUUID string `gcfg:"vm-uuid"` } Network struct { // PublicNetwork is name of the network the VMs are joined to. PublicNetwork string `gcfg:"public-network"` } + Disk struct { // SCSIControllerType defines SCSI controller to be used. SCSIControllerType string `dcfg:"scsicontrollertype"` @@ -201,14 +206,27 @@ func init() { // Returns the name of the VM on which this code is running. // Prerequisite: this code assumes VMWare vmtools or open-vm-tools to be installed in the VM. +// Will attempt to determine the machine's name via it's UUID in this precedence order, failing if neither have a UUID: +// * cloud config value VMUUID +// * sysfs entry func getVMName(client *govmomi.Client, cfg *VSphereConfig) (string, error) { - addrs, err := net.InterfaceAddrs() - if err != nil { - return "", err + var vmUUID string + + if cfg.Global.VMUUID != "" { + vmUUID = cfg.Global.VMUUID + } else { + // This needs root privileges on the host, and will fail otherwise. + vmUUIDbytes, err := ioutil.ReadFile("/sys/devices/virtual/dmi/id/product_uuid") + if err != nil { + return "", err + } + + vmUUID = string(vmUUIDbytes) + cfg.Global.VMUUID = vmUUID } - if len(addrs) == 0 { - return "", fmt.Errorf("unable to retrieve Instance ID") + if vmUUID == "" { + return "", fmt.Errorf("unable to determine machine ID from cloud configuration or sysfs") } // Create context @@ -227,28 +245,17 @@ func getVMName(client *govmomi.Client, cfg *VSphereConfig) (string, error) { s := object.NewSearchIndex(client.Client) - var svm object.Reference - for _, v := range addrs { - ip, _, err := net.ParseCIDR(v.String()) - if err != nil { - return "", fmt.Errorf("unable to parse cidr from ip") - } - - // Finds a virtual machine or host by IP address. - svm, err = s.FindByIp(ctx, dc, ip.String(), true) - if err == nil && svm != nil { - break - } - } - if svm == nil { - return "", fmt.Errorf("unable to retrieve vm reference from vSphere") - } - - var vm mo.VirtualMachine - err = s.Properties(ctx, svm.Reference(), []string{"name", "resourcePool"}, &vm) + svm, err := s.FindByUuid(ctx, dc, strings.ToLower(strings.TrimSpace(vmUUID)), true, nil) if err != nil { return "", err } + + var vm mo.VirtualMachine + err = s.Properties(ctx, svm.Reference(), []string{"name"}, &vm) + if err != nil { + return "", err + } + return vm.Name, nil } diff --git a/pkg/cloudprovider/providers/vsphere/vsphere_test.go b/pkg/cloudprovider/providers/vsphere/vsphere_test.go index b7bbdd7cc57..89903b639c7 100644 --- a/pkg/cloudprovider/providers/vsphere/vsphere_test.go +++ b/pkg/cloudprovider/providers/vsphere/vsphere_test.go @@ -71,6 +71,7 @@ user = user password = password insecure-flag = true datacenter = us-west +vm-uuid = 1234 `)) if err != nil { t.Fatalf("Should succeed when a valid config is provided: %s", err) @@ -87,6 +88,10 @@ datacenter = us-west if cfg.Global.Datacenter != "us-west" { t.Errorf("incorrect datacenter: %s", cfg.Global.Datacenter) } + + if cfg.Global.VMUUID != "1234" { + t.Errorf("incorrect vm-uuid: %s", cfg.Global.VMUUID) + } } func TestNewVSphere(t *testing.T) {