github.com/vmware/govmomi@v0.51.0/simulator/vm_compatibility_checker.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  	"fmt"
     9  	"math/rand"
    10  	"slices"
    11  
    12  	"github.com/vmware/govmomi/vim25/methods"
    13  	"github.com/vmware/govmomi/vim25/mo"
    14  	"github.com/vmware/govmomi/vim25/soap"
    15  	"github.com/vmware/govmomi/vim25/types"
    16  )
    17  
    18  type VmCompatibilityChecker struct {
    19  	mo.VirtualMachineCompatibilityChecker
    20  }
    21  
    22  func resolveHostsAndPool(ctx *Context, vm, host, pool *types.ManagedObjectReference) (*ResourcePool, []types.ManagedObjectReference) {
    23  	var vmMo *VirtualMachine
    24  	var poolMo *ResourcePool
    25  
    26  	switch {
    27  	case pool != nil:
    28  		poolMo = ctx.Map.Get(*pool).(*ResourcePool)
    29  	case vm != nil:
    30  		vmMo = ctx.Map.Get(*vm).(*VirtualMachine)
    31  		poolMo = ctx.Map.Get(*vmMo.ResourcePool).(*ResourcePool)
    32  	case host != nil:
    33  		h := ctx.Map.Get(*host).(*HostSystem)
    34  		parent := hostParent(ctx, &h.HostSystem).ResourcePool
    35  		poolMo = ctx.Map.Get(*parent).(*ResourcePool)
    36  	}
    37  
    38  	var hosts []types.ManagedObjectReference
    39  
    40  	switch {
    41  	case host != nil:
    42  		hosts = append(hosts, *host)
    43  	case pool != nil:
    44  		hosts = resourcePoolHosts(ctx, poolMo)
    45  	case vm != nil:
    46  		hosts = append(hosts, *vmMo.Runtime.Host)
    47  	}
    48  
    49  	return poolMo, hosts
    50  }
    51  
    52  func validateHostsAndPool(ctx *Context, pool *ResourcePool, hosts []types.ManagedObjectReference) *types.InvalidArgument {
    53  	allHosts := resourcePoolHosts(ctx, pool)
    54  
    55  	for _, host := range hosts {
    56  		if !slices.Contains(allHosts, host) {
    57  			return &types.InvalidArgument{
    58  				InvalidProperty: "spec.pool",
    59  			}
    60  		}
    61  	}
    62  
    63  	return nil
    64  }
    65  
    66  func (c *VmCompatibilityChecker) checkVmConfigSpec(ctx *Context, check *types.CheckResult, spec types.VirtualMachineConfigSpec, hosts []types.ManagedObjectReference) {
    67  	if check.Host == nil {
    68  		// By default all hosts use the same HostSystem template, so we check against any.
    69  		// But we could choose a host based on the spec, e.g. record + playback of real hosts
    70  		check.Host = &hosts[rand.Intn(len(hosts))]
    71  	}
    72  
    73  	host := ctx.Map.Get(*check.Host).(*HostSystem)
    74  
    75  	mem := int32(spec.MemoryMB)
    76  	if mem > 0 {
    77  		min := int32(4)
    78  		max := host.Capability.MaxSupportedVmMemory
    79  		if mem > max || mem < min {
    80  			check.Warning = append(check.Warning, types.LocalizedMethodFault{
    81  				Fault: &types.MemorySizeNotSupported{
    82  					MemorySizeMB:    mem,
    83  					MinMemorySizeMB: min,
    84  					MaxMemorySizeMB: max,
    85  				},
    86  				LocalizedMessage: fmt.Sprintf("vm requires %d MB of memory, outside the range of %d to %d", mem, min, max),
    87  			})
    88  		}
    89  	}
    90  
    91  	cpu := spec.NumCPUs
    92  	if cpu > 0 {
    93  		max := int32(host.Summary.Hardware.NumCpuCores)
    94  		if cpu > max {
    95  			check.Warning = append(check.Warning, types.LocalizedMethodFault{
    96  				Fault: &types.NotEnoughCpus{
    97  					NumCpuDest: max,
    98  					NumCpuVm:   cpu,
    99  				},
   100  				LocalizedMessage: fmt.Sprintf("vm requires %d CPUs, host has %d", cpu, max),
   101  			})
   102  		}
   103  	}
   104  
   105  	if spec.GuestId != "" {
   106  		var guest types.VirtualMachineGuestOsIdentifier
   107  		if !slices.Contains(guest.Strings(), spec.GuestId) {
   108  			check.Warning = append(check.Warning, types.LocalizedMethodFault{
   109  				Fault: &types.UnsupportedGuest{
   110  					UnsupportedGuestOS: spec.GuestId,
   111  				},
   112  				LocalizedMessage: fmt.Sprintf("vm guest os %s not supported", spec.GuestId),
   113  			})
   114  		}
   115  	}
   116  }
   117  
   118  func (c *VmCompatibilityChecker) CheckVmConfigTask(
   119  	ctx *Context,
   120  	r *types.CheckVmConfig_Task) soap.HasFault {
   121  
   122  	task := CreateTask(c, "checkVmConfig", func(t *Task) (types.AnyType, types.BaseMethodFault) {
   123  		if r.Vm == nil && r.Host == nil && r.Pool == nil {
   124  			return nil, new(types.InvalidArgument)
   125  		}
   126  
   127  		poolMo, hosts := resolveHostsAndPool(ctx, r.Vm, r.Host, r.Pool)
   128  		if err := validateHostsAndPool(ctx, poolMo, hosts); err != nil {
   129  			return nil, err
   130  		}
   131  
   132  		check := types.CheckResult{
   133  			Vm:   r.Vm,
   134  			Host: r.Host,
   135  		}
   136  
   137  		c.checkVmConfigSpec(ctx, &check, r.Spec, hosts)
   138  
   139  		return types.ArrayOfCheckResult{
   140  			CheckResult: []types.CheckResult{check},
   141  		}, nil
   142  	})
   143  
   144  	return &methods.CheckVmConfig_TaskBody{
   145  		Res: &types.CheckVmConfig_TaskResponse{
   146  			Returnval: task.Run(ctx),
   147  		},
   148  	}
   149  }
   150  
   151  func (c *VmCompatibilityChecker) CheckCompatibilityTask(
   152  	ctx *Context,
   153  	r *types.CheckCompatibility_Task) soap.HasFault {
   154  
   155  	task := CreateTask(c, "checkCompatibility", func(t *Task) (types.AnyType, types.BaseMethodFault) {
   156  		poolMo, hosts := resolveHostsAndPool(ctx, &r.Vm, r.Host, r.Pool)
   157  		if err := validateHostsAndPool(ctx, poolMo, hosts); err != nil {
   158  			return nil, err
   159  		}
   160  
   161  		check := types.CheckResult{
   162  			Vm:   &r.Vm,
   163  			Host: r.Host,
   164  		}
   165  
   166  		return types.ArrayOfCheckResult{
   167  			CheckResult: []types.CheckResult{check},
   168  		}, nil
   169  	})
   170  
   171  	return &methods.CheckCompatibility_TaskBody{
   172  		Res: &types.CheckCompatibility_TaskResponse{
   173  			Returnval: task.Run(ctx),
   174  		},
   175  	}
   176  }