diff --git a/builder/vmware/common/driver.go b/builder/vmware/common/driver.go index f0f53a150..6e879e5f6 100644 --- a/builder/vmware/common/driver.go +++ b/builder/vmware/common/driver.go @@ -6,6 +6,7 @@ import ( "log" "os/exec" "runtime" + "strconv" "strings" "github.com/mitchellh/multistep" @@ -89,6 +90,11 @@ func NewDriver(dconfig *DriverConfig, config *SSHConfig) (Driver, error) { } case "windows": drivers = []Driver{ + &Workstation10Driver{ + Workstation9Driver: Workstation9Driver{ + SSHConfig: config, + }, + }, &Workstation9Driver{ SSHConfig: config, }, @@ -137,3 +143,32 @@ func runAndLog(cmd *exec.Cmd) (string, string, error) { return returnStdout, returnStderr, err } + +func normalizeVersion(version string) (string, error) { + i, err := strconv.Atoi(version) + if err != nil { + return "", fmt.Errorf( + "VMWare WS version '%s' is not numeric", version) + } + + return fmt.Sprintf("%02d", i), nil +} + +func compareVersions(versionFound string, versionWanted string) error { + found, err := normalizeVersion(versionFound) + if err != nil { + return err + } + + wanted, err := normalizeVersion(versionWanted) + if err != nil { + return err + } + + if found < wanted { + return fmt.Errorf( + "VMWare WS %s, or greater, is required. Found version: %s", versionWanted, versionFound) + } + + return nil +} diff --git a/builder/vmware/common/driver_workstation10.go b/builder/vmware/common/driver_workstation10.go index be127356d..7e6ac8b8f 100644 --- a/builder/vmware/common/driver_workstation10.go +++ b/builder/vmware/common/driver_workstation10.go @@ -1,17 +1,13 @@ package common import ( - "bytes" - "fmt" - "log" "os/exec" - "regexp" - "runtime" - "strings" ) +const VMWARE_WS_VERSION = "10" + // Workstation10Driver is a driver that can run VMware Workstation 10 -// installations. Current only tested for UNIX +// installations. type Workstation10Driver struct { Workstation9Driver @@ -31,37 +27,9 @@ func (d *Workstation10Driver) Clone(dst, src string) error { } func (d *Workstation10Driver) Verify() error { - if runtime.GOOS != "linux" { - return fmt.Errorf("WS10 driver is only supported on Linux at the moment. Your OS: %s", runtime.GOOS) - } - if err := d.Workstation9Driver.Verify(); err != nil { return err } - //TODO(pmyjavec) there is a better way to find this, how? - //the default will suffice for now. - vmxpath := "/usr/lib/vmware/bin/vmware-vmx" - - var stderr bytes.Buffer - cmd := exec.Command(vmxpath, "-v") - cmd.Stderr = &stderr - if err := cmd.Run(); err != nil { - return err - } - - versionRe := regexp.MustCompile(`(?i)VMware Workstation (\d+\.\d+\.\d+)\s`) - matches := versionRe.FindStringSubmatch(stderr.String()) - if matches == nil { - return fmt.Errorf( - "Couldn't find VMware WS version in output: %s", stderr.String()) - } - log.Printf("Detected VMware WS version: %s", matches[1]) - - if !strings.HasPrefix(matches[1], "10.") { - return fmt.Errorf( - "WS 10 not detected. Got version: %s", matches[1]) - } - - return nil + return workstationVerifyVersion(VMWARE_WS_VERSION) } diff --git a/builder/vmware/common/driver_workstation10_windows.go b/builder/vmware/common/driver_workstation10_windows.go new file mode 100644 index 000000000..9b036a9bb --- /dev/null +++ b/builder/vmware/common/driver_workstation10_windows.go @@ -0,0 +1,35 @@ +// +build windows + +package common + +import ( + "fmt" + "log" + "regexp" + "syscall" +) + +func workstationVerifyVersion(version string) error { + key := `SOFTWARE\Wow6432Node\VMware, Inc.\VMware Workstation` + subkey := "ProductVersion" + productVersion, err := readRegString(syscall.HKEY_LOCAL_MACHINE, key, subkey) + if err != nil { + log.Printf(`Unable to read registry key %s\%s`, key, subkey) + key = `SOFTWARE\VMware, Inc.\VMware Workstation` + productVersion, err = readRegString(syscall.HKEY_LOCAL_MACHINE, key, subkey) + if err != nil { + log.Printf(`Unable to read registry key %s\%s`, key, subkey) + return err + } + } + + versionRe := regexp.MustCompile(`^(\d+)\.`) + matches := versionRe.FindStringSubmatch(productVersion) + if matches == nil { + return fmt.Errorf( + "Could not find VMware WS version in registry key %s/subkey: %s", key, subkey, productVersion) + } + log.Printf("Detected VMware WS version: %s", matches[1]) + + return compareVersions(matches[1], version) +} diff --git a/builder/vmware/common/driver_workstation9.go b/builder/vmware/common/driver_workstation9.go index 8643d8b1f..6dd7048cc 100644 --- a/builder/vmware/common/driver_workstation9.go +++ b/builder/vmware/common/driver_workstation9.go @@ -13,7 +13,6 @@ import ( ) // Workstation9Driver is a driver that can run VMware Workstation 9 -// on non-Windows platforms. type Workstation9Driver struct { AppPath string VdiskManagerPath string @@ -24,7 +23,7 @@ type Workstation9Driver struct { } func (d *Workstation9Driver) Clone(dst, src string) error { - return errors.New("Cloning is not supported with WS 9. Please use WS 10+.") + return errors.New("Cloning is not supported with VMWare WS 9. Please use VMWare WS 10, or greater.") } func (d *Workstation9Driver) CompactDisk(diskPath string) error { diff --git a/builder/vmware/common/driver_workstation_unix.go b/builder/vmware/common/driver_workstation_unix.go index 3d5a4ab42..efa672862 100644 --- a/builder/vmware/common/driver_workstation_unix.go +++ b/builder/vmware/common/driver_workstation_unix.go @@ -4,10 +4,14 @@ package common import ( + "bytes" "errors" "fmt" + "log" "os/exec" "path/filepath" + "regexp" + "runtime" ) func workstationCheckLicense() error { @@ -46,3 +50,30 @@ func workstationToolsIsoPath(flavor string) string { func workstationVmnetnatConfPath() string { return "" } + +func workstationVerifyVersion(version string) error { + if runtime.GOOS != "linux" { + return fmt.Errorf("The VMWare WS %s driver is only supported on Linux, and Windows, at the moment. Your OS: %s", version, runtime.GOOS) + } + + //TODO(pmyjavec) there is a better way to find this, how? + //the default will suffice for now. + vmxpath := "/usr/lib/vmware/bin/vmware-vmx" + + var stderr bytes.Buffer + cmd := exec.Command(vmxpath, "-v") + cmd.Stderr = &stderr + if err := cmd.Run(); err != nil { + return err + } + + versionRe := regexp.MustCompile(`(?i)VMware Workstation (\d+)\.`) + matches := versionRe.FindStringSubmatch(stderr.String()) + if matches == nil { + return fmt.Errorf( + "Could not find VMWare WS version in output: %s", stderr.String()) + } + log.Printf("Detected VMWare WS version: %s", matches[1]) + + return compareVersions(matches[1], version) +}