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

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