Commit 275dc6d2 authored by Mitchell Hashimoto's avatar Mitchell Hashimoto

builder/vmware: Driver abstraction

parent 9e9196ea
......@@ -12,6 +12,7 @@ const BuilderId = "mitchellh.vmware"
type Builder struct {
config config
driver Driver
runner multistep.Runner
}
......@@ -65,6 +66,11 @@ func (b *Builder) Prepare(raw interface{}) (err error) {
return
}
b.driver, err = b.newDriver()
if err != nil {
return
}
return nil
}
......@@ -83,6 +89,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook) packer.Artifact {
// Setup the state bag
state := make(map[string]interface{})
state["config"] = &b.config
state["driver"] = b.driver
state["hook"] = hook
state["ui"] = ui
......@@ -99,3 +106,8 @@ func (b *Builder) Cancel() {
b.runner.Cancel()
}
}
func (b *Builder) newDriver() (Driver, error) {
fusionAppPath := "/Applications/VMware Fusion.app"
return &Fusion5Driver{fusionAppPath}, nil
}
package vmware
import (
"os/exec"
"path/filepath"
)
// A driver is able to talk to VMware, control virtual machines, etc.
type Driver interface {
// CreateDisk creates a virtual disk with the given size.
CreateDisk(string, string) error
// Start starts a VM specified by the path to the VMX given.
Start(string) error
// Stop stops a VM specified by the path to the VMX given.
Stop(string) error
}
// Fusion5Driver is a driver that can run VMWare Fusion 5.
type Fusion5Driver struct {
// This is the path to the "VMware Fusion.app"
AppPath string
}
func (d *Fusion5Driver) CreateDisk(output string, size string) error {
vdiskPath := filepath.Join(d.AppPath, "Contents", "Library", "vmware-vdiskmanager")
cmd := exec.Command(vdiskPath, "-c", "-s", size, "-a", "lsilogic", "-t", "1", output)
if err := cmd.Run(); err != nil {
return err
}
return nil
}
func (d *Fusion5Driver) Start(vmxPath string) error {
cmd := exec.Command(d.vmrunPath(), "-T", "fusion", "start", vmxPath, "gui")
if err := cmd.Run(); 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 := cmd.Run(); err != nil {
return err
}
return nil
}
func (d *Fusion5Driver) vmrunPath() string {
return filepath.Join(d.AppPath, "Contents", "Library", "vmrun")
}
......@@ -4,7 +4,6 @@ import (
"fmt"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
"os/exec"
"path/filepath"
)
......@@ -12,6 +11,7 @@ import (
//
// Uses:
// config *config
// driver Driver
// ui packer.Ui
//
// Produces:
......@@ -23,14 +23,12 @@ func (stepCreateDisk) Run(state map[string]interface{}) multistep.StepAction {
// TODO(mitchellh): Capture error output in case things go wrong to report it
config := state["config"].(*config)
driver := state["driver"].(Driver)
ui := state["ui"].(packer.Ui)
vdisk_manager := "/Applications/VMware Fusion.app/Contents/Library/vmware-vdiskmanager"
output := filepath.Join(config.OutputDir, config.DiskName+".vmdk")
ui.Say("Creating virtual machine disk")
cmd := exec.Command(vdisk_manager, "-c", "-s", "40000M", "-a", "lsilogic", "-t", "1", output)
if err := cmd.Run(); err != nil {
output := filepath.Join(config.OutputDir, config.DiskName+".vmdk")
if err := driver.CreateDisk(output, "40000M"); err != nil {
ui.Error(fmt.Sprintf("Error creating VMware disk: %s", err))
return multistep.ActionHalt
}
......
......@@ -4,7 +4,6 @@ import (
"fmt"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
"os/exec"
"time"
)
......@@ -12,6 +11,7 @@ import (
//
// Uses:
// config *config
// driver Driver
// ui packer.Ui
// vmx_path string
//
......@@ -24,18 +24,16 @@ type stepRun struct {
func (s *stepRun) Run(state map[string]interface{}) multistep.StepAction {
config := state["config"].(*config)
driver := state["driver"].(Driver)
ui := state["ui"].(packer.Ui)
vmxPath := state["vmx_path"].(string)
vmrun_path := "/Applications/VMware Fusion.app/Contents/Library/vmrun"
// Set the VMX path so that we know we started the machine
s.bootTime = time.Now()
s.vmxPath = vmxPath
ui.Say("Starting virtual machine...")
cmd := exec.Command(vmrun_path, "-T", "fusion", "start", s.vmxPath, "gui")
if err := cmd.Run(); err != nil {
if err := driver.Start(vmxPath); err != nil {
ui.Error(fmt.Sprintf("Error starting VM: %s", err))
return multistep.ActionHalt
}
......@@ -50,22 +48,22 @@ func (s *stepRun) Run(state map[string]interface{}) multistep.StepAction {
}
func (s *stepRun) Cleanup(state map[string]interface{}) {
driver := state["driver"].(Driver)
ui := state["ui"].(packer.Ui)
vmrun_path := "/Applications/VMware Fusion.app/Contents/Library/vmrun"
// If we started the machine... stop it.
if s.vmxPath != "" {
// If we started it less than 5 seconds ago... wait.
sinceBootTime := time.Since(s.bootTime)
waitBootTime := 5 * time.Second
if sinceBootTime < waitBootTime {
time.Sleep(waitBootTime - sinceBootTime)
sleepTime := waitBootTime - sinceBootTime
ui.Say(fmt.Sprintf("Waiting %s to give VMware time to clean up...", sleepTime.String()))
time.Sleep(sleepTime)
}
ui.Say("Stopping virtual machine...")
cmd := exec.Command(vmrun_path, "-T", "fusion", "stop", s.vmxPath, "hard")
if err := cmd.Run(); err != nil {
if err := driver.Stop(s.vmxPath); err != nil {
ui.Error(fmt.Sprintf("Error stopping VM: %s", err))
}
}
......
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