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  }