From 808f18439d9231cfd1ef06575ae41670ead4ca2d Mon Sep 17 00:00:00 2001 From: Vipul Sabhaya Date: Thu, 18 Aug 2016 11:09:57 -0700 Subject: [PATCH] Make a vSphere cluster the failure_zone * Currently the vSphere cloud provider treats Datacenter as the failure Zone. This doesn't necessarily work since in the current implemention Kubernetes nodes cannot span Datacenters. * This change introduces Clusters as the failure zone, while treating Datacenters as Regions * Also updated tests for Zones --- .../providers/vsphere/vsphere.go | 54 ++++++++++++++----- .../providers/vsphere/vsphere_test.go | 8 ++- 2 files changed, 47 insertions(+), 15 deletions(-) diff --git a/pkg/cloudprovider/providers/vsphere/vsphere.go b/pkg/cloudprovider/providers/vsphere/vsphere.go index d6ae0135abf..c22c1de0d1f 100644 --- a/pkg/cloudprovider/providers/vsphere/vsphere.go +++ b/pkg/cloudprovider/providers/vsphere/vsphere.go @@ -72,6 +72,8 @@ type VSphere struct { cfg *VSphereConfig // InstanceID of the server where this VSphere object is instantiated. localInstanceID string + // Cluster that VirtualMachine belongs to + clusterName string } type VSphereConfig struct { @@ -126,17 +128,17 @@ func init() { }) } -// Returns the name of the VM on which this code is running. +// 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. // Prerequisite: this code assumes VMWare vmtools or open-vm-tools to be installed in the VM. -func readInstanceID(cfg *VSphereConfig) (string, error) { +func readInstance(cfg *VSphereConfig) (string, string, error) { addrs, err := net.InterfaceAddrs() if err != nil { - return "", err + return "", "", err } if len(addrs) == 0 { - return "", fmt.Errorf("unable to retrieve Instance ID") + return "", "", fmt.Errorf("unable to retrieve Instance ID") } // Create context @@ -146,7 +148,7 @@ func readInstanceID(cfg *VSphereConfig) (string, error) { // Create vSphere client c, err := vsphereLogin(cfg, ctx) if err != nil { - return "", err + return "", "", err } defer c.Logout(ctx) @@ -156,7 +158,7 @@ func readInstanceID(cfg *VSphereConfig) (string, error) { // Fetch and set data center dc, err := f.Datacenter(ctx, cfg.Global.Datacenter) if err != nil { - return "", err + return "", "", err } f.SetDatacenter(dc) @@ -166,7 +168,7 @@ func readInstanceID(cfg *VSphereConfig) (string, error) { for _, v := range addrs { ip, _, err := net.ParseCIDR(v.String()) if err != nil { - return "", fmt.Errorf("unable to parse cidr from ip") + return "", "", fmt.Errorf("unable to parse cidr from ip") } // Finds a virtual machine or host by IP address. @@ -176,19 +178,37 @@ func readInstanceID(cfg *VSphereConfig) (string, error) { } } if svm == nil { - return "", fmt.Errorf("unable to retrieve vm reference from vSphere") + return "", "", fmt.Errorf("unable to retrieve vm reference from vSphere") } var vm mo.VirtualMachine - err = s.Properties(ctx, svm.Reference(), []string{"name"}, &vm) + err = s.Properties(ctx, svm.Reference(), []string{"name", "resourcePool"}, &vm) if err != nil { - return "", err + return "", "", err } - return vm.Name, nil + + var cluster string + if vm.ResourcePool != nil { + // Extract the Cluster Name if VM belongs to a ResourcePool + var rp mo.ResourcePool + err = s.Properties(ctx, *vm.ResourcePool, []string{"parent"}, &rp) + if err == nil { + var ccr mo.ClusterComputeResource + err = s.Properties(ctx, *rp.Parent, []string{"name"}, &ccr) + if err == nil { + cluster = ccr.Name + } else { + glog.Warningf("VM %s, does not belong to a vSphere Cluster, will not have FailureDomain label", vm.Name) + } + } else { + glog.Warningf("VM %s, does not belong to a vSphere Cluster, will not have FailureDomain label", vm.Name) + } + } + return vm.Name, cluster, nil } func newVSphere(cfg VSphereConfig) (*VSphere, error) { - id, err := readInstanceID(&cfg) + id, cluster, err := readInstance(&cfg) if err != nil { return nil, err } @@ -205,6 +225,7 @@ func newVSphere(cfg VSphereConfig) (*VSphere, error) { vs := VSphere{ cfg: &cfg, localInstanceID: id, + clusterName: cluster, } return &vs, nil } @@ -498,9 +519,14 @@ func (vs *VSphere) Zones() (cloudprovider.Zones, bool) { } func (vs *VSphere) GetZone() (cloudprovider.Zone, error) { - glog.V(4).Infof("Current zone is %v", vs.cfg.Global.Datacenter) + glog.V(4).Infof("Current datacenter is %v, cluster is %v", vs.cfg.Global.Datacenter, vs.clusterName) - return cloudprovider.Zone{Region: vs.cfg.Global.Datacenter}, nil + // The clusterName is determined from the VirtualMachine ManagedObjectReference during init + // If the VM is not created within a Cluster, this will return empty-string + return cloudprovider.Zone{ + Region: vs.cfg.Global.Datacenter, + FailureDomain: vs.clusterName, + }, nil } // Routes returns a false since the interface is not supported for vSphere. diff --git a/pkg/cloudprovider/providers/vsphere/vsphere_test.go b/pkg/cloudprovider/providers/vsphere/vsphere_test.go index 217bf24907f..02d808faf37 100644 --- a/pkg/cloudprovider/providers/vsphere/vsphere_test.go +++ b/pkg/cloudprovider/providers/vsphere/vsphere_test.go @@ -126,10 +126,12 @@ func TestVSphereLogin(t *testing.T) { func TestZones(t *testing.T) { cfg := VSphereConfig{} cfg.Global.Datacenter = "myDatacenter" + failureZone := "myCluster" // Create vSphere configuration object vs := VSphere{ - cfg: &cfg, + cfg: &cfg, + clusterName: failureZone, } z, ok := vs.Zones() @@ -145,6 +147,10 @@ func TestZones(t *testing.T) { if zone.Region != vs.cfg.Global.Datacenter { t.Fatalf("GetZone() returned wrong region (%s)", zone.Region) } + + if zone.FailureDomain != failureZone { + t.Fatalf("GetZone() returned wrong Failure Zone (%s)", zone.FailureDomain) + } } func TestInstances(t *testing.T) {