github.com/vmware/govmomi@v0.37.1/eam/simulator/utils.go (about)

     1  /*
     2  Copyright (c) 2021 VMware, Inc. All Rights Reserved.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package simulator
    18  
    19  import (
    20  	"errors"
    21  	"fmt"
    22  	"math/rand"
    23  	"regexp"
    24  
    25  	"github.com/vmware/govmomi/eam/types"
    26  	vimobj "github.com/vmware/govmomi/object"
    27  	"github.com/vmware/govmomi/simulator"
    28  	vimmo "github.com/vmware/govmomi/vim25/mo"
    29  	vim "github.com/vmware/govmomi/vim25/types"
    30  )
    31  
    32  var (
    33  	// fsOrHTTPRx matches a URI that is either on the local file
    34  	// system or an HTTP endpoint.
    35  	fsOrHTTPRx = regexp.MustCompile(`^(?:\.?/)|(?:http[s]?:)`)
    36  )
    37  
    38  var (
    39  	agentVmDatastoreEmptyErr     = errors.New("AgentVmDatastore is empty")
    40  	agentVmNetworkEmptyErr       = errors.New("AgentVmNetwork is empty")
    41  	foldersEmptyErr              = errors.New("Folders is empty")
    42  	scopeComputeResourceEmptyErr = errors.New("Scope.ComputeResource is empty")
    43  	poolRefNilErr                = errors.New("Unable to determine ResourcePool from ComputeResource")
    44  )
    45  
    46  func getAgentVMPlacementOptions(
    47  	ctx *simulator.Context,
    48  	reg *simulator.Registry,
    49  	r *rand.Rand, i int,
    50  	baseAgencyConfig types.BaseAgencyConfigInfo) (AgentVMPlacementOptions, error) {
    51  
    52  	var opts AgentVMPlacementOptions
    53  	agencyConfig := baseAgencyConfig.GetAgencyConfigInfo()
    54  	if l := len(agencyConfig.AgentVmDatastore); l == 0 {
    55  		return opts, agentVmDatastoreEmptyErr
    56  	} else if l == len(agencyConfig.AgentConfig) {
    57  		opts.datastore = agencyConfig.AgentVmDatastore[i]
    58  	} else {
    59  		opts.datastore = agencyConfig.AgentVmDatastore[r.Intn(l)]
    60  	}
    61  
    62  	if l := len(agencyConfig.AgentVmNetwork); l == 0 {
    63  		return opts, agentVmNetworkEmptyErr
    64  	} else if l == len(agencyConfig.AgentConfig) {
    65  		opts.network = agencyConfig.AgentVmNetwork[i]
    66  	} else {
    67  		opts.network = agencyConfig.AgentVmNetwork[r.Intn(l)]
    68  	}
    69  
    70  	if l := len(agencyConfig.Folders); l == 0 {
    71  		return opts, foldersEmptyErr
    72  	} else if l == len(agencyConfig.AgentConfig) {
    73  		opts.folder = agencyConfig.Folders[i].FolderId
    74  		opts.datacenter = agencyConfig.Folders[i].DatacenterId
    75  	} else {
    76  		j := r.Intn(l)
    77  		opts.folder = agencyConfig.Folders[j].FolderId
    78  		opts.datacenter = agencyConfig.Folders[j].DatacenterId
    79  	}
    80  
    81  	if l := len(agencyConfig.ResourcePools); l == 0 {
    82  		switch tscope := agencyConfig.Scope.(type) {
    83  		case *types.AgencyComputeResourceScope:
    84  			crRefs := tscope.ComputeResource
    85  			if l := len(crRefs); l == 0 {
    86  				return opts, scopeComputeResourceEmptyErr
    87  			} else if l == len(agencyConfig.AgentConfig) {
    88  				opts.computeResource = crRefs[i]
    89  			} else {
    90  				opts.computeResource = crRefs[r.Intn(l)]
    91  			}
    92  			poolRef, err := getPoolFromComputeResource(ctx, reg, opts.computeResource)
    93  			if err != nil {
    94  				return opts, err
    95  			}
    96  			opts.pool = *poolRef
    97  		}
    98  	} else if l == len(agencyConfig.AgentConfig) {
    99  		opts.pool = agencyConfig.ResourcePools[i].ResourcePoolId
   100  		opts.computeResource = agencyConfig.ResourcePools[i].ComputeResourceId
   101  	} else {
   102  		j := r.Intn(l)
   103  		opts.pool = agencyConfig.ResourcePools[j].ResourcePoolId
   104  		opts.computeResource = agencyConfig.ResourcePools[j].ComputeResourceId
   105  	}
   106  
   107  	hosts := getHostsFromPool(ctx, reg, opts.pool)
   108  	if l := len(hosts); l == 0 {
   109  		return opts, fmt.Errorf("HostSystems not found for %v", opts.pool)
   110  	} else if l == len(agencyConfig.AgentConfig) {
   111  		opts.host = hosts[i]
   112  	} else {
   113  		opts.host = hosts[r.Intn(l)]
   114  	}
   115  
   116  	return opts, nil
   117  }
   118  
   119  func getPoolFromComputeResource(
   120  	ctx *simulator.Context,
   121  	reg *simulator.Registry,
   122  	computeResource vim.ManagedObjectReference) (*vim.ManagedObjectReference, error) {
   123  
   124  	var poolRef *vim.ManagedObjectReference
   125  	crObj := reg.Get(computeResource)
   126  	if crObj == nil {
   127  		return nil, fmt.Errorf("%v not in registry", computeResource)
   128  	}
   129  	ctx.WithLock(crObj, func() {
   130  		switch cr := crObj.(type) {
   131  		case *vimmo.ComputeResource:
   132  			poolRef = cr.ResourcePool
   133  		case *simulator.ClusterComputeResource:
   134  			poolRef = cr.ResourcePool
   135  		default:
   136  			panic(fmt.Errorf(
   137  				"%v is not a %s or %s",
   138  				crObj,
   139  				"*mo.ComputeResource",
   140  				"*simulator.ClusterComputeResource",
   141  			))
   142  		}
   143  	})
   144  	if poolRef == nil {
   145  		return nil, poolRefNilErr
   146  	}
   147  	return poolRef, nil
   148  }
   149  
   150  // getHostsFromPool returns the host(s) for the provided compute resource.
   151  func getHostsFromPool(
   152  	ctx *simulator.Context,
   153  	reg *simulator.Registry,
   154  	poolRef vim.ManagedObjectReference) []vim.ManagedObjectReference {
   155  
   156  	pool := reg.Get(poolRef).(vimmo.Entity)
   157  	cr := getEntityComputeResource(reg, pool)
   158  
   159  	var hosts []vim.ManagedObjectReference
   160  
   161  	ctx.WithLock(cr, func() {
   162  		switch cr := cr.(type) {
   163  		case *vimmo.ComputeResource:
   164  			hosts = cr.Host
   165  		case *simulator.ClusterComputeResource:
   166  			hosts = cr.Host
   167  		}
   168  	})
   169  
   170  	return hosts
   171  }
   172  
   173  // hostsWithDatastore returns hosts that have access to the given datastore path
   174  func hostsWithDatastore( // nolint:unused nolint:deadcode
   175  	reg *simulator.Registry,
   176  	hosts []vim.ManagedObjectReference, path string) []vim.ManagedObjectReference {
   177  
   178  	attached := hosts[:0]
   179  	var p vimobj.DatastorePath
   180  	p.FromString(path)
   181  
   182  	for _, host := range hosts {
   183  		h := reg.Get(host).(*simulator.HostSystem)
   184  		if reg.FindByName(p.Datastore, h.Datastore) != nil {
   185  			attached = append(attached, host)
   186  		}
   187  	}
   188  
   189  	return attached
   190  }
   191  
   192  // getEntityComputeResource returns the ComputeResource parent for the given item.
   193  // A ResourcePool for example may have N Parents of type ResourcePool, but the top
   194  // most Parent pool is always a ComputeResource child.
   195  func getEntityComputeResource(
   196  	reg *simulator.Registry,
   197  	item vimmo.Entity) vimmo.Entity {
   198  
   199  	for {
   200  		parent := item.Entity().Parent
   201  		item = reg.Get(*parent).(vimmo.Entity)
   202  		switch item.Reference().Type {
   203  		case "ComputeResource":
   204  			return item
   205  		case "ClusterComputeResource":
   206  			return item
   207  		}
   208  	}
   209  }