func()

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
}