Skip to content

Commit

Permalink
Merge pull request #3373 from akutz/feature/more-hw-and-esxi-version-…
Browse files Browse the repository at this point in the history
…enhancements

chore: Better support for ESXi & HW versions
  • Loading branch information
akutz authored Feb 26, 2024
2 parents 1c017f8 + 08d2fd0 commit 3664efb
Show file tree
Hide file tree
Showing 8 changed files with 830 additions and 198 deletions.
2 changes: 1 addition & 1 deletion govc/USAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -5818,7 +5818,7 @@ Options:
-net.protocol= Network device protocol. Applicable to vmxnet3vrdma. Default to 'rocev2'
-on=true Power on VM
-pool= Resource pool [GOVC_RESOURCE_POOL]
-version= ESXi hardware version [8.0.2|8.0|7.0.2|7.0.1|7.0.0|6.7.2|6.7|6.5|6.0|5.5|5.1|5.0|4.0|3|2]
-version= ESXi hardware version [2|3|4|5.0|5.1|5.5|6.0|6.5|6.7|6.7.2|7.0|7.0.1|7.0.2|8.0|8.0.1|8.0.2]
```

## vm.customize
Expand Down
22 changes: 13 additions & 9 deletions govc/vm/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,14 @@ func (cmd *create) Register(ctx context.Context, f *flag.FlagSet) {
f.StringVar(&cmd.annotation, "annotation", "", "VM description")

f.StringVar(&cmd.firmware, "firmware", FirmwareTypes[0], FirmwareUsage)

esxiVersions := types.GetESXiVersions()
esxiVersionStrings := make([]string, len(esxiVersions))
for i := range esxiVersions {
esxiVersionStrings[i] = esxiVersions[i].String()
}
f.StringVar(&cmd.version, "version", "",
fmt.Sprintf("ESXi hardware version [%s]", strings.Join(types.GetESXiVersions(), "|")))
fmt.Sprintf("ESXi hardware version [%s]", strings.Join(esxiVersionStrings, "|")))

f.StringVar(&cmd.iso, "iso", "", "ISO path")
cmd.isoDatastoreFlag, ctx = flags.NewCustomDatastoreFlag(ctx)
Expand Down Expand Up @@ -327,15 +333,13 @@ func (cmd *create) createVM(ctx context.Context) (*object.Task, error) {
var err error

if cmd.version != "" {
v, ok := types.GetHardwareVersionForESXi(cmd.version)
if !ok {
hv := types.HardwareVersion(cmd.version)
if !hv.IsValid() {
return nil, fmt.Errorf("invalid version: %s", cmd.version)
}
v = hv
if v, _ := types.ParseESXiVersion(cmd.version); v.IsValid() {
cmd.version = v.HardwareVersion().String()
} else if v, _ := types.ParseHardwareVersion(cmd.version); v.IsValid() {
cmd.version = v.String()
} else {
return nil, fmt.Errorf("invalid version: %s", cmd.version)
}
cmd.version = v.String()
}

spec := &types.VirtualMachineConfigSpec{
Expand Down
17 changes: 7 additions & 10 deletions simulator/environment_browser.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,30 +83,27 @@ func (b *EnvironmentBrowser) initDescriptorReturnVal(
ref := hostRefs[j]
ctx.WithLock(ref, func() {
host := ctx.Map.Get(ref).(*HostSystem)
hostVersion := host.Config.Product.Version
hostHardwareVersion, ok := types.GetHardwareVersionForESXi(hostVersion)
if !ok {
return
}
hostVersion := types.MustParseESXiVersion(host.Config.Product.Version)
hostHardwareVersion := hostVersion.HardwareVersion()
maxHardwareVersionForHost[ref] = hostHardwareVersion
if maxHardwareVersion == "" {
if !maxHardwareVersion.IsValid() {
maxHardwareVersion = hostHardwareVersion
return
}
if hostHardwareVersion.Int() > maxHardwareVersion.Int() {
if hostHardwareVersion > maxHardwareVersion {
maxHardwareVersion = hostHardwareVersion
}
})
}

if maxHardwareVersion == "" {
if !maxHardwareVersion.IsValid() {
return
}

hardwareVersions := types.GetHardwareVersions()
for i := range hardwareVersions {
hv := hardwareVersions[i]
dco := hv.Int() == maxHardwareVersion.Int()
dco := hv == maxHardwareVersion
cod := types.VirtualMachineConfigOptionDescriptor{
Key: hv.String(),
Description: hv.String(),
Expand All @@ -116,7 +113,7 @@ func (b *EnvironmentBrowser) initDescriptorReturnVal(
UpgradeSupported: types.NewBool(true),
}
for hostRef, hostVer := range maxHardwareVersionForHost {
if hostVer.Int() >= hv.Int() {
if hostVer >= hv {
cod.Host = append(cod.Host, hostRef)
}
}
Expand Down
19 changes: 13 additions & 6 deletions simulator/virtual_machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -1921,6 +1921,7 @@ func (vm *VirtualMachine) UpgradeVMTask(ctx *Context, req *types.UpgradeVM_Task)
latestHardwareVersion string
hostRef = vm.Runtime.Host
supportedHardwareVersions = map[string]struct{}{}
vmHardwareVersionString = vm.Config.Version
)
if hostRef != nil {
var hostInMaintenanceMode bool
Expand Down Expand Up @@ -1965,17 +1966,20 @@ func (vm *VirtualMachine) UpgradeVMTask(ctx *Context, req *types.UpgradeVM_Task)
if latestHardwareVersion == "" {
latestHardwareVersion = esx.HardwareVersion
}
if vm.Config.Version == latestHardwareVersion {
if vmHardwareVersionString == latestHardwareVersion {
return nil, newInvalidStateFault("%s is latest version", vm.Reference().Value)
}
if req.Version == "" {
req.Version = latestHardwareVersion
}

// NotSupported
targetVersion := types.HardwareVersion(req.Version)
if _, ok := supportedHardwareVersions[targetVersion.String()]; !ok {
msg := fmt.Sprintf("%s not supported", string(targetVersion))
targetVersion, _ := types.ParseHardwareVersion(req.Version)
if targetVersion.IsValid() {
req.Version = targetVersion.String()
}
if _, ok := supportedHardwareVersions[req.Version]; !ok {
msg := fmt.Sprintf("%s not supported", req.Version)
return nil, &types.NotSupported{
RuntimeFault: types.RuntimeFault{
MethodFault: types.MethodFault{
Expand All @@ -1991,12 +1995,15 @@ func (vm *VirtualMachine) UpgradeVMTask(ctx *Context, req *types.UpgradeVM_Task)
}

// AlreadyUpgraded
if targetVersion.Int() <= types.HardwareVersion(vm.Config.Version).Int() {
vmHardwareVersion, _ := types.ParseHardwareVersion(vmHardwareVersionString)
if targetVersion.IsValid() && vmHardwareVersion.IsValid() &&
targetVersion <= vmHardwareVersion {

return nil, &types.AlreadyUpgradedFault{}
}

// InvalidArgument
if targetVersion.Int() < 3 {
if targetVersion < types.VMX3 {
return nil, &types.InvalidArgument{}
}

Expand Down
233 changes: 233 additions & 0 deletions vim25/types/esxi_version.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
/*
Copyright (c) 2024-2024 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package types

import (
"fmt"
"regexp"
"strconv"
)

// ESXiVersion is an ESXi version.
type ESXiVersion uint8

const (
esxiVersionBegin ESXiVersion = iota

ESXi2000
ESXi3000
ESXi4000
ESXi5000
ESXi5100
ESXi5500
ESXi6000
ESXi6500
ESXi6700
ESXi6720
ESXi7000
ESXi7010
ESXi7020
ESXi8000
ESXi8010
ESXi8020

esxiVersionEnd
)

// HardwareVersion returns the maximum hardware version supported by this
// version of ESXi, per https://kb.vmware.com/s/article/1003746.
func (ev ESXiVersion) HardwareVersion() HardwareVersion {
switch ev {
case ESXi2000:
return VMX3
case ESXi3000:
return VMX4
case ESXi4000:
return VMX7
case ESXi5000:
return VMX8
case ESXi5100:
return VMX9
case ESXi5500:
return VMX10
case ESXi6000:
return VMX11
case ESXi6500:
return VMX13
case ESXi6700:
return VMX14
case ESXi6720:
return VMX15
case ESXi7000:
return VMX17
case ESXi7010:
return VMX18
case ESXi7020:
return VMX19
case ESXi8000, ESXi8010:
return VMX20
case ESXi8020:
return VMX21
}
return 0
}

// IsHardwareVersionSupported returns true if the provided hardware version is
// supported by the given version of ESXi.
func (ev ESXiVersion) IsHardwareVersionSupported(hv HardwareVersion) bool {
return hv <= ev.HardwareVersion()
}

func (ev ESXiVersion) IsValid() bool {
return ev.String() != ""
}

func (ev ESXiVersion) String() string {
switch ev {
case ESXi2000:
return "2"
case ESXi3000:
return "3"
case ESXi4000:
return "4"
case ESXi5000:
return "5.0"
case ESXi5100:
return "5.1"
case ESXi5500:
return "5.5"
case ESXi6000:
return "6.0"
case ESXi6500:
return "6.5"
case ESXi6700:
return "6.7"
case ESXi6720:
return "6.7.2"
case ESXi7000:
return "7.0"
case ESXi7010:
return "7.0.1"
case ESXi7020:
return "7.0.2"
case ESXi8000:
return "8.0"
case ESXi8010:
return "8.0.1"
case ESXi8020:
return "8.0.2"
}
return ""
}

func (ev ESXiVersion) MarshalText() ([]byte, error) {
return []byte(ev.String()), nil
}

func (ev *ESXiVersion) UnmarshalText(text []byte) error {
v, err := ParseESXiVersion(string(text))
if err != nil {
return err
}
*ev = v
return nil
}

// MustParseESXiVersion parses the provided string into an ESXi version.
func MustParseESXiVersion(s string) ESXiVersion {
v, err := ParseESXiVersion(s)
if err != nil {
panic(err)
}
return v
}

var esxiRe = regexp.MustCompile(`(?i)^v?(\d)(?:\.(\d))?(?:\.(\d))?(?:\s*u(\d))?$`)

// ParseESXiVersion parses the provided string into an ESXi version.
func ParseESXiVersion(s string) (ESXiVersion, error) {
if m := esxiRe.FindStringSubmatch(s); len(m) > 0 {
var (
major int64
minor int64
patch int64
update int64
)

major, _ = strconv.ParseInt(m[1], 0, 0)
if len(m) > 2 {
minor, _ = strconv.ParseInt(m[2], 0, 0)
}
if len(m) > 3 {
patch, _ = strconv.ParseInt(m[3], 0, 0)
}
if len(m) > 4 {
update, _ = strconv.ParseInt(m[4], 0, 0)
}

switch {
case major == 2 && minor == 0 && patch == 0 && update == 0:
return ESXi2000, nil
case major == 3 && minor == 0 && patch == 0 && update == 0:
return ESXi3000, nil
case major == 4 && minor == 0 && patch == 0 && update == 0:
return ESXi4000, nil
case major == 5 && minor == 0 && patch == 0 && update == 0:
return ESXi5000, nil
case major == 5 && minor == 1 && patch == 0 && update == 0:
return ESXi5100, nil
case major == 5 && minor == 5 && patch == 0 && update == 0:
return ESXi5500, nil
case major == 6 && minor == 0 && patch == 0 && update == 0:
return ESXi6000, nil
case major == 6 && minor == 5 && patch == 0 && update == 0:
return ESXi6500, nil
case major == 6 && minor == 7 && patch == 0 && update == 0:
return ESXi6700, nil
case major == 6 && minor == 7 && patch == 2 && update == 0,
major == 6 && minor == 7 && patch == 0 && update == 2:
return ESXi6720, nil
case major == 7 && minor == 0 && patch == 0 && update == 0:
return ESXi7000, nil
case major == 7 && minor == 0 && patch == 1 && update == 0,
major == 7 && minor == 0 && patch == 0 && update == 1:
return ESXi7010, nil
case major == 7 && minor == 0 && patch == 2 && update == 0,
major == 7 && minor == 0 && patch == 0 && update == 2:
return ESXi7020, nil
case major == 8 && minor == 0 && patch == 0 && update == 0:
return ESXi8000, nil
case major == 8 && minor == 0 && patch == 1 && update == 0,
major == 8 && minor == 0 && patch == 0 && update == 1:
return ESXi8010, nil
case major == 8 && minor == 0 && patch == 2 && update == 0,
major == 8 && minor == 0 && patch == 0 && update == 2:
return ESXi8020, nil
}
}

return 0, fmt.Errorf("invalid version: %q", s)
}

// GetESXiVersions returns a list of ESXi versions.
func GetESXiVersions() []ESXiVersion {
dst := make([]ESXiVersion, esxiVersionEnd-1)
for i := esxiVersionBegin + 1; i < esxiVersionEnd; i++ {
dst[i-1] = i
}
return dst
}
Loading

0 comments on commit 3664efb

Please sign in to comment.