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 authored and lbajolet-hashicorp committed Oct 7, 2024
1 parent 448c054 commit 3b080bf
Show file tree
Hide file tree
Showing 8 changed files with 559 additions and 614 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
298 changes: 298 additions & 0 deletions builder/vmware/common/driver_player.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,298 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package common

import (
"fmt"
"log"
"os"
"os/exec"
"path/filepath"
"strings"

"github.com/hashicorp/packer-plugin-sdk/multistep"
)

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

// The path to VMware Workstation Player.
AppPath string

VdiskManagerPath string
QemuImgPath string
VmrunPath string

SSHConfig *SSHConfig
}

func NewPlayerDriver(config *SSHConfig) Driver {
return &PlayerDriver{
SSHConfig: config,
}
}

func (d *PlayerDriver) CompactDisk(diskPath string) error {
if d.QemuImgPath != "" {
return d.qemuCompactDisk(diskPath)
}

defragCmd := exec.Command(d.VdiskManagerPath, "-d", diskPath)
if _, _, err := runAndLog(defragCmd); err != nil {
return err
}

shrinkCmd := exec.Command(d.VdiskManagerPath, "-k", diskPath)
if _, _, err := runAndLog(shrinkCmd); err != nil {
return err
}

return nil
}

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
}

if err := os.Remove(diskPath); err != nil {
return err
}

if err := os.Rename(diskPath+".new", diskPath); err != nil {
return err
}

return nil
}

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)
} else {
cmd = exec.Command(d.VdiskManagerPath, "-c", "-s", size, "-a", adapter_type, "-t", type_id, output)
}
if _, _, err := runAndLog(cmd); err != nil {
return err
}

return nil
}

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 *PlayerDriver) IsRunning(vmxPath string) (bool, error) {
vmxPath, err := filepath.Abs(vmxPath)
if err != nil {
return false, err
}

cmd := exec.Command(d.VmrunPath, "-T", "player", "list")
stdout, _, err := runAndLog(cmd)
if err != nil {
return false, err
}

for _, line := range strings.Split(stdout, "\n") {
if line == vmxPath {
return true, nil
}
}

return false, nil
}

func (d *PlayerDriver) CommHost(state multistep.StateBag) (string, error) {
return CommHost(d.SSHConfig)(state)
}

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)
if _, _, err := runAndLog(cmd); err != nil {
return err
}

return nil
}

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 *PlayerDriver) SuppressMessages(vmxPath string) error {
return nil
}

func (d *PlayerDriver) Verify() error {
var err error

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

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

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

if d.VdiskManagerPath == "" {
d.VdiskManagerPath, err = playerFindVdiskManager()
}

if d.VdiskManagerPath == "" && d.QemuImgPath == "" {
d.QemuImgPath, err = playerFindQemuImg()
}

if err != nil {
return fmt.Errorf("error finding either %s or %s: %s", appVdiskManager, appQemuImg, err)
}

log.Printf("[INFO] - %s found at: %s", appVdiskManager, d.VdiskManagerPath)
log.Printf("[INFO] - %s found at: %s", appQemuImg, d.QemuImgPath)

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

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

if 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("[INFO] - %s found at: %s", appVdiskManager, d.VdiskManagerPath)
} else {
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("[INFO] - %s found at: %s", appQemuImg, d.QemuImgPath)
}

// Assigning the path callbacks to VmwareDriver
d.VmwareDriver.DhcpLeasesPath = func(device string) string {
return playerDhcpLeasesPath(device)
}

d.VmwareDriver.DhcpConfPath = func(device string) string {
return playerVmDhcpConfPath(device)
}

d.VmwareDriver.VmnetnatConfPath = func(device string) string {
return playerVmnetnatConfPath(device)
}

d.VmwareDriver.NetworkMapper = func() (NetworkNameMapper, error) {
pathNetmap := playerNetmapConfPath()

if _, err := os.Stat(pathNetmap); err == nil {
log.Printf("[INFO] Found: %s", pathNetmap)
return ReadNetmapConfig(pathNetmap)
}

libpath, _ := playerInstallationPath()
pathNetworking := filepath.Join(libpath, "networking")
if _, err := os.Stat(pathNetworking); err != nil {
return nil, fmt.Errorf("not found: %s", pathNetworking)
}

log.Printf("[INFO] Found: %s", pathNetworking)
fd, err := os.Open(pathNetworking)
if err != nil {
return nil, err
}
defer fd.Close()

return ReadNetworkingConfig(fd)
}

return playerVerifyVersion(minimumPlayerVersion)
}

func (d *PlayerDriver) ToolsIsoPath(flavor string) string {
return playerToolsIsoPath(flavor)
}

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

0 comments on commit 3b080bf

Please sign in to comment.