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
This commit is contained in:
Doug MacEachern 2018-08-23 14:47:58 -07:00
parent 83030032ad
commit ec732d8aab
2 changed files with 43 additions and 24 deletions

View File

@ -36,6 +36,7 @@ import (
"github.com/golang/glog" "github.com/golang/glog"
"github.com/vmware/govmomi/vapi/rest" "github.com/vmware/govmomi/vapi/rest"
"github.com/vmware/govmomi/vapi/tags" "github.com/vmware/govmomi/vapi/tags"
"github.com/vmware/govmomi/vim25/mo"
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
k8stypes "k8s.io/apimachinery/pkg/types" k8stypes "k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/informers" "k8s.io/client-go/informers"
@ -1352,18 +1353,28 @@ func (vs *VSphere) GetZone(ctx context.Context) (cloudprovider.Zone, error) {
glog.Errorf("Cannot find VM runtime host. Get zone for node %s error", nodeName) glog.Errorf("Cannot find VM runtime host. Get zone for node %s error", nodeName)
return cloudprovider.Zone{}, err 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) 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 { if err != nil {
glog.Errorf("Cannot list attached tags. Get zone for node %s error", nodeName) return err
}
// 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 return err
} }
for _, value := range tags { for _, value := range tags {
tag, err := client.GetTag(ctx, value) tag, err := client.GetTag(ctx, value)
if err != nil { if err != nil {
glog.Errorf("Get tag %s error", value) glog.Errorf("Get tag %s: %s", value, err)
return err return err
} }
category, err := client.GetCategory(ctx, tag.CategoryID) category, err := client.GetCategory(ctx, tag.CategoryID)
@ -1372,11 +1383,21 @@ func (vs *VSphere) GetZone(ctx context.Context) (cloudprovider.Zone, error) {
return err return err
} }
found := func() {
glog.Errorf("Found %q tag (%s) for %s attached to %s", category.Name, tag.Name, vs.vmUUID, obj.Reference())
}
switch { switch {
case category.Name == vs.cfg.Labels.Zone: case category.Name == vs.cfg.Labels.Zone:
zone.FailureDomain = tag.Name zone.FailureDomain = tag.Name
found()
case category.Name == vs.cfg.Labels.Region: case category.Name == vs.cfg.Labels.Region:
zone.Region = tag.Name 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 return nil
}) })
if err != 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 cloudprovider.Zone{}, err
} }
return zone, nil return zone, nil

View File

@ -451,7 +451,7 @@ func TestZones(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
}}, }},
{"dc region, cluster zone", true, func() { {"dc region, cluster zone", false, func() {
var h mo.HostSystem var h mo.HostSystem
if err = pc.RetrieveOne(ctx, host.Reference(), []string{"parent"}, &h); err != nil { if err = pc.RetrieveOne(ctx, host.Reference(), []string{"parent"}, &h); err != nil {
t.Fatal(err) t.Fatal(err)
@ -464,8 +464,6 @@ func TestZones(t *testing.T) {
if err = m.AttachTag(ctx, zoneID, h.Parent); err != nil { if err = m.AttachTag(ctx, zoneID, h.Parent); err != nil {
t.Fatal(err) t.Fatal(err)
} }
// TODO: this should pass with Datacenter tagged as the region and Cluster tagged as the zone
}}, }},
} }