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 }