From ec732d8aab816334c93db79168e42e710ea8b147 Mon Sep 17 00:00:00 2001 From: Doug MacEachern Date: Thu, 23 Aug 2018 14:47:58 -0700 Subject: [PATCH] vsphere: support zone tags at any level in the hierarchy Rather than just looking for zone tags at the VM's Host level, traverse up the hierarchy. This allows zone tags to be attached at host level, along with cluster, datacenter, root folder and any inventory folders in between. Issue #64021 --- .../providers/vsphere/vsphere.go | 63 ++++++++++++------- .../providers/vsphere/vsphere_test.go | 4 +- 2 files changed, 43 insertions(+), 24 deletions(-) diff --git a/pkg/cloudprovider/providers/vsphere/vsphere.go b/pkg/cloudprovider/providers/vsphere/vsphere.go index 1877cc11e0a..b6a43504a9f 100644 --- a/pkg/cloudprovider/providers/vsphere/vsphere.go +++ b/pkg/cloudprovider/providers/vsphere/vsphere.go @@ -36,6 +36,7 @@ import ( "github.com/golang/glog" "github.com/vmware/govmomi/vapi/rest" "github.com/vmware/govmomi/vapi/tags" + "github.com/vmware/govmomi/vim25/mo" "k8s.io/api/core/v1" k8stypes "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/informers" @@ -1352,31 +1353,51 @@ func (vs *VSphere) GetZone(ctx context.Context) (cloudprovider.Zone, error) { glog.Errorf("Cannot find VM runtime host. Get zone for node %s error", nodeName) return cloudprovider.Zone{}, err } - client := vsi.conn - err = withTagsClient(ctx, client, func(c *rest.Client) error { + + pc := vsi.conn.Client.ServiceContent.PropertyCollector + err = withTagsClient(ctx, vsi.conn, func(c *rest.Client) error { client := tags.NewManager(c) - tags, err := client.ListAttachedTags(ctx, vmHost) + // example result: ["Folder", "Datacenter", "Cluster", "Host"] + objects, err := mo.Ancestors(ctx, vsi.conn.Client, pc, *vmHost) if err != nil { - glog.Errorf("Cannot list attached tags. Get zone for node %s error", nodeName) return err } - for _, value := range tags { - tag, err := client.GetTag(ctx, value) - if err != nil { - glog.Errorf("Get tag %s error", value) - return err - } - category, err := client.GetCategory(ctx, tag.CategoryID) - if err != nil { - glog.Errorf("Get category %s error", value) - return err - } - switch { - case category.Name == vs.cfg.Labels.Zone: - zone.FailureDomain = tag.Name - case category.Name == vs.cfg.Labels.Region: - zone.Region = tag.Name + // search the hierarchy, example order: ["Host", "Cluster", "Datacenter", "Folder"] + for i := range objects { + obj := objects[len(objects)-1-i] + tags, err := client.ListAttachedTags(ctx, obj) + if err != nil { + glog.Errorf("Cannot list attached tags. Get zone for node %s: %s", nodeName, err) + return err + } + for _, value := range tags { + tag, err := client.GetTag(ctx, value) + if err != nil { + glog.Errorf("Get tag %s: %s", value, err) + return err + } + category, err := client.GetCategory(ctx, tag.CategoryID) + if err != nil { + glog.Errorf("Get category %s error", value) + return err + } + + found := func() { + glog.Errorf("Found %q tag (%s) for %s attached to %s", category.Name, tag.Name, vs.vmUUID, obj.Reference()) + } + switch { + case category.Name == vs.cfg.Labels.Zone: + zone.FailureDomain = tag.Name + found() + case category.Name == vs.cfg.Labels.Region: + zone.Region = tag.Name + found() + } + + if zone.FailureDomain != "" && zone.Region != "" { + return nil + } } } @@ -1394,7 +1415,7 @@ func (vs *VSphere) GetZone(ctx context.Context) (cloudprovider.Zone, error) { return nil }) if err != nil { - glog.Errorf("Get zone for node %s error", nodeName) + glog.Errorf("Get zone for node %s: %s", nodeName, err) return cloudprovider.Zone{}, err } return zone, nil diff --git a/pkg/cloudprovider/providers/vsphere/vsphere_test.go b/pkg/cloudprovider/providers/vsphere/vsphere_test.go index ad6b63b5579..56a29e28022 100644 --- a/pkg/cloudprovider/providers/vsphere/vsphere_test.go +++ b/pkg/cloudprovider/providers/vsphere/vsphere_test.go @@ -451,7 +451,7 @@ func TestZones(t *testing.T) { t.Fatal(err) } }}, - {"dc region, cluster zone", true, func() { + {"dc region, cluster zone", false, func() { var h mo.HostSystem if err = pc.RetrieveOne(ctx, host.Reference(), []string{"parent"}, &h); err != nil { t.Fatal(err) @@ -464,8 +464,6 @@ func TestZones(t *testing.T) { if err = m.AttachTag(ctx, zoneID, h.Parent); err != nil { t.Fatal(err) } - - // TODO: this should pass with Datacenter tagged as the region and Cluster tagged as the zone }}, }