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 }