Skip to content

Commit

Permalink
fix: version checks
Browse files Browse the repository at this point in the history
- Updates the version checks.
- Updates log messages based on INFO or WARN context.
- Moves constants to the `driver.go` for easier maintenance.

Signed-off-by: Ryan Johnson <[email protected]>
  • Loading branch information
tenthirtyam authored and lbajolet-hashicorp committed Dec 5, 2024
1 parent bc98c53 commit 1c153d8
Show file tree
Hide file tree
Showing 8 changed files with 161 additions and 175 deletions.
95 changes: 42 additions & 53 deletions builder/vmware/common/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import (
"os/exec"
"regexp"
"runtime"
"strconv"
"strings"
"time"

Expand All @@ -23,6 +22,20 @@ import (
)

const (
// VMware Fusion.
fusionProductName = "VMware Fusion"
fusionMinVersion = "13.5.0"

// VMware Workstation.
workstationProductName = "VMware Workstation"
workstationMinVersion = "17.5.0"

// VMware Workstation Player.
playerProductName = "VMware Workstation Player"
playerMinVersion = "17.5.0"
playerInstallationPathKey = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\vmplayer.exe"
playerRegistryKey = "SYSTEM\\CurrentControlSet\\services\\VMnetDHCP\\Parameters"

// OVF Tool.
ovfToolDownloadURL = "https://developer.broadcom.com/tools/open-virtualization-format-ovf-tool/latest"
ovfToolMinVersion = "4.6.0"
Expand Down Expand Up @@ -63,6 +76,14 @@ const (
netmapConfFile = "netmap.conf"
)

// Initialize version objects
var (
fusionMinVersionObj = version.Must(version.NewVersion(fusionMinVersion))
workstationMinVersionObj = version.Must(version.NewVersion(workstationMinVersion))
playerMinVersionObj = version.Must(version.NewVersion(playerMinVersion))
ovfToolMinVersionObj = version.Must(version.NewVersion(ovfToolMinVersion))
)

// The possible paths to the DHCP leases file.
var dhcpLeasesPaths = []string{
"dhcp/dhcp.leases",
Expand All @@ -88,9 +109,6 @@ var technicalPreview = regexp.MustCompile(technicalPreviewRegex)
// The VMware OVF Tool version.
var ovfToolVersion = regexp.MustCompile(ovfToolVersionRegex)

// The minimum recommended version of the VMware OVF Tool.
var ovfToolMinRecommended = version.Must(version.NewVersion(ovfToolMinVersion))

// A driver is able to talk to VMware, control virtual machines, etc.
type Driver interface {
// Clone clones the VMX and the disk to the destination path. The
Expand Down Expand Up @@ -162,8 +180,6 @@ type Driver interface {
VerifyOvfTool(bool, bool) error
}

// NewDriver returns a new driver implementation for this operating
// system, or an error if the driver couldn't be initialized.
func NewDriver(dconfig *DriverConfig, config *SSHConfig, vmName string) (Driver, error) {
var drivers []Driver

Expand Down Expand Up @@ -212,7 +228,7 @@ func NewDriver(dconfig *DriverConfig, config *SSHConfig, vmName string) (Driver,
func runAndLog(cmd *exec.Cmd) (string, string, error) {
var stdout, stderr bytes.Buffer

log.Printf("Executing: %s %s", cmd.Path, strings.Join(cmd.Args[1:], " "))
log.Printf("[INFO] Running: %s %s", cmd.Path, strings.Join(cmd.Args[1:], " "))
cmd.Stdout = &stdout
cmd.Stderr = &stderr
err := cmd.Run()
Expand Down Expand Up @@ -256,38 +272,11 @@ func runAndLog(cmd *exec.Cmd) (string, string, error) {
return returnStdout, returnStderr, err
}

// Still used for Workstation and Player until conversion.
func normalizeVersion(version string) (string, error) {
i, err := strconv.Atoi(version)
if err != nil {
return "", fmt.Errorf("returned a non-integer version %q: %s", version, err)
}

return fmt.Sprintf("%02d", i), nil
}

// Still used for Workstation and Player until conversion.
func compareVersions(versionFound string, versionWanted string, product string) error {
found, err := normalizeVersion(versionFound)
if err != nil {
return err
}

wanted, err := normalizeVersion(versionWanted)
if err != nil {
return err
}

if found < wanted {
return fmt.Errorf("requires %s or later, found %s", versionWanted, versionFound)
}

return nil
}

func compareVersionObjects(versionFound *version.Version, versionWanted *version.Version, product string) error {
if versionFound.LessThan(versionWanted) {
return fmt.Errorf("requires %s or later, found %s", versionWanted.String(), versionFound.String())
// compareVersionObjects compares two version.Version objects and returns an
// error if the found version is less than the required version.
func compareVersionObjects(versionFound, versionRequired *version.Version, product string) error {
if versionFound.LessThan(versionRequired) {
return fmt.Errorf("[ERROR] Requires %s %s or later; %s installed", product, versionRequired.String(), versionFound.String())
}
return nil
}
Expand Down Expand Up @@ -375,7 +364,7 @@ func (d *VmwareDriver) GuestAddress(state multistep.StateBag) (string, error) {
return "", errors.New("unable to determine MAC address")
}
}
log.Printf("GuestAddress discovered MAC address: %s", macAddress)
log.Printf("[INFO] GuestAddress discovered MAC address: %s", macAddress)

res, err := net.ParseMAC(macAddress)
if err != nil {
Expand All @@ -399,7 +388,7 @@ func (d *VmwareDriver) PotentialGuestIP(state multistep.StateBag) ([]string, err

// log them to see what was detected
for _, device := range devices {
log.Printf("GuestIP discovered device matching %s: %s", network, device)
log.Printf("[INFO] GuestIP discovered device matching %s: %s", network, device)
}

// we were unable to find the device, maybe it's a custom one...
Expand All @@ -417,7 +406,7 @@ func (d *VmwareDriver) PotentialGuestIP(state multistep.StateBag) ([]string, err
if err != nil {
return []string{}, err
}
log.Printf("GuestIP discovered custom device matching %s: %s", network, device)
log.Printf("[INFO] GuestIP discovered custom device matching %s: %s", network, device)
}

// figure out our MAC address for looking up the guest address
Expand All @@ -433,7 +422,7 @@ func (d *VmwareDriver) PotentialGuestIP(state multistep.StateBag) ([]string, err
for _, device := range devices {
// figure out the correct dhcp leases
dhcpLeasesPath := d.DhcpLeasesPath(device)
log.Printf("Trying DHCP leases path: %s", dhcpLeasesPath)
log.Printf("[INFO] Trying DHCP leases path: %s", dhcpLeasesPath)
if dhcpLeasesPath == "" {
return []string{}, fmt.Errorf("no DHCP leases path found for device %s", device)
}
Expand Down Expand Up @@ -518,7 +507,7 @@ func (d *VmwareDriver) PotentialGuestIP(state multistep.StateBag) ([]string, err

// set the apple dhcp leases path
appleDhcpLeasesPath := "/var/db/dhcpd_leases"
log.Printf("Trying Apple DHCP leases path: %s", appleDhcpLeasesPath)
log.Printf("[INFO] Trying Apple DHCP leases path: %s", appleDhcpLeasesPath)

// open up the path to the apple dhcpd leases
fh, err := os.Open(appleDhcpLeasesPath)
Expand Down Expand Up @@ -577,7 +566,7 @@ func (d *VmwareDriver) HostAddress(state multistep.StateBag) (string, error) {

// log them to see what was detected
for _, device := range devices {
log.Printf("HostAddress discovered device matching %s: %s", network, device)
log.Printf("[INFO] HostAddress discovered device matching %s: %s", network, device)
}

// we were unable to find the device, maybe it's a custom one...
Expand All @@ -595,7 +584,7 @@ func (d *VmwareDriver) HostAddress(state multistep.StateBag) (string, error) {
if err != nil {
return "", err
}
log.Printf("HostAddress discovered custom device matching %s: %s", network, device)
log.Printf("[INFO] HostAddress discovered custom device matching %s: %s", network, device)
}

var lastError error
Expand Down Expand Up @@ -657,7 +646,7 @@ func (d *VmwareDriver) HostIP(state multistep.StateBag) (string, error) {

// log them to see what was detected
for _, device := range devices {
log.Printf("HostIP discovered device matching %s: %s", network, device)
log.Printf("[INFO] HostIP discovered device matching %s: %s", network, device)
}

// we were unable to find the device, maybe it's a custom one...
Expand All @@ -675,7 +664,7 @@ func (d *VmwareDriver) HostIP(state multistep.StateBag) (string, error) {
if err != nil {
return "", err
}
log.Printf("HostIP discovered custom device matching %s: %s", network, device)
log.Printf("[INFO] HostIP discovered custom device matching %s: %s", network, device)
}

var lastError error
Expand Down Expand Up @@ -740,7 +729,7 @@ func CheckOvfToolVersion(ovftoolPath string) error {
return errors.New("failed to execute ovftool")
}
versionOutput := string(output)
log.Printf("Returned ovftool version: %s.", versionOutput)
log.Printf("[INFO] Returned ovftool version: %s.", versionOutput)

versionString := ovfToolVersion.FindString(versionOutput)
if versionString == "" {
Expand All @@ -753,8 +742,8 @@ func CheckOvfToolVersion(ovftoolPath string) error {
return fmt.Errorf("failed to parse ovftool version: %v", err)
}

if currentVersion.LessThan(ovfToolMinRecommended) {
log.Printf("[WARN] The version of ovftool (%s) is below the minimum recommended version (%s). Please download the latest version from %s.", currentVersion, ovfToolMinRecommended, ovfToolDownloadURL)
if currentVersion.LessThan(ovfToolMinVersionObj) {
log.Printf("[WARN] The version of ovftool (%s) is below the minimum recommended version (%s). Please download the latest version from %s.", currentVersion, ovfToolMinVersionObj, ovfToolDownloadURL)
// Log a warning; do not return an error.
// TODO: Transition this to an error in a future major release.
}
Expand All @@ -780,13 +769,13 @@ func (d *VmwareDriver) VerifyOvfTool(SkipExport, _ bool) error {
return nil
}

log.Printf("Verifying that ovftool exists...")
log.Printf("[INFO] Verifying that ovftool exists...")
ovftoolPath := GetOvfTool()
if ovftoolPath == "" {
return errors.New("ovftool not found; install and include it in your PATH")
}

log.Printf("Checking ovftool version...")
log.Printf("[INFO] Checking ovftool version...")
if err := CheckOvfToolVersion(ovftoolPath); err != nil {
return fmt.Errorf("%v", err)
}
Expand Down
53 changes: 9 additions & 44 deletions builder/vmware/common/driver_fusion.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,6 @@ import (
"github.com/hashicorp/packer-plugin-sdk/multistep"
)

const (
// VMware Fusion application name.
fusionProductName = "VMware Fusion"

// VMware Fusion versions.
// TODO: Update to best effort comply with the Broadcom Product Lifecycle.
minimumFusionVersion = "6.0.0"
isoPathChangeFusionVersion = "13.0.0"
)

// Initialize version objects
var (
minimumFusionVersionObj, _ = version.NewVersion(minimumFusionVersion)
isoPathChangeFusionVersionObj, _ = version.NewVersion(isoPathChangeFusionVersion)
)

const fusionSuppressPlist = `<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
Expand Down Expand Up @@ -206,13 +190,13 @@ func (d *FusionDriver) Clone(dst, src string, linked bool, snapshot string) erro
}

func (d *FusionDriver) Verify() error {
version, err := d.getFusionVersion()
fusionVersion, err := d.getFusionVersion()
log.Printf("[INFO] Checking %s version...", fusionProductName)
if err != nil {
return fmt.Errorf("error getting %s version: %s", fusionProductName, err)
}

log.Printf("[INFO] %s: %s", fusionProductName, version)
log.Printf("[INFO] %s: %s", fusionProductName, fusionVersion)
log.Printf("[INFO] Checking %s paths...", fusionProductName)

if _, err := os.Stat(d.AppPath); err != nil {
Expand Down Expand Up @@ -283,38 +267,19 @@ func (d *FusionDriver) Verify() error {
return ReadNetworkingConfig(fd)
}

return compareVersionObjects(version, minimumFusionVersionObj, fusionProductName)
return compareVersionObjects(fusionVersion, fusionMinVersionObj, fusionProductName)
}

func (d *FusionDriver) ToolsIsoPath(k string) string {
versionStr, err := d.getFusionVersion()
if err != nil {
log.Printf("[WARN] Unable to return %s version: %s. Using the default path.", fusionProductName, err)
return d.toolsIsoPath(archAMD64, d.isoFileName(k))
}

versionMatch := productVersion.FindStringSubmatch(versionStr.String())
if len(versionMatch) < 2 {
log.Printf("[WARN] Unable to extract version from string: %s. Using the default path.", versionStr)
return d.toolsIsoPath(archAMD64, d.isoFileName(k))
}

parsedVersion, err := version.NewVersion(versionMatch[1])
if err != nil {
log.Printf("[WARN] Unable to parse %s version: %s. Using the default path.", fusionProductName, err)
return d.toolsIsoPath(archAMD64, d.isoFileName(k))
}

if isoPathChangeFusionVersionObj == nil {
log.Printf("[WARN] Unable to parse %s version for comparison. Using the default path.", fusionProductName)
return d.toolsIsoPath(archAMD64, d.isoFileName(k))
}

arch := archAMD64
if parsedVersion.GreaterThanOrEqual(isoPathChangeFusionVersionObj) && k == osWindows && runtime.GOARCH == archARM64 {
var arch string
switch runtime.GOARCH {
case "amd64":
arch = archAMD64
default:
arch = archARM64
}

log.Printf("[INFO] Selected architecture: %s", arch)
return d.toolsIsoPath(arch, d.isoFileName(k))
}

Expand Down
Loading

0 comments on commit 1c153d8

Please sign in to comment.