diff --git a/builder/vmware/common/driver.go b/builder/vmware/common/driver.go
index 454e5587..cc1ed296 100644
--- a/builder/vmware/common/driver.go
+++ b/builder/vmware/common/driver.go
@@ -23,16 +23,48 @@ import (
)
const (
+ // OVF Tool.
ovfToolDownloadURL = "https://developer.broadcom.com/tools/open-virtualization-format-ovf-tool/latest"
ovfToolMinVersion = "4.6.0"
+
+ // Architectures.
+ archAMD64 = "x86_x64"
+ archARM64 = "arm64"
+
+ // Operating systems.
+ osWindows = "windows"
+
+ // Clone types.
+ cloneTypeLinked = "linked"
+ cloneTypeFull = "full"
+
+ // GUI arguments.
+ guiArgumentNoGUI = "nogui"
+ guiArgumentGUI = "gui"
+
+ // Application binary names.
+ appVdiskManager = "vmware-vdiskmanager"
+ appVmrun = "vmrun"
+ appVmx = "vmware-vmx"
+
+ // 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+`
)
+// The product version.
+var productVersion = regexp.MustCompile(productVersionRegex)
+
+// The technical preview version.
+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 regex to match the version of the VMware OVF Tool.
-var ovfToolVersionRegex = regexp.MustCompile(`\d+\.\d+\.\d+`)
-
// 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
@@ -120,8 +152,7 @@ func NewDriver(dconfig *DriverConfig, config *SSHConfig, vmName string) (Driver,
switch runtime.GOOS {
case "darwin":
drivers = []Driver{
- NewFusion6Driver(dconfig, config),
- NewFusion5Driver(dconfig, config),
+ NewFusionDriver(dconfig, config),
}
case "linux":
fallthrough
@@ -141,12 +172,12 @@ func NewDriver(dconfig *DriverConfig, config *SSHConfig, vmName string) (Driver,
for _, driver := range drivers {
err := driver.Verify()
- log.Printf("Testing against driver %T, Success: %t", driver, err == nil)
+ log.Printf("Using driver %T, Success: %t", driver, err == nil)
if err == nil {
return driver, nil
}
- log.Printf("skipping %T because it failed with the following error %s", driver, err)
+ log.Printf("Skipping %T because it failed with the following error %s", driver, err)
errs += "* " + err.Error() + "\n"
}
@@ -200,6 +231,7 @@ 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 {
@@ -209,6 +241,7 @@ func normalizeVersion(version string) (string, error) {
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 {
@@ -227,6 +260,13 @@ func compareVersions(versionFound string, versionWanted string, product string)
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())
+ }
+ return nil
+}
+
// helper functions that read configuration information from a file
// read the network<->device configuration out of the specified path
func ReadNetmapConfig(path string) (NetworkMap, error) {
@@ -362,7 +402,7 @@ func (d *VmwareDriver) PotentialGuestIP(state multistep.StateBag) ([]string, err
}
// iterate through all of the devices and collect all the dhcp lease entries
- // that we possibly cacn.
+ // that we possibly can.
var available_lease_entries []dhcpLeaseEntry
for _, device := range devices {
@@ -450,7 +490,6 @@ func (d *VmwareDriver) PotentialGuestIP(state multistep.StateBag) ([]string, err
// We have match no vmware DHCP lease for this MAC. We'll try to match it in Apple DHCP leases.
// As a remember, VMware is no longer able to rely on its own dhcpd server on MacOS BigSur and is
// forced to use Apple DHCPD server instead.
- // https://communities.vmware.com/t5/VMware-Fusion-Discussions/Big-Sur-hosts-with-Fusion-Is-vmnet-dhcpd-vmnet8-leases-file/m-p/2298927/highlight/true#M140003
// set the apple dhcp leases path
appleDhcpLeasesPath := "/var/db/dhcpd_leases"
@@ -667,7 +706,7 @@ func CheckOvfToolVersion(ovftoolPath string) error {
versionOutput := string(output)
log.Printf("Returned ovftool version: %s.", versionOutput)
- versionString := ovfToolVersionRegex.FindString(versionOutput)
+ versionString := ovfToolVersion.FindString(versionOutput)
if versionString == "" {
return errors.New("unable to determine the version of ovftool")
}
diff --git a/builder/vmware/common/driver_fusion.go b/builder/vmware/common/driver_fusion.go
new file mode 100644
index 00000000..e3d84368
--- /dev/null
+++ b/builder/vmware/common/driver_fusion.go
@@ -0,0 +1,352 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package common
+
+import (
+ "bytes"
+ "fmt"
+ "log"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "runtime"
+ "strings"
+
+ "github.com/hashicorp/go-version"
+ "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 = `
+
+
+
+ disallowUpgrade
+
+
+`
+
+// FusionDriver is a driver for VMware Fusion for macOS.
+type FusionDriver struct {
+ VmwareDriver
+
+ // The path to the "VMware Fusion.app"
+ AppPath string
+
+ SSHConfig *SSHConfig
+}
+
+func NewFusionDriver(dconfig *DriverConfig, config *SSHConfig) Driver {
+ return &FusionDriver{
+ AppPath: dconfig.FusionAppPath,
+ SSHConfig: config,
+ }
+}
+
+func (d *FusionDriver) CompactDisk(diskPath string) error {
+ 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 *FusionDriver) CreateDisk(output string, size string, adapter_type string, type_id string) error {
+ 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 *FusionDriver) CreateSnapshot(vmxPath string, snapshotName string) error {
+ cmd := exec.Command(d.vmrunPath(), "-T", "fusion", "snapshot", vmxPath, snapshotName)
+ _, _, err := runAndLog(cmd)
+ return err
+}
+
+func (d *FusionDriver) IsRunning(vmxPath string) (bool, error) {
+ vmxPath, err := filepath.Abs(vmxPath)
+ if err != nil {
+ return false, err
+ }
+
+ cmd := exec.Command(d.vmrunPath(), "-T", "fusion", "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 *FusionDriver) CommHost(state multistep.StateBag) (string, error) {
+ return CommHost(d.SSHConfig)(state)
+}
+
+func (d *FusionDriver) Start(vmxPath string, headless bool) error {
+ guiArgument := guiArgumentNoGUI
+ if !headless {
+ guiArgument = guiArgumentGUI
+ }
+
+ cmd := exec.Command(d.vmrunPath(), "-T", "fusion", "start", vmxPath, guiArgument)
+ if _, _, err := runAndLog(cmd); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (d *FusionDriver) Stop(vmxPath string) error {
+ cmd := exec.Command(d.vmrunPath(), "-T", "fusion", "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 *FusionDriver) SuppressMessages(vmxPath string) error {
+ dir := filepath.Dir(vmxPath)
+ base := filepath.Base(vmxPath)
+ base = strings.Replace(base, ".vmx", "", -1)
+
+ plistPath := filepath.Join(dir, base+".plist")
+ return os.WriteFile(plistPath, []byte(fusionSuppressPlist), 0644)
+}
+
+func (d *FusionDriver) libPath() string {
+ return filepath.Join("/", "Library", "Preferences", "VMware Fusion")
+}
+
+func (d *FusionDriver) binaryPath(binaryName string) string {
+ return filepath.Join(d.AppPath, "Contents", "Library", binaryName)
+}
+
+func (d *FusionDriver) toolsIsoPath(subdirs ...string) string {
+ parts := append([]string{d.AppPath, "Contents", "Library", "isoimages"}, subdirs...)
+ return filepath.Join(parts...)
+}
+
+func (d *FusionDriver) vmxPath() string {
+ return d.binaryPath(appVmx)
+}
+
+func (d *FusionDriver) vmrunPath() string {
+ return d.binaryPath(appVmrun)
+}
+
+func (d *FusionDriver) vdiskManagerPath() string {
+ return d.binaryPath(appVdiskManager)
+}
+
+func (d *FusionDriver) isoFileName(base string) string {
+ return base + ".iso"
+}
+
+func (d *FusionDriver) ToolsInstall() error {
+ return nil
+}
+
+func (d *FusionDriver) Clone(dst, src string, linked bool, snapshot string) error {
+ var cloneType string
+
+ if linked {
+ cloneType = cloneTypeLinked
+ } else {
+ cloneType = cloneTypeFull
+ }
+
+ args := []string{"-T", "fusion", "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 *FusionDriver) Verify() error {
+ version, err := d.getFusionVersion()
+ log.Printf("Checking %s version...", fusionProductName)
+ if err != nil {
+ return fmt.Errorf("error getting %s version: %s", fusionProductName, err)
+ }
+
+ log.Printf("%s: %s", fusionProductName, version)
+ log.Printf("Checking %s paths...", fusionProductName)
+
+ if _, err := os.Stat(d.AppPath); err != nil {
+ if os.IsNotExist(err) {
+ return fmt.Errorf("%s.app not found at: %s", fusionProductName, d.AppPath)
+ }
+
+ return err
+ }
+
+ log.Printf("- %s.app found at: %s", fusionProductName, d.AppPath)
+
+ if _, err := os.Stat(d.vmxPath()); err != nil {
+ if os.IsNotExist(err) {
+ return fmt.Errorf("%s not found at: %s", appVmx, d.vmxPath())
+ }
+
+ return err
+ }
+
+ log.Printf("- %s found at: %s", appVmx, d.vmxPath())
+
+ 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("- %s found at: %s", appVmrun, d.vmrunPath())
+
+ 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())
+
+ libpath := d.libPath()
+
+ d.VmwareDriver.DhcpLeasesPath = func(device string) string {
+ return "/var/db/vmware/vmnet-dhcpd-" + device + ".leases"
+ }
+
+ d.VmwareDriver.DhcpConfPath = func(device string) string {
+ return filepath.Join(libpath, device, "dhcpd.conf")
+ }
+
+ d.VmwareDriver.VmnetnatConfPath = func(device string) string {
+ return filepath.Join(libpath, device, "nat.conf")
+ }
+
+ d.VmwareDriver.NetworkMapper = func() (NetworkNameMapper, error) {
+ pathNetworking := filepath.Join(libpath, "networking")
+ if _, err := os.Stat(pathNetworking); err != nil {
+ return nil, fmt.Errorf("unable to locate networking configuration file: %s", pathNetworking)
+ }
+
+ fd, err := os.Open(pathNetworking)
+ if err != nil {
+ return nil, err
+ }
+ defer fd.Close()
+
+ return ReadNetworkingConfig(fd)
+ }
+
+ return compareVersionObjects(version, minimumFusionVersionObj, 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 {
+ arch = archARM64
+ }
+
+ return d.toolsIsoPath(arch, d.isoFileName(k))
+}
+
+func (d *FusionDriver) GetVmwareDriver() VmwareDriver {
+ return d.VmwareDriver
+}
+
+func (d *FusionDriver) getFusionVersion() (*version.Version, error) {
+ var stderr bytes.Buffer
+ cmd := exec.Command(d.vmxPath(), "-v")
+ cmd.Stderr = &stderr
+ if err := cmd.Run(); err != nil {
+ return nil, fmt.Errorf("error getting version: %w", err)
+ }
+
+ // Check for Tech Preview version.
+ if matches := technicalPreview.FindStringSubmatch(stderr.String()); matches != nil {
+ log.Printf("%s: e.x.p (Tech Preview)", fusionProductName)
+ return version.NewVersion("0.0.0-e.x.p")
+ }
+
+ // Check for generally available version.
+ versionMatch := productVersion.FindStringSubmatch(stderr.String())
+ if versionMatch == nil {
+ return nil, fmt.Errorf("error parsing version from output: %s", stderr.String())
+ }
+
+ versionStr := versionMatch[1]
+ parsedVersion, err := version.NewVersion(versionStr)
+ if err != nil {
+ return nil, fmt.Errorf("error parsing version: %w", err)
+ }
+
+ return parsedVersion, nil
+}
diff --git a/builder/vmware/common/driver_fusion5.go b/builder/vmware/common/driver_fusion5.go
deleted file mode 100644
index adc67abe..00000000
--- a/builder/vmware/common/driver_fusion5.go
+++ /dev/null
@@ -1,214 +0,0 @@
-// Copyright (c) HashiCorp, Inc.
-// SPDX-License-Identifier: MPL-2.0
-
-package common
-
-import (
- "errors"
- "fmt"
- "log"
- "os"
- "os/exec"
- "path/filepath"
- "strings"
-
- "github.com/hashicorp/packer-plugin-sdk/multistep"
-)
-
-// Fusion5Driver is a driver that can run VMware Fusion 5.
-type Fusion5Driver struct {
- VmwareDriver
-
- // This is the path to the "VMware Fusion.app"
- AppPath string
-
- // SSHConfig are the SSH settings for the Fusion VM
- SSHConfig *SSHConfig
-}
-
-func NewFusion5Driver(dconfig *DriverConfig, config *SSHConfig) Driver {
- return &Fusion5Driver{
- AppPath: dconfig.FusionAppPath,
- SSHConfig: config,
- }
-}
-
-func (d *Fusion5Driver) Clone(dst, src string, linked bool, snapshot string) error {
- return errors.New("linked clones are not supported on this version VMware Fusion, please upgrade")
-}
-
-func (d *Fusion5Driver) CompactDisk(diskPath string) error {
- 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 *Fusion5Driver) CreateDisk(output string, size string, adapter_type string, type_id string) error {
- 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 *Fusion5Driver) CreateSnapshot(vmxPath string, snapshotName string) error {
- cmd := exec.Command(d.vmrunPath(), "-T", "fusion", "snapshot", vmxPath, snapshotName)
- _, _, err := runAndLog(cmd)
- return err
-}
-
-func (d *Fusion5Driver) IsRunning(vmxPath string) (bool, error) {
- vmxPath, err := filepath.Abs(vmxPath)
- if err != nil {
- return false, err
- }
-
- cmd := exec.Command(d.vmrunPath(), "-T", "fusion", "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 *Fusion5Driver) CommHost(state multistep.StateBag) (string, error) {
- return CommHost(d.SSHConfig)(state)
-}
-
-func (d *Fusion5Driver) Start(vmxPath string, headless bool) error {
- guiArgument := "gui"
- if headless {
- guiArgument = "nogui"
- }
-
- cmd := exec.Command(d.vmrunPath(), "-T", "fusion", "start", vmxPath, guiArgument)
- if _, _, err := runAndLog(cmd); err != nil {
- return err
- }
-
- return nil
-}
-
-func (d *Fusion5Driver) Stop(vmxPath string) error {
- cmd := exec.Command(d.vmrunPath(), "-T", "fusion", "stop", vmxPath, "hard")
- if _, _, err := runAndLog(cmd); err != nil {
- // Check if the VM is running. If its not, it was already stopped
- running, rerr := d.IsRunning(vmxPath)
- if rerr == nil && !running {
- return nil
- }
-
- return err
- }
-
- return nil
-}
-
-func (d *Fusion5Driver) SuppressMessages(vmxPath string) error {
- dir := filepath.Dir(vmxPath)
- base := filepath.Base(vmxPath)
- base = strings.Replace(base, ".vmx", "", -1)
-
- plistPath := filepath.Join(dir, base+".plist")
- return os.WriteFile(plistPath, []byte(fusionSuppressPlist), 0644)
-}
-
-func (d *Fusion5Driver) Verify() error {
- if _, err := os.Stat(d.AppPath); err != nil {
- if os.IsNotExist(err) {
- return fmt.Errorf("fusion not found in path: %s", d.AppPath)
- }
-
- return err
- }
-
- if _, err := os.Stat(d.vmrunPath()); err != nil {
- if os.IsNotExist(err) {
- return fmt.Errorf("'vmrun' not found in path: %s", d.vmrunPath())
- }
-
- return err
- }
-
- if _, err := os.Stat(d.vdiskManagerPath()); err != nil {
- if os.IsNotExist(err) {
- return fmt.Errorf("error finding either 'vmware-vdiskmanager' or 'qemu-img' in path: %s", d.vdiskManagerPath())
- }
-
- return err
- }
-
- libpath := filepath.Join("/", "Library", "Preferences", "VMware Fusion")
-
- d.VmwareDriver.DhcpLeasesPath = func(device string) string {
- return "/var/db/vmware/vmnet-dhcpd-" + device + ".leases"
- }
- d.VmwareDriver.DhcpConfPath = func(device string) string {
- return filepath.Join(libpath, device, "dhcpd.conf")
- }
- d.VmwareDriver.VmnetnatConfPath = func(device string) string {
- return filepath.Join(libpath, device, "nat.conf")
- }
- d.VmwareDriver.NetworkMapper = func() (NetworkNameMapper, error) {
- pathNetworking := filepath.Join(libpath, "networking")
- if _, err := os.Stat(pathNetworking); err != nil {
- return nil, fmt.Errorf("error finding networking configuration file %q: %s", pathNetworking, err)
- }
- log.Printf("[INFO] Located networkmapper configuration file: %s", pathNetworking)
-
- fd, err := os.Open(pathNetworking)
- if err != nil {
- return nil, err
- }
- defer fd.Close()
-
- return ReadNetworkingConfig(fd)
- }
-
- return nil
-}
-
-func (d *Fusion5Driver) vdiskManagerPath() string {
- return filepath.Join(d.AppPath, "Contents", "Library", "vmware-vdiskmanager")
-}
-
-func (d *Fusion5Driver) vmrunPath() string {
- return filepath.Join(d.AppPath, "Contents", "Library", "vmrun")
-}
-
-func (d *Fusion5Driver) ToolsIsoPath(k string) string {
- return filepath.Join(d.AppPath, "Contents", "Library", "isoimages", k+".iso")
-}
-
-func (d *Fusion5Driver) ToolsInstall() error {
- return nil
-}
-
-const fusionSuppressPlist = `
-
-
-
- disallowUpgrade
-
-
-`
-
-func (d *Fusion5Driver) GetVmwareDriver() VmwareDriver {
- return d.VmwareDriver
-}
diff --git a/builder/vmware/common/driver_fusion6.go b/builder/vmware/common/driver_fusion6.go
deleted file mode 100644
index cbe4d75e..00000000
--- a/builder/vmware/common/driver_fusion6.go
+++ /dev/null
@@ -1,152 +0,0 @@
-// Copyright (c) HashiCorp, Inc.
-// SPDX-License-Identifier: MPL-2.0
-
-package common
-
-import (
- "bytes"
- "fmt"
- "log"
- "os"
- "os/exec"
- "path/filepath"
- "regexp"
- "runtime"
- "strings"
-)
-
-const VMWARE_FUSION_VERSION = "6"
-
-// Fusion6Driver is a driver that can run VMware Fusion 6.
-type Fusion6Driver struct {
- Fusion5Driver
-}
-
-func NewFusion6Driver(dconfig *DriverConfig, config *SSHConfig) Driver {
- return &Fusion6Driver{
- Fusion5Driver: Fusion5Driver{
- AppPath: dconfig.FusionAppPath,
- SSHConfig: config,
- },
- }
-}
-
-func (d *Fusion6Driver) Clone(dst, src string, linked bool, snapshot string) error {
-
- var cloneType string
- if linked {
- cloneType = "linked"
- } else {
- cloneType = "full"
- }
-
- args := []string{"-T", "fusion", "clone", src, dst, cloneType}
- if snapshot != "" {
- args = append(args, "-snapshot", snapshot)
- }
- cmd := exec.Command(d.vmrunPath(), args...)
- if _, _, err := runAndLog(cmd); err != nil {
- if strings.Contains(err.Error(), "parameters was invalid") {
- return fmt.Errorf("linked clones are not supported on this version")
- }
-
- return err
- }
-
- return nil
-}
-
-func (d *Fusion6Driver) Verify() error {
- if err := d.Fusion5Driver.Verify(); err != nil {
- return err
- }
-
- vmxpath := filepath.Join(d.AppPath, "Contents", "Library", "vmware-vmx")
- if _, err := os.Stat(vmxpath); err != nil {
- if os.IsNotExist(err) {
- return fmt.Errorf("'vmware-vmx' not found in path: %s", vmxpath)
- }
-
- return err
- }
-
- var stderr bytes.Buffer
- cmd := exec.Command(vmxpath, "-v")
- cmd.Stderr = &stderr
- if err := cmd.Run(); err != nil {
- return err
- }
-
- // Example: VMware Fusion e.x.p build-6048684 Release
- techPreviewRe := regexp.MustCompile(`(?i)VMware [a-z0-9-]+ e\.x\.p `)
- matches := techPreviewRe.FindStringSubmatch(stderr.String())
- if matches != nil {
- log.Printf("Detected VMware version: e.x.p (Tech Preview)")
- return nil
- }
-
- // Example: VMware Fusion 7.1.3 build-3204469 Release
- versionRe := regexp.MustCompile(`(?i)VMware [a-z0-9-]+ (\d+)\.`)
- matches = versionRe.FindStringSubmatch(stderr.String())
- if matches == nil {
- return fmt.Errorf("error parsing version output: %s", stderr.String())
- }
- log.Printf("Detected VMware version: %s", matches[1])
-
- libpath := filepath.Join("/", "Library", "Preferences", "VMware Fusion")
-
- d.VmwareDriver.DhcpLeasesPath = func(device string) string {
- return "/var/db/vmware/vmnet-dhcpd-" + device + ".leases"
- }
- d.VmwareDriver.DhcpConfPath = func(device string) string {
- return filepath.Join(libpath, device, "dhcpd.conf")
- }
-
- d.VmwareDriver.VmnetnatConfPath = func(device string) string {
- return filepath.Join(libpath, device, "nat.conf")
- }
- d.VmwareDriver.NetworkMapper = func() (NetworkNameMapper, error) {
- pathNetworking := filepath.Join(libpath, "networking")
- if _, err := os.Stat(pathNetworking); err != nil {
- return nil, fmt.Errorf("error finding networking configuration file: %s", pathNetworking)
- }
- log.Printf("Located networkmapper configuration file: %s", pathNetworking)
-
- fd, err := os.Open(pathNetworking)
- if err != nil {
- return nil, err
- }
- defer fd.Close()
-
- return ReadNetworkingConfig(fd)
- }
-
- return compareVersions(matches[1], VMWARE_FUSION_VERSION, "Fusion Professional")
-}
-
-func (d *Fusion6Driver) ToolsIsoPath(k string) string {
- // Fusion 13.x.x changes tools iso location
- vmxpath := filepath.Join(d.AppPath, "Contents", "Library", "vmware-vmx")
- var stderr bytes.Buffer
- cmd := exec.Command(vmxpath, "-v")
- cmd.Stderr = &stderr
- if err := cmd.Run(); err != nil {
- log.Printf("[DEBUG] failed to execute vmware-vmx command to get version %s", err)
- log.Printf("[DEBUG] continuing with default iso path for fusion6+.")
- return filepath.Join(d.AppPath, "Contents", "Library", "isoimages", "x86_x64", k+".iso")
- }
- versionRe := regexp.MustCompile(`(?i)VMware [a-z0-9-]+ (\d+)\.`)
- matches := versionRe.FindStringSubmatch(stderr.String())
- if len(matches) > 0 && (matches[1] < "13") {
- return filepath.Join(d.AppPath, "Contents", "Library", "isoimages", k+".iso")
- }
- if k == "windows" && runtime.GOARCH == "arm64" {
- return filepath.Join(d.AppPath, "Contents", "Library", "isoimages", "arm64", k+".iso")
- }
-
- return filepath.Join(d.AppPath, "Contents", "Library", "isoimages", "x86_x64", k+".iso")
-}
-
-func (d *Fusion6Driver) GetVmwareDriver() VmwareDriver {
- return d.Fusion5Driver.VmwareDriver
-}