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.
pull/6/head
Robert Roland 2017-02-02 08:48:05 -08:00 committed by Robert Roland
parent c26bd88620
commit 53a009302a
2 changed files with 37 additions and 25 deletions

View File

@ -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()
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
}
if len(addrs) == 0 {
return "", fmt.Errorf("unable to retrieve Instance ID")
vmUUID = string(vmUUIDbytes)
cfg.Global.VMUUID = vmUUID
}
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
}

View File

@ -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) {