diff --git a/builder/vmware/driver.go b/builder/vmware/driver.go index 4df6089fd..bc6d97595 100644 --- a/builder/vmware/driver.go +++ b/builder/vmware/driver.go @@ -38,24 +38,36 @@ type Driver interface { // NewDriver returns a new driver implementation for this operating // system, or an error if the driver couldn't be initialized. func NewDriver() (Driver, error) { - var driver Driver + drivers := []Driver{} switch runtime.GOOS { case "darwin": - driver = &Fusion5Driver{ - AppPath: "/Applications/VMware Fusion.app", + drivers = []Driver{ + &Fusion5Driver{ + AppPath: "/Applications/VMware Fusion.app", + }, } case "linux": - fallthrough + drivers = []Driver{ + new(Workstation9Driver), + new(Player5LinuxDriver), + } case "windows": - driver = &Workstation9Driver{} + drivers = []Driver{ + new(Workstation9Driver), + } default: return nil, fmt.Errorf("can't find driver for OS: %s", runtime.GOOS) } - if err := driver.Verify(); err != nil { - return nil, err + errs := "" + for _, driver := range drivers { + err := driver.Verify() + if err == nil { + return driver, nil + } + errs += err.Error() + "\n" } - return driver, nil + return nil, fmt.Errorf("Unable to initialize any driver:\n%s", errs) } diff --git a/builder/vmware/driver_player5.go b/builder/vmware/driver_player5.go new file mode 100644 index 000000000..f154f512e --- /dev/null +++ b/builder/vmware/driver_player5.go @@ -0,0 +1,172 @@ +package vmware + +import ( + "fmt" + "os" + "os/exec" + "path/filepath" + "strings" +) + +// Player5LinuxDriver is a driver that can run VMware Player 5 on Linux. +type Player5LinuxDriver struct { + AppPath string + VdiskManagerPath string + QemuImgPath string + VmrunPath string +} + +func (d *Player5LinuxDriver) 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 *Player5LinuxDriver) 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 *Player5LinuxDriver) CreateDisk(output string, size 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", "lsilogic", "-t", "1", output) + } + if _, _, err := runAndLog(cmd); err != nil { + return err + } + + return nil +} + +func (d *Player5LinuxDriver) 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 *Player5LinuxDriver) Start(vmxPath string, headless bool) error { + guiArgument := "gui" + if headless { + guiArgument = "nogui" + } + + cmd := exec.Command(d.VmrunPath, "-T", "player", "start", vmxPath, guiArgument) + if _, _, err := runAndLog(cmd); err != nil { + return err + } + + return nil +} + +func (d *Player5LinuxDriver) Stop(vmxPath string) error { + cmd := exec.Command(d.VmrunPath, "-T", "player", "stop", vmxPath, "hard") + if _, _, err := runAndLog(cmd); err != nil { + return err + } + + return nil +} + +func (d *Player5LinuxDriver) Verify() error { + if err := d.findApp(); err != nil { + return fmt.Errorf("VMware Player application ('vmplayer') not found in path.") + } + + if err := d.findVmrun(); err != nil { + return fmt.Errorf("Critical application 'vmrun' not found in path.") + } + + if err := d.findVdiskManager(); err != nil { + if err := d.findQemuImg(); err != nil { + return fmt.Errorf("Neither 'vmware-vdiskmanager', not 'qemu-img' found in path.") + } + } + + return nil +} + +func (d *Player5LinuxDriver) findApp() error { + path, err := exec.LookPath("vmplayer") + if err != nil { + return err + } + d.AppPath = path + return nil +} + +func (d *Player5LinuxDriver) findVdiskManager() error { + path, err := exec.LookPath("vmware-vdiskmanager") + if err != nil { + return err + } + d.VdiskManagerPath = path + return nil +} + +func (d *Player5LinuxDriver) findQemuImg() error { + path, err := exec.LookPath("qemu-img") + if err != nil { + return err + } + d.QemuImgPath = path + return nil +} + +func (d *Player5LinuxDriver) findVmrun() error { + path, err := exec.LookPath("vmrun") + if err != nil { + return err + } + d.VmrunPath = path + return nil +} + +func (d *Player5LinuxDriver) ToolsIsoPath(flavor string) string { + return "/usr/lib/vmware/isoimages/" + flavor + ".iso" +} + +func (d *Player5LinuxDriver) DhcpLeasesPath(device string) string { + return "/etc/vmware/" + device + "/dhcpd/dhcpd.leases" +} diff --git a/builder/vmware/step_prepare_output_dir.go b/builder/vmware/step_prepare_output_dir.go index 6919f676c..738bedca3 100644 --- a/builder/vmware/step_prepare_output_dir.go +++ b/builder/vmware/step_prepare_output_dir.go @@ -36,7 +36,6 @@ func (stepPrepareOutputDir) Cleanup(state map[string]interface{}) { ui := state["ui"].(packer.Ui) ui.Say("Deleting output directory...") - for i := 0; i < 5; i++ { err := os.RemoveAll(config.OutputDir) if err == nil {