Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Robert Roland committed Feb 2, 2017
1 parent 43c962e commit 4cdcfe5
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 25 deletions.
54 changes: 29 additions & 25 deletions pkg/cloudprovider/providers/vsphere/vsphere.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import (
"errors"
"fmt"
"io"
"net"
"io/ioutil"
"net/url"
"path"
"path/filepath"
Expand Down Expand Up @@ -124,12 +124,15 @@ type VSphereConfig struct {
WorkingDir string `gcfg:"working-dir"`
// Soap round tripper count (retries = RoundTripper - 1)
RoundTripperCount uint `gcfg:"soap-roundtrip-count"`
// VMUUID is the virtual machine's UUID. If not set, will be fetched from the machine.
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"`
Expand Down Expand Up @@ -201,17 +204,30 @@ func init() {
})
}

// Returns the name of the VM and its Cluster on which this code is running.
// This is done by searching for the name of virtual machine by current IP.
// 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.
func readInstance(client *govmomi.Client, cfg *VSphereConfig) (string, string, error) {
addrs, err := net.InterfaceAddrs()
if err != nil {
return "", "", err
// 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, string, error) {
var vmUUID string

if cfg.Global.VMUUID != "" {
vmUUID = cfg.Global.VMUUID
glog.Infof("VM UUID specified in cloud config: %s", vmUUID)
} else {
vmUUIDbytes, err := ioutil.ReadFile("/sys/devices/virtual/dmi/id/product_uuid")
if err != nil {
return "", "", err
}

vmUUID = string(vmUUIDbytes)
cfg.Global.VMUUID = vmUUID
glog.Infof("VM UUID retrieved from sysfs: %s", 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
Expand All @@ -230,21 +246,9 @@ func readInstance(client *govmomi.Client, cfg *VSphereConfig) (string, string, e

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")
svm, err := s.FindByUuid(ctx, dc, strings.ToLower(strings.TrimSpace(vmUUID)), true, nil)
if err != nil {
return "", "", err
}

var vm mo.VirtualMachine
Expand Down Expand Up @@ -292,7 +296,7 @@ func newVSphere(cfg VSphereConfig) (*VSphere, error) {
return nil, err
}

id, cluster, err := readInstance(c, &cfg)
id, cluster, err := getVMName(c, &cfg)
if err != nil {
return nil, err
}
Expand Down
5 changes: 5 additions & 0 deletions pkg/cloudprovider/providers/vsphere/vsphere_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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) {
Expand Down

0 comments on commit 4cdcfe5

Please sign in to comment.