Commit 60520c11 authored by Mitchell Hashimoto's avatar Mitchell Hashimoto

Merge branch 'rasa-master'

This adds support for Windows VMware Workstation
parents cecb797e fc899193
...@@ -46,7 +46,9 @@ func NewDriver() (Driver, error) { ...@@ -46,7 +46,9 @@ func NewDriver() (Driver, error) {
AppPath: "/Applications/VMware Fusion.app", AppPath: "/Applications/VMware Fusion.app",
} }
case "linux": case "linux":
driver = &Workstation9LinuxDriver{} fallthrough
case "windows":
driver = &Workstation9Driver{}
default: default:
return nil, fmt.Errorf("can't find driver for OS: %s", runtime.GOOS) return nil, fmt.Errorf("can't find driver for OS: %s", runtime.GOOS)
} }
......
// +build darwin freebsd linux netbsd openbsd
package vmware package vmware
import ( import (
...@@ -10,15 +12,15 @@ import ( ...@@ -10,15 +12,15 @@ import (
"strings" "strings"
) )
// Workstation9LinuxDriver is a driver that can run VMware Workstation 9 // Workstation9Driver is a driver that can run VMware Workstation 9
// on Linux. // on non-Windows platforms.
type Workstation9LinuxDriver struct { type Workstation9Driver struct {
AppPath string AppPath string
VdiskManagerPath string VdiskManagerPath string
VmrunPath string VmrunPath string
} }
func (d *Workstation9LinuxDriver) CompactDisk(diskPath string) error { func (d *Workstation9Driver) CompactDisk(diskPath string) error {
defragCmd := exec.Command(d.VdiskManagerPath, "-d", diskPath) defragCmd := exec.Command(d.VdiskManagerPath, "-d", diskPath)
if _, _, err := d.runAndLog(defragCmd); err != nil { if _, _, err := d.runAndLog(defragCmd); err != nil {
return err return err
...@@ -32,7 +34,7 @@ func (d *Workstation9LinuxDriver) CompactDisk(diskPath string) error { ...@@ -32,7 +34,7 @@ func (d *Workstation9LinuxDriver) CompactDisk(diskPath string) error {
return nil return nil
} }
func (d *Workstation9LinuxDriver) CreateDisk(output string, size string) error { func (d *Workstation9Driver) CreateDisk(output string, size string) error {
cmd := exec.Command(d.VdiskManagerPath, "-c", "-s", size, "-a", "lsilogic", "-t", "1", output) cmd := exec.Command(d.VdiskManagerPath, "-c", "-s", size, "-a", "lsilogic", "-t", "1", output)
if _, _, err := d.runAndLog(cmd); err != nil { if _, _, err := d.runAndLog(cmd); err != nil {
return err return err
...@@ -41,7 +43,7 @@ func (d *Workstation9LinuxDriver) CreateDisk(output string, size string) error { ...@@ -41,7 +43,7 @@ func (d *Workstation9LinuxDriver) CreateDisk(output string, size string) error {
return nil return nil
} }
func (d *Workstation9LinuxDriver) IsRunning(vmxPath string) (bool, error) { func (d *Workstation9Driver) IsRunning(vmxPath string) (bool, error) {
vmxPath, err := filepath.Abs(vmxPath) vmxPath, err := filepath.Abs(vmxPath)
if err != nil { if err != nil {
return false, err return false, err
...@@ -62,7 +64,7 @@ func (d *Workstation9LinuxDriver) IsRunning(vmxPath string) (bool, error) { ...@@ -62,7 +64,7 @@ func (d *Workstation9LinuxDriver) IsRunning(vmxPath string) (bool, error) {
return false, nil return false, nil
} }
func (d *Workstation9LinuxDriver) Start(vmxPath string, headless bool) error { func (d *Workstation9Driver) Start(vmxPath string, headless bool) error {
guiArgument := "gui" guiArgument := "gui"
if headless { if headless {
guiArgument = "nogui" guiArgument = "nogui"
...@@ -76,7 +78,7 @@ func (d *Workstation9LinuxDriver) Start(vmxPath string, headless bool) error { ...@@ -76,7 +78,7 @@ func (d *Workstation9LinuxDriver) Start(vmxPath string, headless bool) error {
return nil return nil
} }
func (d *Workstation9LinuxDriver) Stop(vmxPath string) error { func (d *Workstation9Driver) Stop(vmxPath string) error {
cmd := exec.Command(d.VmrunPath, "-T", "ws", "stop", vmxPath, "hard") cmd := exec.Command(d.VmrunPath, "-T", "ws", "stop", vmxPath, "hard")
if _, _, err := d.runAndLog(cmd); err != nil { if _, _, err := d.runAndLog(cmd); err != nil {
return err return err
...@@ -85,7 +87,7 @@ func (d *Workstation9LinuxDriver) Stop(vmxPath string) error { ...@@ -85,7 +87,7 @@ func (d *Workstation9LinuxDriver) Stop(vmxPath string) error {
return nil return nil
} }
func (d *Workstation9LinuxDriver) Verify() error { func (d *Workstation9Driver) Verify() error {
if err := d.findApp(); err != nil { if err := d.findApp(); err != nil {
return fmt.Errorf("VMware Workstation application ('vmware') not found in path.") return fmt.Errorf("VMware Workstation application ('vmware') not found in path.")
} }
...@@ -111,7 +113,7 @@ func (d *Workstation9LinuxDriver) Verify() error { ...@@ -111,7 +113,7 @@ func (d *Workstation9LinuxDriver) Verify() error {
return nil return nil
} }
func (d *Workstation9LinuxDriver) findApp() error { func (d *Workstation9Driver) findApp() error {
path, err := exec.LookPath("vmware") path, err := exec.LookPath("vmware")
if err != nil { if err != nil {
return err return err
...@@ -120,7 +122,7 @@ func (d *Workstation9LinuxDriver) findApp() error { ...@@ -120,7 +122,7 @@ func (d *Workstation9LinuxDriver) findApp() error {
return nil return nil
} }
func (d *Workstation9LinuxDriver) findVdiskManager() error { func (d *Workstation9Driver) findVdiskManager() error {
path, err := exec.LookPath("vmware-vdiskmanager") path, err := exec.LookPath("vmware-vdiskmanager")
if err != nil { if err != nil {
return err return err
...@@ -129,7 +131,7 @@ func (d *Workstation9LinuxDriver) findVdiskManager() error { ...@@ -129,7 +131,7 @@ func (d *Workstation9LinuxDriver) findVdiskManager() error {
return nil return nil
} }
func (d *Workstation9LinuxDriver) findVmrun() error { func (d *Workstation9Driver) findVmrun() error {
path, err := exec.LookPath("vmrun") path, err := exec.LookPath("vmrun")
if err != nil { if err != nil {
return err return err
...@@ -138,15 +140,15 @@ func (d *Workstation9LinuxDriver) findVmrun() error { ...@@ -138,15 +140,15 @@ func (d *Workstation9LinuxDriver) findVmrun() error {
return nil return nil
} }
func (d *Workstation9LinuxDriver) ToolsIsoPath(flavor string) string { func (d *Workstation9Driver) ToolsIsoPath(flavor string) string {
return "/usr/lib/vmware/isoimages/" + flavor + ".iso" return "/usr/lib/vmware/isoimages/" + flavor + ".iso"
} }
func (d *Workstation9LinuxDriver) DhcpLeasesPath(device string) string { func (d *Workstation9Driver) DhcpLeasesPath(device string) string {
return "/etc/vmware/" + device + "/dhcpd/dhcpd.leases" return "/etc/vmware/" + device + "/dhcpd/dhcpd.leases"
} }
func (d *Workstation9LinuxDriver) runAndLog(cmd *exec.Cmd) (string, string, error) { func (d *Workstation9Driver) runAndLog(cmd *exec.Cmd) (string, string, error) {
var stdout, stderr bytes.Buffer var stdout, stderr bytes.Buffer
log.Printf("Executing: %s %v", cmd.Path, cmd.Args[1:]) log.Printf("Executing: %s %v", cmd.Path, cmd.Args[1:])
......
// +build windows
// Contributed by Ross Smith II (smithii.com)
package vmware
import (
"bytes"
"fmt"
"log"
"os"
"os/exec"
"path/filepath"
"strings"
"syscall"
"unsafe"
)
// Workstation9Driver is a driver that can run VMware Workstation 9
// on Windows.
type Workstation9Driver struct {
AppPath string
VdiskManagerPath string
VmrunPath string
}
func (d *Workstation9Driver) CompactDisk(diskPath string) error {
defragCmd := exec.Command(d.VdiskManagerPath, "-d", diskPath)
if _, _, err := d.runAndLog(defragCmd); err != nil {
return err
}
shrinkCmd := exec.Command(d.VdiskManagerPath, "-k", diskPath)
if _, _, err := d.runAndLog(shrinkCmd); err != nil {
return err
}
return nil
}
func (d *Workstation9Driver) CreateDisk(output string, size string) error {
cmd := exec.Command(d.VdiskManagerPath, "-c", "-s", size, "-a", "lsilogic", "-t", "1", output)
if _, _, err := d.runAndLog(cmd); err != nil {
return err
}
return nil
}
func (d *Workstation9Driver) IsRunning(vmxPath string) (bool, error) {
vmxPath, err := filepath.Abs(vmxPath)
if err != nil {
return false, err
}
cmd := exec.Command(d.VmrunPath, "-T", "ws", "list")
stdout, _, err := d.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 *Workstation9Driver) Start(vmxPath string, headless bool) error {
guiArgument := "gui"
if headless {
guiArgument = "nogui"
}
cmd := exec.Command(d.VmrunPath, "-T", "ws", "start", vmxPath, guiArgument)
if _, _, err := d.runAndLog(cmd); err != nil {
return err
}
return nil
}
func (d *Workstation9Driver) Stop(vmxPath string) error {
cmd := exec.Command(d.VmrunPath, "-T", "ws", "stop", vmxPath, "hard")
if _, _, err := d.runAndLog(cmd); err != nil {
return err
}
return nil
}
func (d *Workstation9Driver) Verify() error {
if err := d.findApp(); err != nil {
return fmt.Errorf("VMware Workstation application ('vmware') not found in path.")
}
if err := d.findVmrun(); err != nil {
return fmt.Errorf("Required application 'vmrun' not found in path.")
}
if err := d.findVdiskManager(); err != nil {
return fmt.Errorf("Required application 'vmware-vdiskmanager' not found in path.")
}
// Check to see if it APPEARS to be licensed.
/*
matches, err := filepath.Glob("/etc/vmware/license-*")
if err != nil {
return fmt.Errorf("Error looking for VMware license: %s", err)
}
if len(matches) == 0 {
return errors.New("Workstation does not appear to be licensed. Please license it.")
}
*/
return nil
}
func (d *Workstation9Driver) findApp() error {
path, err := exec.LookPath("vmware.exe")
if err != nil {
path, err := getVmwarePath()
if err != nil {
return err
}
path += "vmware.exe"
}
path = strings.Replace(path, "\\", "/", -1)
log.Printf("Using '%s' for vmware path", path)
d.AppPath = path
return nil
}
func (d *Workstation9Driver) findVdiskManager() error {
path, err := exec.LookPath("vmware-vdiskmanager.exe")
if err != nil {
path, err := getVmwarePath()
if err != nil {
return err
}
path += "vmware-vdiskmanager.exe"
}
path = strings.Replace(path, "\\", "/", -1)
log.Printf("Using '%s' for vmware-vdiskmanager path", path)
d.VdiskManagerPath = path
return nil
}
func (d *Workstation9Driver) findVmrun() error {
path, err := exec.LookPath("vmrun.exe")
if err != nil {
path, err := getVmwarePath()
if err != nil {
return err
}
path += "vmrun.exe"
}
path = strings.Replace(path, "\\", "/", -1)
log.Printf("Using '%s' for vmrun path", path)
d.VmrunPath = path
return nil
}
func (d *Workstation9Driver) ToolsIsoPath(flavor string) string {
path, err := getVmwarePath()
if err != nil {
return ""
} else {
return path + flavor + ".iso"
}
}
func (d *Workstation9Driver) DhcpLeasesPath(device string) string {
programData := os.Getenv("ProgramData")
rv := programData + "/VMware/vmnetdhcp.leases"
if _, err := os.Stat(rv); os.IsNotExist(err) {
log.Printf("File not found: '%s' (found '%s' in %%ProgramData%%)", rv, programData)
return ""
}
return rv
}
func (d *Workstation9Driver) runAndLog(cmd *exec.Cmd) (string, string, error) {
var stdout, stderr bytes.Buffer
log.Printf("Executing: %s %v", cmd.Path, cmd.Args[1:])
cmd.Stdout = &stdout
cmd.Stderr = &stderr
err := cmd.Run()
stdoutString := strings.TrimSpace(stdout.String())
stderrString := strings.TrimSpace(stderr.String())
if _, ok := err.(*exec.ExitError); ok {
err = fmt.Errorf("VMware error: %s", stderrString)
}
log.Printf("stdout: %s", stdoutString)
log.Printf("stderr: %s", stderrString)
return stdout.String(), stderr.String(), err
}
// see http://blog.natefinch.com/2012/11/go-win-stuff.html
func readRegString(hive syscall.Handle, subKeyPath, valueName string) (value string, err error) {
var h syscall.Handle
err = syscall.RegOpenKeyEx(hive, syscall.StringToUTF16Ptr(subKeyPath), 0, syscall.KEY_READ, &h)
if err != nil {
return
}
defer syscall.RegCloseKey(h)
var typ uint32
var bufSize uint32
err = syscall.RegQueryValueEx(
h,
syscall.StringToUTF16Ptr(valueName),
nil,
&typ,
nil,
&bufSize)
if err != nil {
return
}
data := make([]uint16, bufSize/2+1)
err = syscall.RegQueryValueEx(
h,
syscall.StringToUTF16Ptr(valueName),
nil,
&typ,
(*byte)(unsafe.Pointer(&data[0])),
&bufSize)
if err != nil {
return
}
return syscall.UTF16ToString(data), nil
}
func getVmwarePath() (s string, e error) {
key := "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\vmware.exe"
subkey := "Path"
s, e = readRegString(syscall.HKEY_LOCAL_MACHINE, key, subkey)
if e != nil {
log.Printf("Unable to read registry key %s\\%s", key, subkey)
return "", e
}
log.Printf("Found '%s' in registry key %s\\%s", s, key, subkey)
s = strings.Replace(s, "\\", "/", -1)
return s, nil
}
...@@ -50,6 +50,9 @@ func (f *DHCPLeaseGuestLookup) GuestIP() (string, error) { ...@@ -50,6 +50,9 @@ func (f *DHCPLeaseGuestLookup) GuestIP() (string, error) {
macLineRe := regexp.MustCompile(`^\s*hardware ethernet (.+?);$`) macLineRe := regexp.MustCompile(`^\s*hardware ethernet (.+?);$`)
for _, line := range strings.Split(string(dhcpBytes), "\n") { for _, line := range strings.Split(string(dhcpBytes), "\n") {
// Need to trim off CR character when running in windows
line = strings.TrimRight(line, "\r")
matches := ipLineRe.FindStringSubmatch(line) matches := ipLineRe.FindStringSubmatch(line)
if matches != nil { if matches != nil {
lastIp = matches[1] lastIp = matches[1]
......
// +build darwin freebsd linux netbsd openbsd
package vmware package vmware
import ( import (
......
// +build windows
// Contributed by Ross Smith II (smithii.com)
package vmware
import (
"errors"
"io/ioutil"
"log"
"net"
"os"
"regexp"
"strings"
)
// Interface to help find the host IP that is available from within
// the VMware virtual machines.
type HostIPFinder interface {
HostIP() (string, error)
}
// IfconfigIPFinder finds the host IP based on the output of `ifconfig`.
type IfconfigIPFinder struct {
Device string
}
func (f *IfconfigIPFinder) HostIP() (string, error) {
ift, err := net.Interfaces()
if err != nil {
return "", errors.New("No network interfaces found")
}
vmwareMac, err := getVMWareMAC()
if err != nil {
log.Print(err)
}
log.Printf("Searching for MAC %s", vmwareMac)
re := regexp.MustCompile("(?i)^" + vmwareMac)
ip := ""
for _, ifi := range ift {
mac := ifi.HardwareAddr.String()
log.Printf("Found MAC %s", mac)
matches := re.FindStringSubmatch(mac)
if matches == nil {
continue
}
addrs, err := ifi.Addrs()
if err != nil {
log.Printf("No IP addresses found for MAC %s", mac)
continue
}
for _, address := range addrs {
ip = address.String()
log.Printf("Found IP address %s for MAC %s", ip, mac)
}
// continue looping as VMNet8 comes after VMNet1 (at least on my system)
}
if ip == "" {
return "", errors.New("No MACs found matching " + vmwareMac)
}
log.Printf("Returning IP address %s", ip)
return ip, nil
}
func getVMWareMAC() (string, error) {
// return the first three tuples, if the actual MAC cannot be found
const defaultMacRe = "00:50:56"
programData := os.Getenv("ProgramData")
programData = strings.Replace(programData, "\\", "/", -1)
vmnetnat := programData + "/VMware/vmnetnat.conf"
if _, err := os.Stat(vmnetnat); os.IsNotExist(err) {
log.Printf("File not found: '%s' (found '%s' in %%ProgramData%%)", vmnetnat, programData)
return defaultMacRe, err
}
log.Printf("Searching for key hostMAC in '%s'", vmnetnat)
fh, err := os.Open(vmnetnat)
if err != nil {
return defaultMacRe, err
}
defer fh.Close()
bytes, err := ioutil.ReadAll(fh)
if err != nil {
return defaultMacRe, err
}
hostMacRe := regexp.MustCompile(`(?i)^\s*hostMAC\s*=\s*(.+)\s*$`)
for _, line := range strings.Split(string(bytes), "\n") {
// Need to trim off CR character when running in windows
line = strings.TrimRight(line, "\r")
matches := hostMacRe.FindStringSubmatch(line)
if matches != nil {
log.Printf("Found MAC '%s' in '%s'", matches[1], vmnetnat)
return matches[1], nil
}
}
log.Printf("Did not find key hostMAC in '%s', using %s instead", vmnetnat, defaultMacRe)
return defaultMacRe, nil
}
...@@ -36,6 +36,7 @@ xc() { ...@@ -36,6 +36,7 @@ xc() {
-d="${DIR}/pkg" \ -d="${DIR}/pkg" \
-pv="${VERSION}" \ -pv="${VERSION}" \
-pr="${PREVERSION}" \ -pr="${PREVERSION}" \
$XC_OPTS \
go-install \ go-install \
xc xc
} }
......
...@@ -7,9 +7,10 @@ layout: "docs" ...@@ -7,9 +7,10 @@ layout: "docs"
Type: `vmware` Type: `vmware`
The VMware builder is able to create VMware virtual machines. It currently The VMware builder is able to create VMware virtual machines. It currently
only supports building the virtual machines using supports building virtual machines on hosts running
[VMware Fusion](http://www.vmware.com/products/fusion/overview.html), but [VMware Fusion](http://www.vmware.com/products/fusion/overview.html) for OS X, and
support for Windows and other VMware products is forthcoming. [VMware Workstation](http://www.vmware.com/products/workstation/overview.html) for Linux and Windows.
Support for VMWare ESXi/vSphere and VMWare Player is forthcoming.
The builder builds a virtual machine by creating a new virtual machine The builder builds a virtual machine by creating a new virtual machine
from scratch, booting it, installing an OS, provisioning software within from scratch, booting it, installing an OS, provisioning software within
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment