diff --git a/builder/vmware/common/driver.go b/builder/vmware/common/driver.go index 454e5587..e5be9990 100644 --- a/builder/vmware/common/driver.go +++ b/builder/vmware/common/driver.go @@ -23,16 +23,39 @@ 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. + productPreviewRegex = `(?i)VMware [a-z0-9-]+ e\.x\.p ` + productVersionRegex = `(?i)VMware [a-z0-9-]+ (\d+\.\d+\.\d+)` + ovfToolVersionRegex = `\d+\.\d+\.\d+` ) // 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 +143,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 +163,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 +222,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 +232,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 +251,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 +393,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 +481,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 +697,7 @@ func CheckOvfToolVersion(ovftoolPath string) error { versionOutput := string(output) log.Printf("Returned ovftool version: %s.", versionOutput) - versionString := ovfToolVersionRegex.FindString(versionOutput) + versionString := regexp.MustCompile(ovfToolVersionRegex).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..0f533ede --- /dev/null +++ b/builder/vmware/common/driver_fusion.go @@ -0,0 +1,354 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package common + +import ( + "bytes" + "fmt" + "log" + "os" + "os/exec" + "path/filepath" + "regexp" + "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)) + } + + re := regexp.MustCompile(productVersionRegex) + versionString := re.FindStringSubmatch(versionStr.String()) + if len(versionString) < 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(versionString[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 := regexp.MustCompile(productPreviewRegex).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. + matches := regexp.MustCompile(productVersionRegex).FindStringSubmatch(stderr.String()) + if matches == nil { + return nil, fmt.Errorf("error parsing version from output: %s", stderr.String()) + } + + versionStr := matches[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 -}