From 82753c2689ac9587fd545f572b3d11ead59d5aac Mon Sep 17 00:00:00 2001 From: Ryan Johnson Date: Thu, 18 Jul 2024 18:04:10 -0400 Subject: [PATCH] refactor: consolidate player driver Consolidates `Player5Driver` and `Player6Driver` to `PlayerDriver` within `driver_player.go`. Signed-off-by: Ryan Johnson --- builder/vmware/common/driver.go | 3 +- .../{driver_player5.go => driver_player.go} | 57 +++++++++++------- builder/vmware/common/driver_player6.go | 59 ------------------- .../vmware/common/driver_player6_windows.go | 38 ------------ builder/vmware/common/driver_player_unix.go | 44 +++++++------- ...r5_windows.go => driver_player_windows.go} | 47 ++++++++++++--- 6 files changed, 97 insertions(+), 151 deletions(-) rename builder/vmware/common/{driver_player5.go => driver_player.go} (78%) delete mode 100644 builder/vmware/common/driver_player6.go delete mode 100644 builder/vmware/common/driver_player6_windows.go rename builder/vmware/common/{driver_player5_windows.go => driver_player_windows.go} (77%) diff --git a/builder/vmware/common/driver.go b/builder/vmware/common/driver.go index 72083941..47a76537 100644 --- a/builder/vmware/common/driver.go +++ b/builder/vmware/common/driver.go @@ -129,8 +129,7 @@ func NewDriver(dconfig *DriverConfig, config *SSHConfig, vmName string) (Driver, drivers = []Driver{ NewWorkstation10Driver(config), NewWorkstation9Driver(config), - NewPlayer6Driver(config), - NewPlayer5Driver(config), + NewPlayerDriver(config), } default: return nil, fmt.Errorf("can't find driver for OS: %s", runtime.GOOS) diff --git a/builder/vmware/common/driver_player5.go b/builder/vmware/common/driver_player.go similarity index 78% rename from builder/vmware/common/driver_player5.go rename to builder/vmware/common/driver_player.go index f0ec8cd0..4b386d06 100644 --- a/builder/vmware/common/driver_player5.go +++ b/builder/vmware/common/driver_player.go @@ -4,7 +4,6 @@ package common import ( - "errors" "fmt" "log" "os" @@ -15,8 +14,8 @@ import ( "github.com/hashicorp/packer-plugin-sdk/multistep" ) -// Player5Driver is a driver that can run VMware Player 5 on Linux. -type Player5Driver struct { +// PlayerDriver is a driver for VMware Workstation Player. +type PlayerDriver struct { VmwareDriver AppPath string @@ -24,21 +23,37 @@ type Player5Driver struct { QemuImgPath string VmrunPath string - // SSHConfig are the SSH settings for the Fusion VM SSHConfig *SSHConfig } -func NewPlayer5Driver(config *SSHConfig) Driver { - return &Player5Driver{ +func NewPlayerDriver(config *SSHConfig) Driver { + return &PlayerDriver{ SSHConfig: config, } } -func (d *Player5Driver) Clone(dst, src string, linked bool, snapshot string) error { - return errors.New("linked clones are not supported on this version of VMware Player, please upgrade") +func (d *PlayerDriver) Clone(dst, src string, linked bool, snapshot string) error { + + var cloneType string + if linked { + cloneType = "linked" + } else { + cloneType = "full" + } + + args := []string{"-T", "ws", "clone", src, dst, cloneType} + if snapshot != "" { + args = append(args, "-snapshot", snapshot) + } + cmd := exec.Command(d.VmrunPath, args...) + if _, _, err := runAndLog(cmd); err != nil { + return err + } + + return nil } -func (d *Player5Driver) CompactDisk(diskPath string) error { +func (d *PlayerDriver) CompactDisk(diskPath string) error { if d.QemuImgPath != "" { return d.qemuCompactDisk(diskPath) } @@ -56,7 +71,7 @@ func (d *Player5Driver) CompactDisk(diskPath string) error { return nil } -func (d *Player5Driver) qemuCompactDisk(diskPath string) error { +func (d *PlayerDriver) qemuCompactDisk(diskPath string) error { cmd := exec.Command(d.QemuImgPath, "convert", "-f", "vmdk", "-O", "vmdk", "-o", "compat6", diskPath, diskPath+".new") if _, _, err := runAndLog(cmd); err != nil { return err @@ -73,7 +88,7 @@ func (d *Player5Driver) qemuCompactDisk(diskPath string) error { return nil } -func (d *Player5Driver) CreateDisk(output string, size string, adapter_type string, type_id string) error { +func (d *PlayerDriver) CreateDisk(output string, size string, adapter_type string, type_id string) error { var cmd *exec.Cmd if d.QemuImgPath != "" { cmd = exec.Command(d.QemuImgPath, "create", "-f", "vmdk", "-o", "compat6", output, size) @@ -87,13 +102,13 @@ func (d *Player5Driver) CreateDisk(output string, size string, adapter_type stri return nil } -func (d *Player5Driver) CreateSnapshot(vmxPath string, snapshotName string) error { +func (d *PlayerDriver) CreateSnapshot(vmxPath string, snapshotName string) error { cmd := exec.Command(d.VmrunPath, "-T", "player", "snapshot", vmxPath, snapshotName) _, _, err := runAndLog(cmd) return err } -func (d *Player5Driver) IsRunning(vmxPath string) (bool, error) { +func (d *PlayerDriver) IsRunning(vmxPath string) (bool, error) { vmxPath, err := filepath.Abs(vmxPath) if err != nil { return false, err @@ -114,11 +129,11 @@ func (d *Player5Driver) IsRunning(vmxPath string) (bool, error) { return false, nil } -func (d *Player5Driver) CommHost(state multistep.StateBag) (string, error) { +func (d *PlayerDriver) CommHost(state multistep.StateBag) (string, error) { return CommHost(d.SSHConfig)(state) } -func (d *Player5Driver) Start(vmxPath string, headless bool) error { +func (d *PlayerDriver) Start(vmxPath string, headless bool) error { guiArgument := "gui" if headless { guiArgument = "nogui" @@ -132,7 +147,7 @@ func (d *Player5Driver) Start(vmxPath string, headless bool) error { return nil } -func (d *Player5Driver) Stop(vmxPath string) error { +func (d *PlayerDriver) Stop(vmxPath string) error { cmd := exec.Command(d.VmrunPath, "-T", "player", "stop", vmxPath, "hard") if _, _, err := runAndLog(cmd); err != nil { return err @@ -141,11 +156,11 @@ func (d *Player5Driver) Stop(vmxPath string) error { return nil } -func (d *Player5Driver) SuppressMessages(vmxPath string) error { +func (d *PlayerDriver) SuppressMessages(vmxPath string) error { return nil } -func (d *Player5Driver) Verify() error { +func (d *PlayerDriver) Verify() error { var err error if d.AppPath == "" { if d.AppPath, err = playerFindVMware(); err != nil { @@ -239,14 +254,14 @@ func (d *Player5Driver) Verify() error { return nil } -func (d *Player5Driver) ToolsIsoPath(flavor string) string { +func (d *PlayerDriver) ToolsIsoPath(flavor string) string { return playerToolsIsoPath(flavor) } -func (d *Player5Driver) ToolsInstall() error { +func (d *PlayerDriver) ToolsInstall() error { return nil } -func (d *Player5Driver) GetVmwareDriver() VmwareDriver { +func (d *PlayerDriver) GetVmwareDriver() VmwareDriver { return d.VmwareDriver } diff --git a/builder/vmware/common/driver_player6.go b/builder/vmware/common/driver_player6.go deleted file mode 100644 index 4d2af0f9..00000000 --- a/builder/vmware/common/driver_player6.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package common - -import ( - "os/exec" -) - -const VMWARE_PLAYER_VERSION = "6" - -// Player6Driver is a driver that can run VMware Player 6 -// installations. - -type Player6Driver struct { - Player5Driver -} - -func NewPlayer6Driver(config *SSHConfig) Driver { - return &Player6Driver{ - Player5Driver: Player5Driver{ - SSHConfig: config, - }, - } -} - -func (d *Player6Driver) Clone(dst, src string, linked bool, snapshot string) error { - // TODO(rasa) check if running player+, not just player - - var cloneType string - if linked { - cloneType = "linked" - } else { - cloneType = "full" - } - - args := []string{"-T", "ws", "clone", src, dst, cloneType} - if snapshot != "" { - args = append(args, "-snapshot", snapshot) - } - cmd := exec.Command(d.Player5Driver.VmrunPath, args...) - if _, _, err := runAndLog(cmd); err != nil { - return err - } - - return nil -} - -func (d *Player6Driver) Verify() error { - if err := d.Player5Driver.Verify(); err != nil { - return err - } - - return playerVerifyVersion(VMWARE_PLAYER_VERSION) -} - -func (d *Player6Driver) GetVmwareDriver() VmwareDriver { - return d.Player5Driver.VmwareDriver -} diff --git a/builder/vmware/common/driver_player6_windows.go b/builder/vmware/common/driver_player6_windows.go deleted file mode 100644 index bfacb2df..00000000 --- a/builder/vmware/common/driver_player6_windows.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -//go:build windows - -package common - -import ( - "fmt" - "log" - "regexp" - "syscall" -) - -func playerVerifyVersion(version string) error { - key := `SOFTWARE\Wow6432Node\VMware, Inc.\VMware Player` - subkey := "ProductVersion" - productVersion, err := readRegString(syscall.HKEY_LOCAL_MACHINE, key, subkey) - if err != nil { - log.Printf(`Unable to read registry key %s\%s`, key, subkey) - key = `SOFTWARE\VMware, Inc.\VMware Player` - productVersion, err = readRegString(syscall.HKEY_LOCAL_MACHINE, key, subkey) - if err != nil { - log.Printf(`Unable to read registry key %s\%s`, key, subkey) - return err - } - } - - versionRe := regexp.MustCompile(`^(\d+)\.`) - matches := versionRe.FindStringSubmatch(productVersion) - if matches == nil { - return fmt.Errorf( - `Could not find a VMware Player version in registry key %s\%s: '%s'`, key, subkey, productVersion) - } - log.Printf("Detected VMware Player version: %s", matches[1]) - - return compareVersions(matches[1], version, "Player") -} diff --git a/builder/vmware/common/driver_player_unix.go b/builder/vmware/common/driver_player_unix.go index f8bba40c..611ca914 100644 --- a/builder/vmware/common/driver_player_unix.go +++ b/builder/vmware/common/driver_player_unix.go @@ -3,7 +3,6 @@ //go:build !windows -// These functions are compatible with WS 9 and 10 on *NIX package common import ( @@ -17,6 +16,8 @@ import ( "runtime" ) +// VMware Workstation Player for Linux. + func playerFindVdiskManager() (string, error) { return exec.LookPath("vmware-vdiskmanager") } @@ -37,7 +38,7 @@ func playerToolsIsoPath(flavor string) string { return "/usr/lib/vmware/isoimages/" + flavor + ".iso" } -// return the base path to vmware's config on the host +// Return the base path to configuration files. func playerVMwareRoot() (s string, err error) { return "/etc/vmware", nil } @@ -45,17 +46,17 @@ func playerVMwareRoot() (s string, err error) { func playerDhcpLeasesPath(device string) string { base, err := playerVMwareRoot() if err != nil { - log.Printf("Error finding VMware root: %s", err) + log.Printf("Error finding configuration root path: %s", err) return "" } - // Build the base path to VMware configuration for specified device: `/etc/vmware/${device}` + // Build the base path to configuration for specified device: + // `/etc/vmware/${device}` devicebase := filepath.Join(base, device) - // Walk through a list of paths searching for the correct permutation... - // ...as it appears that in >= WS14 and < WS14, the leases file may be labelled differently. - - // Docs say we should expect: dhcpd/dhcpd.leases + // Iterate through a list of paths searching for the correct permutation. + // The default is dhcpd.leases, per the product documentation, but this + // will check for a few variations. paths := []string{"dhcpd/dhcpd.leases", "dhcpd/dhcp.leases", "dhcp/dhcpd.leases", "dhcp/dhcp.leases"} for _, p := range paths { fp := filepath.Join(devicebase, p) @@ -64,24 +65,24 @@ func playerDhcpLeasesPath(device string) string { } } - log.Printf("Error finding VMware DHCP Server Leases (dhcpd.leases) under device path: %s", devicebase) + log.Printf("Error finding 'dhcpd.leases' in device path: %s", devicebase) return "" } func playerVmDhcpConfPath(device string) string { base, err := playerVMwareRoot() if err != nil { - log.Printf("Error finding VMware root: %s", err) + log.Printf("Error finding the configuration root path: %s", err) return "" } - // Build the base path to VMware configuration for specified device: `/etc/vmware/${device}` + // Build the base path to configuration for specified device: + // `/etc/vmware/${device}` devicebase := filepath.Join(base, device) - // Walk through a list of paths searching for the correct permutation... - // ...as it appears that in >= WS14 and < WS14, the dhcp config may be labelled differently. - - // Docs say we should expect: dhcp/dhcp.conf + // Iterate through a list of paths searching for the correct permutation. + // The default is dhcp/dhcp.conf, per the product documentation, but this + // will check for a few variations. paths := []string{"dhcp/dhcp.conf", "dhcp/dhcpd.conf", "dhcpd/dhcp.conf", "dhcpd/dhcpd.conf"} for _, p := range paths { fp := filepath.Join(devicebase, p) @@ -90,14 +91,14 @@ func playerVmDhcpConfPath(device string) string { } } - log.Printf("Error finding VMware DHCP Server Configuration (dhcp.conf) under device path: %s", devicebase) + log.Printf("Error finding 'dhcp.conf' in device path: %s", devicebase) return "" } func playerVmnetnatConfPath(device string) string { base, err := playerVMwareRoot() if err != nil { - log.Printf("Error finding VMware root: %s", err) + log.Printf("Error finding the configuration root path: %s", err) return "" } return filepath.Join(base, device, "nat/nat.conf") @@ -106,7 +107,7 @@ func playerVmnetnatConfPath(device string) string { func playerNetmapConfPath() string { base, err := playerVMwareRoot() if err != nil { - log.Printf("Error finding VMware root: %s", err) + log.Printf("Error finding the configuration root path: %s", err) return "" } return filepath.Join(base, "netmap.conf") @@ -114,10 +115,9 @@ func playerNetmapConfPath() string { func playerVerifyVersion(version string) error { if runtime.GOOS != "linux" { - return fmt.Errorf("driver is only supported on Linux and Windows, not %s", runtime.GOOS) + return fmt.Errorf("driver is only supported on linux and windows, not %s", runtime.GOOS) } - //TODO: Is there is a better way to find this? // Using the default. vmxpath := "/usr/lib/vmware/bin/vmware-vmx" @@ -131,9 +131,9 @@ func playerVerifyVersion(version string) error { versionRe := regexp.MustCompile(`(?i)VMware Player (\d+)\.`) matches := versionRe.FindStringSubmatch(stderr.String()) if matches == nil { - return fmt.Errorf("error parsing version output: %s", stderr.String()) + return fmt.Errorf("error parsing version from output: %s", stderr.String()) } - log.Printf("Detected VMware Player version: %s", matches[1]) + log.Printf("VMware Workstation Player: %s", matches[1]) return compareVersions(matches[1], version, "Player") } diff --git a/builder/vmware/common/driver_player5_windows.go b/builder/vmware/common/driver_player_windows.go similarity index 77% rename from builder/vmware/common/driver_player5_windows.go rename to builder/vmware/common/driver_player_windows.go index b3dd3d55..bb488f5f 100644 --- a/builder/vmware/common/driver_player5_windows.go +++ b/builder/vmware/common/driver_player_windows.go @@ -6,13 +6,17 @@ package common import ( + "fmt" "log" "os" "os/exec" "path/filepath" + "regexp" "syscall" ) +// VMware Workstation Player for Windows. + func playerFindVdiskManager() (string, error) { path, err := exec.LookPath("vmware-vdiskmanager.exe") if err == nil { @@ -54,9 +58,10 @@ func playerToolsIsoPath(flavor string) string { } func playerDhcpLeasesPath(device string) string { + // Not used on Windows. path, err := playerDhcpLeasesPathRegistry() if err != nil { - log.Printf("Error finding leases in registry: %s", err) + log.Printf("Error retrieving DHCP leases path from registry: %s", err) } else if _, err := os.Stat(path); err == nil { return path } @@ -64,7 +69,7 @@ func playerDhcpLeasesPath(device string) string { } func playerVmDhcpConfPath(device string) string { - // the device isn't actually used on windows hosts + // Not used on Windows. path, err := playerDhcpConfigPathRegistry() if err != nil { log.Printf("Error finding configuration in registry: %s", err) @@ -75,7 +80,7 @@ func playerVmDhcpConfPath(device string) string { } func playerVmnetnatConfPath(device string) string { - // the device isn't actually used on windows hosts + // Not used on Windows. return findFile("vmnetnat.conf", playerDataFilePaths()) } @@ -83,7 +88,7 @@ func playerNetmapConfPath() string { return findFile("netmap.conf", playerDataFilePaths()) } -// This reads the VMware installation path from the Windows registry. +// Read the installation path from the registry. func playerVMwareRoot() (s string, err error) { key := `SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\vmplayer.exe` subkey := "Path" @@ -96,7 +101,7 @@ func playerVMwareRoot() (s string, err error) { return normalizePath(s), nil } -// This reads the VMware DHCP leases path from the Windows registry. +// Read the DHCP leases path from the registry. func playerDhcpLeasesPathRegistry() (s string, err error) { key := "SYSTEM\\CurrentControlSet\\services\\VMnetDHCP\\Parameters" subkey := "LeaseFile" @@ -108,7 +113,7 @@ func playerDhcpLeasesPathRegistry() (s string, err error) { return normalizePath(s), nil } -// This reads the VMware DHCP configuration path from the Windows registry. +// Read the DHCP configuration path from the registry. func playerDhcpConfigPathRegistry() (s string, err error) { key := "SYSTEM\\CurrentControlSet\\services\\VMnetDHCP\\Parameters" subkey := "ConfFile" @@ -121,11 +126,11 @@ func playerDhcpConfigPathRegistry() (s string, err error) { } // playerProgramFilesPaths returns a list of paths that are eligible -// to contain program files we may want just as vmware.exe. +// to contain program files. func playerProgramFilePaths() []string { path, err := playerVMwareRoot() if err != nil { - log.Printf("Error finding VMware root: %s", err) + log.Printf("Error finding the configuration root path: %s", err) } paths := make([]string, 0, 5) @@ -174,7 +179,7 @@ func playerProgramFilePaths() []string { func playerDataFilePaths() []string { leasesPath, err := playerDhcpLeasesPathRegistry() if err != nil { - log.Printf("Error getting DHCP leases path: %s", err) + log.Printf("Error retrieving DHCP leases path from registry: %s", err) } if leasesPath != "" { @@ -202,3 +207,27 @@ func playerDataFilePaths() []string { return paths } + +func playerVerifyVersion(version string) error { + key := `SOFTWARE\Wow6432Node\VMware, Inc.\VMware Player` + subkey := "ProductVersion" + productVersion, err := readRegString(syscall.HKEY_LOCAL_MACHINE, key, subkey) + if err != nil { + log.Printf(`Unable to read registry key %s\%s`, key, subkey) + key = `SOFTWARE\VMware, Inc.\VMware Player` + productVersion, err = readRegString(syscall.HKEY_LOCAL_MACHINE, key, subkey) + if err != nil { + log.Printf(`Unable to read registry key %s\%s`, key, subkey) + return err + } + } + + versionRe := regexp.MustCompile(`^(\d+)\.`) + matches := versionRe.FindStringSubmatch(productVersion) + if matches == nil { + return fmt.Errorf("error retrieving the version from registry key %s\\%s: '%s'", key, subkey, productVersion) + } + log.Printf("VMware Workstation Player: %s", matches[1]) + + return compareVersions(matches[1], version, "Player") +}