yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/esxi/datacenter.go (about)

     1  // Copyright 2019 Yunion
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package esxi
    16  
    17  import (
    18  	"regexp"
    19  	"strings"
    20  
    21  	"github.com/vmware/govmomi/object"
    22  	"github.com/vmware/govmomi/property"
    23  	"github.com/vmware/govmomi/view"
    24  	"github.com/vmware/govmomi/vim25/mo"
    25  	"github.com/vmware/govmomi/vim25/types"
    26  
    27  	"yunion.io/x/pkg/errors"
    28  	"yunion.io/x/pkg/util/sets"
    29  
    30  	api "yunion.io/x/cloudmux/pkg/apis/compute"
    31  	"yunion.io/x/cloudmux/pkg/cloudprovider"
    32  )
    33  
    34  var DATACENTER_PROPS = []string{"name", "parent", "datastore", "network"}
    35  
    36  type SDatacenter struct {
    37  	SManagedObject
    38  
    39  	ihosts       []cloudprovider.ICloudHost
    40  	istorages    []cloudprovider.ICloudStorage
    41  	inetworks    []IVMNetwork
    42  	iresoucePool []cloudprovider.ICloudProject
    43  	clusters     []*SCluster
    44  
    45  	Name string
    46  }
    47  
    48  func newDatacenter(manager *SESXiClient, dc *mo.Datacenter) *SDatacenter {
    49  	obj := SDatacenter{SManagedObject: newManagedObject(manager, dc, nil)}
    50  	obj.datacenter = &obj
    51  	return &obj
    52  }
    53  
    54  func (dc *SDatacenter) isDefaultDc() bool {
    55  	if dc.object == &defaultDc {
    56  		return true
    57  	}
    58  	return false
    59  }
    60  
    61  func (dc *SDatacenter) getDatacenter() *mo.Datacenter {
    62  	return dc.object.(*mo.Datacenter)
    63  }
    64  
    65  func (dc *SDatacenter) getObjectDatacenter() *object.Datacenter {
    66  	if dc.isDefaultDc() {
    67  		return nil
    68  	}
    69  	return object.NewDatacenter(dc.manager.client.Client, dc.object.Reference())
    70  }
    71  
    72  func (dc *SDatacenter) scanResourcePool() error {
    73  	if dc.iresoucePool == nil {
    74  		pools, err := dc.listResourcePools()
    75  		if err != nil {
    76  			return errors.Wrap(err, "listResourcePools")
    77  		}
    78  		dc.iresoucePool = []cloudprovider.ICloudProject{}
    79  		for i := 0; i < len(pools); i++ {
    80  			p := NewResourcePool(dc.manager, &pools[i], dc)
    81  			dc.iresoucePool = append(dc.iresoucePool, p)
    82  		}
    83  	}
    84  	return nil
    85  }
    86  
    87  func (dc *SDatacenter) scanHosts() error {
    88  	if dc.ihosts == nil {
    89  		var hosts []mo.HostSystem
    90  		if dc.isDefaultDc() {
    91  			err := dc.manager.scanAllMObjects(HOST_SYSTEM_PROPS, &hosts)
    92  			if err != nil {
    93  				return errors.Wrap(err, "dc.manager.scanAllMObjects")
    94  			}
    95  		} else {
    96  			err := dc.manager.scanMObjects(dc.object.Entity().Self, HOST_SYSTEM_PROPS, &hosts)
    97  			if err != nil {
    98  				return errors.Wrap(err, "dc.manager.scanMObjects")
    99  			}
   100  		}
   101  		dc.ihosts = make([]cloudprovider.ICloudHost, 0)
   102  		for i := 0; i < len(hosts); i += 1 {
   103  			h := NewHost(dc.manager, &hosts[i], dc)
   104  			if h != nil {
   105  				dc.ihosts = append(dc.ihosts, h)
   106  			}
   107  		}
   108  	}
   109  	return nil
   110  }
   111  
   112  func (dc *SDatacenter) GetResourcePools() ([]cloudprovider.ICloudProject, error) {
   113  	err := dc.scanResourcePool()
   114  	if err != nil {
   115  		return nil, errors.Wrap(err, "dc.scanResourcePool")
   116  	}
   117  	return dc.iresoucePool, nil
   118  }
   119  
   120  func (dc *SDatacenter) listResourcePools() ([]mo.ResourcePool, error) {
   121  	var pools, result []mo.ResourcePool
   122  	err := dc.manager.scanMObjects(dc.object.Entity().Self, RESOURCEPOOL_PROPS, &pools)
   123  	if err != nil {
   124  		return nil, errors.Wrap(err, "scanMObjects")
   125  	}
   126  	for i := range pools {
   127  		if pools[i].Parent.Type == "ClusterComputeResource" {
   128  			continue
   129  		}
   130  		result = append(result, pools[i])
   131  	}
   132  	return result, nil
   133  }
   134  
   135  func (dc *SDatacenter) ListClusters() ([]*SCluster, error) {
   136  	return dc.listClusters()
   137  }
   138  
   139  func (dc *SDatacenter) GetCluster(cluster string) (*SCluster, error) {
   140  	clusters, err := dc.ListClusters()
   141  	if err != nil {
   142  		return nil, errors.Wrap(err, "ListClusters")
   143  	}
   144  	for i := range clusters {
   145  		if clusters[i].GetName() == cluster {
   146  			return clusters[i], nil
   147  		}
   148  
   149  	}
   150  	return nil, cloudprovider.ErrNotFound
   151  }
   152  
   153  func (dc *SDatacenter) listClusters() ([]*SCluster, error) {
   154  	if dc.clusters != nil {
   155  		return dc.clusters, nil
   156  	}
   157  	clusters := []mo.ClusterComputeResource{}
   158  	err := dc.manager.scanMObjects(dc.object.Entity().Self, RESOURCEPOOL_PROPS, &clusters)
   159  	if err != nil {
   160  		return nil, errors.Wrap(err, "scanMObjects")
   161  	}
   162  	ret := []*SCluster{}
   163  	for i := range clusters {
   164  		c := NewCluster(dc.manager, &clusters[i], dc)
   165  		ret = append(ret, c)
   166  	}
   167  	return ret, nil
   168  }
   169  
   170  func (dc *SDatacenter) GetIHosts() ([]cloudprovider.ICloudHost, error) {
   171  	err := dc.scanHosts()
   172  	if err != nil {
   173  		return nil, errors.Wrap(err, "dc.scanHosts")
   174  	}
   175  	return dc.ihosts, nil
   176  }
   177  
   178  func (dc *SDatacenter) scanDatastores() error {
   179  	if dc.istorages == nil {
   180  		var stores []mo.Datastore
   181  		if dc.isDefaultDc() {
   182  			err := dc.manager.scanAllMObjects(DATASTORE_PROPS, &stores)
   183  			if err != nil {
   184  				return errors.Wrap(err, "dc.manager.scanAllMObjects")
   185  			}
   186  		} else {
   187  			dsList := dc.getDatacenter().Datastore
   188  			if dsList != nil {
   189  				err := dc.manager.references2Objects(dsList, DATASTORE_PROPS, &stores)
   190  				if err != nil {
   191  					return errors.Wrap(err, "dc.manager.references2Objects")
   192  				}
   193  			}
   194  		}
   195  		dc.istorages = make([]cloudprovider.ICloudStorage, 0)
   196  		for i := 0; i < len(stores); i += 1 {
   197  			ds := NewDatastore(dc.manager, &stores[i], dc)
   198  			dsId := ds.GetGlobalId()
   199  			if len(dsId) > 0 {
   200  				dc.istorages = append(dc.istorages, ds)
   201  			}
   202  		}
   203  	}
   204  	return nil
   205  }
   206  
   207  func (dc *SDatacenter) GetIStorages() ([]cloudprovider.ICloudStorage, error) {
   208  	err := dc.scanDatastores()
   209  	if err != nil {
   210  		return nil, errors.Wrap(err, "dc.scanDatastores")
   211  	}
   212  	return dc.istorages, nil
   213  }
   214  
   215  func (dc *SDatacenter) GetIHostByMoId(idstr string) (cloudprovider.ICloudHost, error) {
   216  	ihosts, err := dc.GetIHosts()
   217  	if err != nil {
   218  		return nil, errors.Wrap(err, "dc.GetIHosts")
   219  	}
   220  	for i := 0; i < len(ihosts); i += 1 {
   221  		if ihosts[i].GetId() == idstr {
   222  			return ihosts[i], nil
   223  		}
   224  	}
   225  	return nil, cloudprovider.ErrNotFound
   226  }
   227  
   228  func (dc *SDatacenter) GetIStorageByMoId(idstr string) (cloudprovider.ICloudStorage, error) {
   229  	istorages, err := dc.GetIStorages()
   230  	if err != nil {
   231  		return nil, errors.Wrap(err, "dc.GetIStorages")
   232  	}
   233  	for i := 0; i < len(istorages); i += 1 {
   234  		if istorages[i].GetId() == idstr {
   235  			return istorages[i], nil
   236  		}
   237  	}
   238  	return nil, cloudprovider.ErrNotFound
   239  }
   240  
   241  func (dc *SDatacenter) getDcObj() *object.Datacenter {
   242  	if dc.isDefaultDc() {
   243  		return nil
   244  	}
   245  	return object.NewDatacenter(dc.manager.client.Client, dc.object.Reference())
   246  }
   247  
   248  func (dc *SDatacenter) fetchMoVms(filter property.Filter, props []string) ([]mo.VirtualMachine, error) {
   249  	odc := dc.getObjectDatacenter()
   250  	root := odc.Reference()
   251  	var movms []mo.VirtualMachine
   252  	err := dc.manager.scanMObjectsWithFilter(root, props, &movms, filter)
   253  	if err != nil {
   254  		return nil, errors.Wrap(err, "scanMObjectsWithFilter")
   255  	}
   256  	return movms, nil
   257  }
   258  
   259  func (dc *SDatacenter) moVms2Vm(movms []mo.VirtualMachine, all *bool) ([]*SVirtualMachine, error) {
   260  	// avoid applying new memory and copying
   261  	vms := make([]*SVirtualMachine, 0, len(movms))
   262  	for i := range movms {
   263  		if (all != nil && *all) || !strings.HasPrefix(movms[i].Name, api.ESXI_IMAGE_CACHE_TMP_PREFIX) {
   264  			vm := NewVirtualMachine(dc.manager, &movms[i], dc)
   265  			// must
   266  			if vm == nil {
   267  				continue
   268  			}
   269  			vms = append(vms, vm)
   270  		}
   271  	}
   272  	return vms, nil
   273  }
   274  
   275  func (dc *SDatacenter) fetchFakeTemplateVMs(movms []mo.VirtualMachine, regex string) ([]*SVirtualMachine, error) {
   276  	var (
   277  		tNameRegex *regexp.Regexp
   278  		err        error
   279  	)
   280  	if len(regex) == 0 {
   281  		tNameRegex = tempalteNameRegex
   282  	} else {
   283  		tNameRegex, err = regexp.Compile(regex)
   284  		if err != nil {
   285  			return nil, errors.Wrap(err, "generate regexp")
   286  		}
   287  	}
   288  	objs := make([]types.ManagedObjectReference, 0)
   289  	for i := range movms {
   290  		name := movms[i].Name
   291  		if tNameRegex != nil && tNameRegex.MatchString(name) {
   292  			objs = append(objs, movms[i].Reference())
   293  		}
   294  	}
   295  	if len(objs) == 0 {
   296  		return nil, nil
   297  	}
   298  	return dc.fetchVms(objs, false)
   299  }
   300  
   301  func (dc *SDatacenter) fetchVmsFromCache(vmRefs []types.ManagedObjectReference) ([]*SVirtualMachine, error) {
   302  	vmRefSet := sets.NewString()
   303  	for i := range vmRefs {
   304  		vmRefSet.Insert(vmRefs[i].String())
   305  	}
   306  	ihosts, err := dc.GetIHosts()
   307  	if err != nil {
   308  		return nil, err
   309  	}
   310  	ret := make([]*SVirtualMachine, 0, len(vmRefs))
   311  	for i := range ihosts {
   312  		ivms, err := ihosts[i].GetIVMs()
   313  		if err != nil {
   314  			return nil, err
   315  		}
   316  		for i := range ivms {
   317  			vm := ivms[i].(*SVirtualMachine)
   318  			s := vm.getVirtualMachine().Self.String()
   319  			if vmRefSet.Has(s) {
   320  				ret = append(ret, vm)
   321  				vmRefSet.Delete(s)
   322  			}
   323  		}
   324  	}
   325  	return ret, nil
   326  }
   327  
   328  func (dc *SDatacenter) fetchVms(vmRefs []types.ManagedObjectReference, all bool) ([]*SVirtualMachine, error) {
   329  	var movms []mo.VirtualMachine
   330  	if vmRefs != nil {
   331  		err := dc.manager.references2Objects(vmRefs, VIRTUAL_MACHINE_PROPS, &movms)
   332  		if err != nil {
   333  			return nil, errors.Wrap(err, "dc.manager.references2Objects")
   334  		}
   335  	}
   336  	return dc.moVms2Vm(movms, &all)
   337  }
   338  
   339  func (dc *SDatacenter) fetchHosts_(vmRefs []types.ManagedObjectReference, all bool) ([]*SHost, error) {
   340  	var movms []mo.HostSystem
   341  	if vmRefs != nil {
   342  		err := dc.manager.references2Objects(vmRefs, VIRTUAL_MACHINE_PROPS, &movms)
   343  		if err != nil {
   344  			return nil, errors.Wrap(err, "dc.manager.references2Objects")
   345  		}
   346  	}
   347  
   348  	// avoid applying new memory and copying
   349  	vms := make([]*SHost, 0, len(movms))
   350  	for i := range movms {
   351  		if all || !strings.HasPrefix(movms[i].Entity().Name, api.ESXI_IMAGE_CACHE_TMP_PREFIX) {
   352  			vms = append(vms, NewHost(dc.manager, &movms[i], dc))
   353  		}
   354  	}
   355  	return vms, nil
   356  }
   357  
   358  func (dc *SDatacenter) FetchVMs() ([]*SVirtualMachine, error) {
   359  	return dc.fetchVMsWithFilter(property.Filter{})
   360  }
   361  
   362  func (dc *SDatacenter) FetchNoTemplateVMs() ([]*SVirtualMachine, error) {
   363  	filter := property.Filter{}
   364  	filter["config.template"] = false
   365  	return dc.fetchVMsWithFilter(filter)
   366  }
   367  
   368  func (dc *SDatacenter) FetchFakeTempateVMs(regex string) ([]*SVirtualMachine, error) {
   369  	filter := property.Filter{}
   370  	filter["summary.runtime.powerState"] = types.VirtualMachinePowerStatePoweredOff
   371  	movms, err := dc.fetchMoVms(filter, []string{"name"})
   372  	if err != nil {
   373  		return nil, errors.Wrap(err, "unable to fetch mo.VirtualMachines")
   374  	}
   375  	return dc.fetchFakeTemplateVMs(movms, regex)
   376  }
   377  
   378  func (dc *SDatacenter) fetchVMsWithFilter(filter property.Filter) ([]*SVirtualMachine, error) {
   379  	movms, err := dc.fetchMoVms(filter, VIRTUAL_MACHINE_PROPS)
   380  	if err != nil {
   381  		return nil, errors.Wrap(err, "unable to fetch mo.VirtualMachines")
   382  	}
   383  	ret, err := dc.moVms2Vm(movms, nil)
   384  	if err != nil {
   385  		return nil, errors.Wrap(err, "unable to convert mo.VirtualMachine to VirtualMachine")
   386  	}
   387  	return ret, err
   388  }
   389  
   390  func (dc *SDatacenter) FetchNoTemplateVMEntityReferens() ([]types.ManagedObjectReference, error) {
   391  	filter := property.Filter{}
   392  	filter["config.template"] = false
   393  	odc := dc.getObjectDatacenter()
   394  	root := odc.Reference()
   395  	m := view.NewManager(dc.manager.client.Client)
   396  	v, err := m.CreateContainerView(dc.manager.context, root, []string{"VirtualMachine"}, true)
   397  	if err != nil {
   398  		return nil, err
   399  	}
   400  	defer func() {
   401  		_ = v.Destroy(dc.manager.context)
   402  	}()
   403  	objs, err := v.Find(dc.manager.context, []string{"VirtualMachine"}, filter)
   404  	if err != nil {
   405  		return nil, err
   406  	}
   407  	return objs, nil
   408  }
   409  
   410  func (dc *SDatacenter) FetchNoTemplateHostEntityReferens() ([]types.ManagedObjectReference, error) {
   411  	filter := property.Filter{}
   412  	odc := dc.getObjectDatacenter()
   413  	root := odc.Reference()
   414  	m := view.NewManager(dc.manager.client.Client)
   415  	v, err := m.CreateContainerView(dc.manager.context, root, []string{"HostSystem"}, true)
   416  	if err != nil {
   417  		return nil, err
   418  	}
   419  	defer func() {
   420  		_ = v.Destroy(dc.manager.context)
   421  	}()
   422  	objs, err := v.Find(dc.manager.context, []string{"HostSystem"}, filter)
   423  	if err != nil {
   424  		return nil, err
   425  	}
   426  	return objs, nil
   427  }
   428  
   429  func (dc *SDatacenter) fetchHosts(filter property.Filter) ([]*SHost, error) {
   430  	odc := dc.getObjectDatacenter()
   431  	root := odc.Reference()
   432  	m := view.NewManager(dc.manager.client.Client)
   433  	v, err := m.CreateContainerView(dc.manager.context, root, []string{"HostSystem"}, true)
   434  	if err != nil {
   435  		return nil, err
   436  	}
   437  	defer func() {
   438  		_ = v.Destroy(dc.manager.context)
   439  	}()
   440  	objs, err := v.Find(dc.manager.context, []string{"HostSystem"}, filter)
   441  	if err != nil {
   442  		return nil, err
   443  	}
   444  	hosts, err := dc.fetchHosts_(objs, false)
   445  	return hosts, err
   446  }
   447  
   448  func (dc *SDatacenter) FetchTemplateVMs() ([]*SVirtualMachine, error) {
   449  	filter := property.Filter{}
   450  	filter["config.template"] = true
   451  	return dc.fetchVMsWithFilter(filter)
   452  }
   453  
   454  func (dc *SDatacenter) FetchTemplateVMById(id string) (*SVirtualMachine, error) {
   455  	filter := property.Filter{}
   456  	filter["config.template"] = true
   457  	filter["summary.config.uuid"] = id
   458  	vms, err := dc.fetchVMsWithFilter(filter)
   459  	if err != nil {
   460  		return nil, err
   461  	}
   462  	if len(vms) == 0 {
   463  		return nil, errors.ErrNotFound
   464  	}
   465  	return vms[0], nil
   466  }
   467  
   468  func (dc *SDatacenter) FetchVMById(id string) (*SVirtualMachine, error) {
   469  	filter := property.Filter{}
   470  	filter["summary.config.uuid"] = id
   471  	vms, err := dc.fetchVMsWithFilter(filter)
   472  	if err != nil {
   473  		return nil, err
   474  	}
   475  	if len(vms) == 0 {
   476  		return nil, errors.ErrNotFound
   477  	}
   478  	return vms[0], nil
   479  }
   480  
   481  func (dc *SDatacenter) fetchDatastores(datastoreRefs []types.ManagedObjectReference) ([]cloudprovider.ICloudStorage, error) {
   482  	var dss []mo.Datastore
   483  	if datastoreRefs != nil {
   484  		err := dc.manager.references2Objects(datastoreRefs, DATASTORE_PROPS, &dss)
   485  		if err != nil {
   486  			return nil, errors.Wrap(err, "dc.manager.references2Objects")
   487  		}
   488  	}
   489  
   490  	retDatastores := make([]cloudprovider.ICloudStorage, 0, len(dss))
   491  	for i := range dss {
   492  		retDatastores = append(retDatastores, NewDatastore(dc.manager, &dss[i], dc))
   493  	}
   494  	return retDatastores, nil
   495  }
   496  
   497  func (dc *SDatacenter) scanNetworks() error {
   498  	if dc.inetworks == nil {
   499  		if dc.isDefaultDc() {
   500  			return dc.scanDefaultNetworks()
   501  		} else {
   502  			return dc.scanDcNetworks()
   503  		}
   504  	}
   505  	return nil
   506  }
   507  
   508  func (dc *SDatacenter) scanDefaultNetworks() error {
   509  	dc.inetworks = make([]IVMNetwork, 0)
   510  	err := dc.scanAllDvPortgroups()
   511  	if err != nil {
   512  		return errors.Wrap(err, "dc.scanAllDvPortgroups")
   513  	}
   514  	err = dc.scanAllNetworks()
   515  	if err != nil {
   516  		return errors.Wrap(err, "dc.scanAllNetworks")
   517  	}
   518  	return nil
   519  }
   520  
   521  func (dc *SDatacenter) scanAllDvPortgroups() error {
   522  	var dvports []mo.DistributedVirtualPortgroup
   523  
   524  	err := dc.manager.scanAllMObjects(DVPORTGROUP_PROPS, &dvports)
   525  	if err != nil {
   526  		return errors.Wrap(err, "dc.manager.scanAllMObjects mo.DistributedVirtualPortgroup")
   527  	}
   528  	for i := range dvports {
   529  		net := NewDistributedVirtualPortgroup(dc.manager, &dvports[i], dc)
   530  		dc.inetworks = append(dc.inetworks, net)
   531  	}
   532  	return nil
   533  }
   534  
   535  func (dc *SDatacenter) scanAllNetworks() error {
   536  	var nets []mo.Network
   537  
   538  	err := dc.manager.scanAllMObjects(NETWORK_PROPS, &nets)
   539  	if err != nil {
   540  		return errors.Wrap(err, "dc.manager.scanAllMObjects mo.Network")
   541  	}
   542  	for i := range nets {
   543  		net := NewNetwork(dc.manager, &nets[i], dc)
   544  		dc.inetworks = append(dc.inetworks, net)
   545  	}
   546  	return nil
   547  }
   548  
   549  func (dc *SDatacenter) scanDcNetworks() error {
   550  	dc.inetworks = make([]IVMNetwork, 0)
   551  
   552  	netMOBs := dc.getDatacenter().Network
   553  	for i := range netMOBs {
   554  		dvport := mo.DistributedVirtualPortgroup{}
   555  		err := dc.manager.reference2Object(netMOBs[i], DVPORTGROUP_PROPS, &dvport)
   556  		if err == nil {
   557  			net := NewDistributedVirtualPortgroup(dc.manager, &dvport, dc)
   558  			dc.inetworks = append(dc.inetworks, net)
   559  		} else {
   560  			net := mo.Network{}
   561  			err = dc.manager.reference2Object(netMOBs[i], NETWORK_PROPS, &net)
   562  			if err == nil {
   563  				vnet := NewNetwork(dc.manager, &net, dc)
   564  				dc.inetworks = append(dc.inetworks, vnet)
   565  			} else {
   566  				return errors.Wrap(err, "dc.manager.reference2Object")
   567  			}
   568  		}
   569  	}
   570  	return nil
   571  }
   572  
   573  func (dc *SDatacenter) GetNetworks() ([]IVMNetwork, error) {
   574  	err := dc.scanNetworks()
   575  	if err != nil {
   576  		return nil, errors.Wrap(err, "dc.scanNetworks")
   577  	}
   578  	return dc.inetworks, nil
   579  }
   580  
   581  func (dc *SDatacenter) GetTemplateVMs() ([]*SVirtualMachine, error) {
   582  	hosts, err := dc.GetIHosts()
   583  	if err != nil {
   584  		return nil, errors.Wrap(err, "SDatacenter.GetIHosts")
   585  	}
   586  	templateVms := make([]*SVirtualMachine, 5)
   587  	for _, ihost := range hosts {
   588  		host := ihost.(*SHost)
   589  		tvms, err := host.GetTemplateVMs()
   590  		if err != nil {
   591  			return nil, errors.Wrap(err, "host.GetTemplateVMs")
   592  		}
   593  		templateVms = append(templateVms, tvms...)
   594  	}
   595  	return templateVms, nil
   596  }