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