in vsphere/vsphere.go [1847:1978]
func (vs *VSphere) GetZoneToHosts(ctx context.Context, vsi *VSphereInstance) (map[cloudprovider.Zone][]vmwaretypes.ManagedObjectReference, error) {
// Approach is to find tags with the category of 'vs.cfg.Labels.Zone'
zoneToHosts := make(map[cloudprovider.Zone][]vmwaretypes.ManagedObjectReference)
getHostsInTagCategory := func(ctx context.Context, tagCategoryName string) (map[vmwaretypes.ManagedObjectReference]string, error) {
hostToTag := make(map[vmwaretypes.ManagedObjectReference]string)
err := withTagsClient(ctx, vsi.conn, func(c *rest.Client) error {
// Look whether the zone/region tag is defined in VC
tagManager := tags.NewManager(c)
tagsForCat, err := tagManager.GetTagsForCategory(ctx, tagCategoryName)
if err != nil {
klog.V(4).Infof("No tags with category %s exists in VC. So ignoring.", tagCategoryName)
// return a special error so that tag unavailability can be ignored
return ErrNoZoneTagInVC
}
klog.V(4).Infof("List of tags under category %s: %v", tagCategoryName, tagsForCat)
// Each such tag is a different 'zone' marked in vCenter.
// Query for objects associated with each tag. Consider Host, Cluster and Datacenter kind of objects.
tagToObjects := make(map[string][]mo.Reference)
for _, tag := range tagsForCat {
klog.V(4).Infof("Getting objects associated with tag %s", tag.Name)
objects, err := tagManager.ListAttachedObjects(ctx, tag.Name)
if err != nil {
klog.Errorf("Error fetching objects associated with zone tag %s: %+v", tag.Name, err)
return err
}
tagToObjects[tag.Name] = objects
}
klog.V(4).Infof("Map of tag to objects: %v", tagToObjects)
// Infer zone for hosts within Datacenter, hosts within clusters and hosts - in this order of increasing priority
// The below nested for-loops goes over all the objects in tagToObjects three times over.
for _, moType := range []string{vclib.DatacenterType, vclib.ClusterComputeResourceType, vclib.HostSystemType} {
for tagName, objects := range tagToObjects {
for _, obj := range objects {
if obj.Reference().Type == moType {
klog.V(4).Infof("Found zone tag %s associated with %s of type %T: %s", tagName, obj, obj, obj.Reference().Value)
switch moType {
case "Datacenter":
// mark that all hosts in this datacenter has tag applied
dcObjRef := object.NewReference(vsi.conn.Client, obj.Reference())
klog.V(4).Infof("Converted mo obj %v to govmomi object ref %v", obj, dcObjRef)
dcObj, ok := dcObjRef.(*object.Datacenter)
if !ok {
errMsg := fmt.Sprintf("Not able to convert object to Datacenter %v", obj)
klog.Errorf(errMsg)
return errors.New(errMsg)
}
klog.V(4).Infof("Converted to object Datacenter %v", dcObj)
dc := vclib.Datacenter{Datacenter: dcObj}
hosts, err := dc.GetAllHosts(ctx)
if err != nil {
klog.Errorf("Could not get hosts from datacenter %v: %+v", dc, err)
return err
}
for _, host := range hosts {
hostToTag[host] = tagName
}
case "ClusterComputeResource":
// mark that all hosts in this cluster has tag applied
clusterObjRef := object.NewReference(vsi.conn.Client, obj.Reference())
clusterObj, ok := clusterObjRef.(*object.ClusterComputeResource)
if !ok {
errMsg := fmt.Sprintf("Not able to convert object ClusterComputeResource %v", obj)
klog.Errorf(errMsg)
return errors.New(errMsg)
}
hostSystemList, err := clusterObj.Hosts(ctx)
if err != nil {
klog.Errorf("Not able to get hosts in cluster %v: %+v", clusterObj, err)
return err
}
for _, host := range hostSystemList {
hostToTag[host.Reference()] = tagName
}
case "HostSystem":
// mark that this host has tag applied
hostToTag[obj.Reference()] = tagName
}
}
}
}
}
return nil // no error
})
if err != nil {
klog.Errorf("Error processing tag category %s: %+v", tagCategoryName, err)
return nil, err
}
klog.V(6).Infof("Computed hostToTag: %v", hostToTag)
return hostToTag, nil
}
hostToZone, err := getHostsInTagCategory(ctx, vs.cfg.Labels.Zone)
if err != nil {
if err == ErrNoZoneTagInVC {
return zoneToHosts, nil
}
klog.Errorf("Get hosts in tag category %s failed: %+v", vs.cfg.Labels.Zone, err)
return nil, err
}
hostToRegion, err := getHostsInTagCategory(ctx, vs.cfg.Labels.Region)
if err != nil {
if err == ErrNoZoneTagInVC {
return zoneToHosts, nil
}
klog.Errorf("Get hosts in tag category %s failed: %+v", vs.cfg.Labels.Region, err)
return nil, err
}
// populate zoneToHosts based on hostToZone and hostToRegion
klog.V(6).Infof("hostToZone: %v", hostToZone)
klog.V(6).Infof("hostToRegion: %v", hostToRegion)
for host, zone := range hostToZone {
region, regionExists := hostToRegion[host]
if !regionExists {
klog.Errorf("Host %s has a zone, but no region. So ignoring.", host)
continue
}
cpZone := cloudprovider.Zone{FailureDomain: zone, Region: region}
hosts, exists := zoneToHosts[cpZone]
if !exists {
hosts = make([]vmwaretypes.ManagedObjectReference, 0)
}
zoneToHosts[cpZone] = append(hosts, host)
}
klog.V(4).Infof("Final zoneToHosts: %v", zoneToHosts)
return zoneToHosts, nil
}