Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: consolidate player driver #231

Merged
merged 1 commit into from
Oct 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 {
tenthirtyam marked this conversation as resolved.
Show resolved Hide resolved
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