github.com/vmware/govmomi@v0.43.0/simulator/environment_browser.go (about) 1 /* 2 Copyright (c) 2019-2023 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 "strings" 21 22 "github.com/vmware/govmomi/simulator/esx" 23 "github.com/vmware/govmomi/vim25/methods" 24 "github.com/vmware/govmomi/vim25/mo" 25 "github.com/vmware/govmomi/vim25/soap" 26 "github.com/vmware/govmomi/vim25/types" 27 ) 28 29 type EnvironmentBrowser struct { 30 mo.EnvironmentBrowser 31 32 QueryConfigTargetResponse types.QueryConfigTargetResponse 33 QueryConfigOptionResponse types.QueryConfigOptionResponse 34 QueryConfigOptionDescriptorResponse types.QueryConfigOptionDescriptorResponse 35 QueryTargetCapabilitiesResponse types.QueryTargetCapabilitiesResponse 36 } 37 38 func newEnvironmentBrowser( 39 ctx *Context, 40 hostRefs ...types.ManagedObjectReference) *types.ManagedObjectReference { 41 42 env := new(EnvironmentBrowser) 43 env.initDescriptorReturnVal(ctx, hostRefs...) 44 Map.Put(env) 45 return &env.Self 46 } 47 48 func (b *EnvironmentBrowser) addHost( 49 ctx *Context, hostRef types.ManagedObjectReference) { 50 51 // Get a set of unique hosts. 52 hostSet := map[types.ManagedObjectReference]struct{}{ 53 hostRef: {}, 54 } 55 for i := range b.QueryConfigOptionDescriptorResponse.Returnval { 56 cod := b.QueryConfigOptionDescriptorResponse.Returnval[i] 57 for j := range cod.Host { 58 if _, ok := hostSet[cod.Host[j]]; !ok { 59 hostSet[cod.Host[j]] = struct{}{} 60 } 61 } 62 } 63 64 // Get a list of unique hosts. 65 var hostRefs []types.ManagedObjectReference 66 for ref := range hostSet { 67 hostRefs = append(hostRefs, ref) 68 } 69 70 // Clear the descriptor's return val. 71 b.QueryConfigOptionDescriptorResponse.Returnval = nil 72 73 b.initDescriptorReturnVal(ctx, hostRefs...) 74 } 75 76 func (b *EnvironmentBrowser) initDescriptorReturnVal( 77 ctx *Context, hostRefs ...types.ManagedObjectReference) { 78 79 // Get the max supported hardware version for this list of hosts. 80 var maxHardwareVersion types.HardwareVersion 81 maxHardwareVersionForHost := map[types.ManagedObjectReference]types.HardwareVersion{} 82 for j := range hostRefs { 83 ref := hostRefs[j] 84 ctx.WithLock(ref, func() { 85 host := ctx.Map.Get(ref).(*HostSystem) 86 hostVersion := types.MustParseESXiVersion(host.Config.Product.Version) 87 hostHardwareVersion := hostVersion.HardwareVersion() 88 maxHardwareVersionForHost[ref] = hostHardwareVersion 89 if !maxHardwareVersion.IsValid() { 90 maxHardwareVersion = hostHardwareVersion 91 return 92 } 93 if hostHardwareVersion > maxHardwareVersion { 94 maxHardwareVersion = hostHardwareVersion 95 } 96 }) 97 } 98 99 if !maxHardwareVersion.IsValid() { 100 return 101 } 102 103 hardwareVersions := types.GetHardwareVersions() 104 for i := range hardwareVersions { 105 hv := hardwareVersions[i] 106 dco := hv == maxHardwareVersion 107 cod := types.VirtualMachineConfigOptionDescriptor{ 108 Key: hv.String(), 109 Description: hv.String(), 110 DefaultConfigOption: types.NewBool(dco), 111 CreateSupported: types.NewBool(true), 112 RunSupported: types.NewBool(true), 113 UpgradeSupported: types.NewBool(true), 114 } 115 for hostRef, hostVer := range maxHardwareVersionForHost { 116 if hostVer >= hv { 117 cod.Host = append(cod.Host, hostRef) 118 } 119 } 120 121 b.QueryConfigOptionDescriptorResponse.Returnval = append( 122 b.QueryConfigOptionDescriptorResponse.Returnval, cod) 123 124 if dco { 125 break 126 } 127 } 128 } 129 130 func (b *EnvironmentBrowser) hosts(ctx *Context) []types.ManagedObjectReference { 131 ctx.Map.m.Lock() 132 defer ctx.Map.m.Unlock() 133 for _, obj := range ctx.Map.objects { 134 switch e := obj.(type) { 135 case *mo.ComputeResource: 136 if b.Self == *e.EnvironmentBrowser { 137 return e.Host 138 } 139 case *ClusterComputeResource: 140 if b.Self == *e.EnvironmentBrowser { 141 return e.Host 142 } 143 } 144 } 145 return nil 146 } 147 148 func (b *EnvironmentBrowser) QueryConfigOption(req *types.QueryConfigOption) soap.HasFault { 149 body := new(methods.QueryConfigOptionBody) 150 151 opt := b.QueryConfigOptionResponse.Returnval 152 if opt == nil { 153 opt = &types.VirtualMachineConfigOption{ 154 Version: esx.HardwareVersion, 155 DefaultDevice: esx.VirtualDevice, 156 } 157 } 158 159 body.Res = &types.QueryConfigOptionResponse{ 160 Returnval: opt, 161 } 162 163 return body 164 } 165 166 func guestFamily(id string) string { 167 // TODO: We could capture the entire GuestOsDescriptor list from EnvironmentBrowser, 168 // but it is a ton of data.. this should be good enough for now. 169 switch { 170 case strings.HasPrefix(id, "win"): 171 return string(types.VirtualMachineGuestOsFamilyWindowsGuest) 172 case strings.HasPrefix(id, "darwin"): 173 return string(types.VirtualMachineGuestOsFamilyDarwinGuestFamily) 174 default: 175 return string(types.VirtualMachineGuestOsFamilyLinuxGuest) 176 } 177 } 178 179 func (b *EnvironmentBrowser) QueryConfigOptionEx(req *types.QueryConfigOptionEx) soap.HasFault { 180 body := new(methods.QueryConfigOptionExBody) 181 182 opt := b.QueryConfigOptionResponse.Returnval 183 if opt == nil { 184 opt = &types.VirtualMachineConfigOption{ 185 Version: esx.HardwareVersion, 186 DefaultDevice: esx.VirtualDevice, 187 } 188 } 189 190 if req.Spec != nil { 191 // From the SDK QueryConfigOptionEx doc: 192 // "If guestId is nonempty, the guestOSDescriptor array of the config option is filtered to match against the guest IDs in the spec. 193 // If there is no match, the whole list is returned." 194 for _, id := range req.Spec.GuestId { 195 for _, gid := range GuestID { 196 if string(gid) == id { 197 opt.GuestOSDescriptor = []types.GuestOsDescriptor{{ 198 Id: id, 199 Family: guestFamily(id), 200 }} 201 202 break 203 } 204 } 205 } 206 } 207 208 if len(opt.GuestOSDescriptor) == 0 { 209 for i := range GuestID { 210 id := string(GuestID[i]) 211 opt.GuestOSDescriptor = append(opt.GuestOSDescriptor, types.GuestOsDescriptor{ 212 Id: id, 213 Family: guestFamily(id), 214 }) 215 } 216 } 217 218 body.Res = &types.QueryConfigOptionExResponse{ 219 Returnval: opt, 220 } 221 222 return body 223 } 224 225 func (b *EnvironmentBrowser) QueryConfigOptionDescriptor(ctx *Context, req *types.QueryConfigOptionDescriptor) soap.HasFault { 226 body := &methods.QueryConfigOptionDescriptorBody{ 227 Res: &types.QueryConfigOptionDescriptorResponse{ 228 Returnval: b.QueryConfigOptionDescriptorResponse.Returnval, 229 }, 230 } 231 232 return body 233 } 234 235 func (b *EnvironmentBrowser) QueryConfigTarget(ctx *Context, req *types.QueryConfigTarget) soap.HasFault { 236 body := &methods.QueryConfigTargetBody{ 237 Res: &types.QueryConfigTargetResponse{ 238 Returnval: b.QueryConfigTargetResponse.Returnval, 239 }, 240 } 241 242 if body.Res.Returnval != nil { 243 return body 244 } 245 246 target := &types.ConfigTarget{ 247 SmcPresent: types.NewBool(false), 248 } 249 body.Res.Returnval = target 250 251 var hosts []types.ManagedObjectReference 252 if req.Host == nil { 253 hosts = b.hosts(ctx) 254 } else { 255 hosts = append(hosts, *req.Host) 256 } 257 258 seen := make(map[types.ManagedObjectReference]bool) 259 260 for i := range hosts { 261 host := ctx.Map.Get(hosts[i]).(*HostSystem) 262 target.NumCpus += int32(host.Summary.Hardware.NumCpuPkgs) 263 target.NumCpuCores += int32(host.Summary.Hardware.NumCpuCores) 264 target.NumNumaNodes++ 265 266 for _, ref := range host.Datastore { 267 if seen[ref] { 268 continue 269 } 270 seen[ref] = true 271 272 ds := ctx.Map.Get(ref).(*Datastore) 273 target.Datastore = append(target.Datastore, types.VirtualMachineDatastoreInfo{ 274 VirtualMachineTargetInfo: types.VirtualMachineTargetInfo{ 275 Name: ds.Name, 276 }, 277 Datastore: ds.Summary, 278 Capability: ds.Capability, 279 Mode: string(types.HostMountModeReadWrite), 280 VStorageSupport: string(types.FileSystemMountInfoVStorageSupportStatusVStorageUnsupported), 281 }) 282 } 283 284 for _, ref := range host.Network { 285 if seen[ref] { 286 continue 287 } 288 seen[ref] = true 289 290 switch n := ctx.Map.Get(ref).(type) { 291 case *mo.Network: 292 target.Network = append(target.Network, types.VirtualMachineNetworkInfo{ 293 VirtualMachineTargetInfo: types.VirtualMachineTargetInfo{ 294 Name: n.Name, 295 }, 296 Network: n.Summary.GetNetworkSummary(), 297 }) 298 case *DistributedVirtualPortgroup: 299 dvs := ctx.Map.Get(*n.Config.DistributedVirtualSwitch).(*DistributedVirtualSwitch) 300 target.DistributedVirtualPortgroup = append(target.DistributedVirtualPortgroup, types.DistributedVirtualPortgroupInfo{ 301 SwitchName: dvs.Name, 302 SwitchUuid: dvs.Uuid, 303 PortgroupName: n.Name, 304 PortgroupKey: n.Key, 305 PortgroupType: n.Config.Type, 306 UplinkPortgroup: false, 307 Portgroup: n.Self, 308 NetworkReservationSupported: types.NewBool(false), 309 }) 310 case *DistributedVirtualSwitch: 311 target.DistributedVirtualSwitch = append(target.DistributedVirtualSwitch, types.DistributedVirtualSwitchInfo{ 312 SwitchName: n.Name, 313 SwitchUuid: n.Uuid, 314 DistributedVirtualSwitch: n.Self, 315 NetworkReservationSupported: types.NewBool(false), 316 }) 317 } 318 } 319 } 320 321 return body 322 } 323 324 func (b *EnvironmentBrowser) QueryTargetCapabilities(ctx *Context, req *types.QueryTargetCapabilities) soap.HasFault { 325 body := &methods.QueryTargetCapabilitiesBody{ 326 Res: &types.QueryTargetCapabilitiesResponse{ 327 Returnval: b.QueryTargetCapabilitiesResponse.Returnval, 328 }, 329 } 330 331 if body.Res.Returnval != nil { 332 return body 333 } 334 335 body.Res.Returnval = &types.HostCapability{ 336 VmotionSupported: true, 337 MaintenanceModeSupported: true, 338 } 339 340 return body 341 }