Skip to content

Commit

Permalink
refactor: consolidate player driver
Browse files Browse the repository at this point in the history
Consolidates `Player5Driver` and `Player6Driver` to `PlayerDriver` within `driver_player.go`.

Signed-off-by: Ryan Johnson <ryan@tenthirtyam.org>
  • Loading branch information
tenthirtyam committed Sep 24, 2024
1 parent 448c054 commit 5b336cb
Show file tree
Hide file tree
Showing 7 changed files with 363 additions and 416 deletions.
45 changes: 40 additions & 5 deletions builder/vmware/common/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const (

// Operating systems.
osWindows = "windows"
osLinux = "linux"

// Clone types.
cloneTypeLinked = "linked"
Expand All @@ -43,16 +44,41 @@ const (
guiArgumentGUI = "gui"

// Application binary names.
appOvfTool = "ovftool"
appPlayer = "vmplayer"
appVdiskManager = "vmware-vdiskmanager"
appVmrun = "vmrun"
appVmx = "vmware-vmx"
appQemuImg = "qemu-img"

// Version Regular Expressions.
// Version regular expressions.
productVersionRegex = `(?i)VMware [a-z0-9-]+ (\d+\.\d+\.\d+)`
technicalPreviewRegex = `(?i)VMware [a-z0-9-]+ e\.x\.p `
ovfToolVersionRegex = `\d+\.\d+\.\d+`

// File names.
dhcpVmnetConfFile = "vmnetdhcp.conf"
dhcpVmnetLeasesFile = "vmnetdhcp.leases"
natVmnetConfFile = "vmnetnat.conf"
netmapConfFile = "netmap.conf"
)

// The possible paths to the DHCP leases file.
var dhcpLeasesPaths = []string{
"dhcp/dhcp.leases",
"dhcp/dhcpd.leases",
"dhcpd/dhcp.leases",
"dhcpd/dhcpd.leases",
}

// The possible paths to the DHCP configuration file.
var dhcpConfPaths = []string{
"dhcp/dhcp.conf",
"dhcp/dhcpd.conf",
"dhcpd/dhcp.conf",
"dhcpd/dhcpd.conf",
}

// The product version.
var productVersion = regexp.MustCompile(productVersionRegex)

Expand Down Expand Up @@ -160,8 +186,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("error finding a driver for %s", runtime.GOOS)
Expand Down Expand Up @@ -683,9 +708,19 @@ func (d *VmwareDriver) HostIP(state multistep.StateBag) (string, error) {
return "", fmt.Errorf("unable to find host IP from devices %v, last error: %s", devices, lastError)
}

// GetDhcpLeasesPaths returns a copy of the DHCP leases paths.
func GetDhcpLeasesPaths() []string {
return append([]string(nil), dhcpLeasesPaths...)
}

// GetDhcpConfPaths returns a copy of the DHCP configuration paths.
func GetDhcpConfPaths() []string {
return append([]string(nil), dhcpConfPaths...)
}

func GetOvfTool() string {
ovftool := "ovftool"
if runtime.GOOS == "windows" {
ovftool := appOvfTool
if runtime.GOOS == osWindows {
ovftool += ".exe"
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
package common

import (
"errors"
"fmt"
"log"
"os"
Expand All @@ -15,30 +14,36 @@ import (
"github.com/hashicorp/packer-plugin-sdk/multistep"
)

// Player5Driver is a driver that can run VMware Player 5 on Linux.
type Player5Driver struct {
const (
// VMware Workstation Player application name.
playerProductName = "VMware Workstation Player"

// VMware Workstation Player versions.
// TODO: Update to best effort comply with the Broadcom Product Lifecycle.
minimumPlayerVersion = "6.0.0"
)

// PlayerDriver is a driver for VMware Workstation Player.
type PlayerDriver struct {
VmwareDriver

AppPath string
// The path to VMware Workstation Player.
AppPath string

VdiskManagerPath string
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 *Player5Driver) CompactDisk(diskPath string) error {
func (d *PlayerDriver) CompactDisk(diskPath string) error {
if d.QemuImgPath != "" {
return d.qemuCompactDisk(diskPath)
}
Expand All @@ -56,7 +61,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
Expand All @@ -73,7 +78,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)
Expand All @@ -87,13 +92,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
Expand All @@ -114,14 +119,14 @@ 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 {
guiArgument := "gui"
if headless {
guiArgument = "nogui"
func (d *PlayerDriver) Start(vmxPath string, headless bool) error {
guiArgument := guiArgumentNoGUI
if !headless {
guiArgument = guiArgumentGUI
}

cmd := exec.Command(d.VmrunPath, "-T", "player", "start", vmxPath, guiArgument)
Expand All @@ -132,32 +137,43 @@ 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 {
// Check if the virtual machine is running. If not, it is stopped.
running, runningErr := d.IsRunning(vmxPath)
if runningErr == nil && !running {
return nil
}

return err
}

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

log.Printf("[INFO] Checking %s paths...", playerProductName)

if d.AppPath == "" {
if d.AppPath, err = playerFindVMware(); err != nil {
return err
if d.AppPath, err = playerFindVmplayer(); err != nil {
return fmt.Errorf("%s not found: %s", playerProductName, err)
}
}
log.Printf("- %s app path: %s", playerProductName, d.AppPath)

if d.VmrunPath == "" {
if d.VmrunPath, err = playerFindVmrun(); err != nil {
return err
return fmt.Errorf("%s not found: %s", appVmrun, err)
}
}
log.Printf("- %s found at: %s", appVmrun, d.VmrunPath)

if d.VdiskManagerPath == "" {
d.VdiskManagerPath, err = playerFindVdiskManager()
Expand All @@ -168,30 +184,44 @@ func (d *Player5Driver) Verify() error {
}

if err != nil {
return fmt.Errorf("error finding either 'vmware-vdiskmanager' or 'qemu-img' in path")
return fmt.Errorf("error finding either %s or %s: %s", appVdiskManager, appQemuImg, err)
}

log.Printf("VMware app path: %s", d.AppPath)
log.Printf("vmrun path: %s", d.VmrunPath)
log.Printf("vdisk-manager path: %s", d.VdiskManagerPath)
log.Printf("qemu-img path: %s", d.QemuImgPath)
log.Printf("- %s found at: %s", appVdiskManager, d.VdiskManagerPath)
log.Printf("- %s found at: %s", appQemuImg, d.QemuImgPath)

if _, err := os.Stat(d.AppPath); err != nil {
return fmt.Errorf("player not found in path: %s", d.AppPath)
if os.IsNotExist(err) {
return fmt.Errorf("%s not found at: %s", playerProductName, d.AppPath)
}
return err
}
log.Printf("- %s found at: %s", playerProductName, d.AppPath)

if _, err := os.Stat(d.VmrunPath); err != nil {
return fmt.Errorf("'vmrun' not found in path: %s", d.VmrunPath)
if os.IsNotExist(err) {
return fmt.Errorf("%s not found at: %s", appVmrun, d.VmrunPath)
}
return err
}
log.Printf("- %s found at: %s", appVmrun, d.VmrunPath)

if d.VdiskManagerPath != "" {
_, err = os.Stat(d.VdiskManagerPath)
if _, err := os.Stat(d.VdiskManagerPath); err != nil {
if os.IsNotExist(err) {
return fmt.Errorf("%s not found at: %s", appVdiskManager, d.VdiskManagerPath)
}
return err
}
log.Printf("- %s found at: %s", appVdiskManager, d.VdiskManagerPath)
} else {
_, err = os.Stat(d.QemuImgPath)
}

if err != nil {
return fmt.Errorf("error finding either 'vmware-vdiskmanager' or 'qemu-img' in path: %s", d.VdiskManagerPath)
if _, err := os.Stat(d.QemuImgPath); err != nil {
if os.IsNotExist(err) {
return fmt.Errorf("%s not found at: %s", appQemuImg, d.QemuImgPath)
}
return err
}
log.Printf("- %s found at: %s", appQemuImg, d.QemuImgPath)
}

// Assigning the path callbacks to VmwareDriver
Expand All @@ -210,43 +240,59 @@ func (d *Player5Driver) Verify() error {
d.VmwareDriver.NetworkMapper = func() (NetworkNameMapper, error) {
pathNetmap := playerNetmapConfPath()

// If we were able to find the file (no error), then we can proceed with reading
// the networkmapper configuration.
if _, err := os.Stat(pathNetmap); err == nil {
log.Printf("Located networkmapper configuration file: %s", pathNetmap)
log.Printf("Found: %s", pathNetmap)
return ReadNetmapConfig(pathNetmap)
}

// If we weren't able to find the networkmapper configuration file, then fall back
// to the networking file which might also be in the configuration directory.
libpath, _ := playerVMwareRoot()
libpath, _ := playerInstallationPath()
pathNetworking := filepath.Join(libpath, "networking")
if _, err := os.Stat(pathNetworking); err != nil {
return nil, fmt.Errorf("error determining network mappings from files in path: %s", libpath)
return nil, fmt.Errorf("not found: %s", pathNetworking)
}

// We were able to successfully stat the file.. So, now we can open a handle to it.
log.Printf("Located networking configuration file: %s", pathNetworking)
log.Printf("Found: %s", pathNetworking)
fd, err := os.Open(pathNetworking)
if err != nil {
return nil, err
}
defer fd.Close()

// Then we pass the handle to the networking configuration parser.
return ReadNetworkingConfig(fd)
}
return nil

return playerVerifyVersion(minimumPlayerVersion)
}

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 *PlayerDriver) Clone(dst, src string, linked bool, snapshot string) error {
var cloneType string

if linked {
cloneType = cloneTypeLinked
} else {
cloneType = cloneTypeFull
}

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) GetVmwareDriver() VmwareDriver {
func (d *PlayerDriver) GetVmwareDriver() VmwareDriver {
return d.VmwareDriver
}
Loading

0 comments on commit 5b336cb

Please sign in to comment.