From 275dc6d21f37153888996e7749ef685687bfb684 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Thu, 6 Jun 2013 12:19:38 -0700 Subject: [PATCH] builder/vmware: Driver abstraction --- builder/vmware/builder.go | 12 +++++++ builder/vmware/driver.go | 56 ++++++++++++++++++++++++++++++ builder/vmware/step_create_disk.go | 10 +++--- builder/vmware/step_run.go | 18 +++++----- 4 files changed, 80 insertions(+), 16 deletions(-) create mode 100644 builder/vmware/driver.go diff --git a/builder/vmware/builder.go b/builder/vmware/builder.go index ef3298cff..49196da89 100644 --- a/builder/vmware/builder.go +++ b/builder/vmware/builder.go @@ -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 +} diff --git a/builder/vmware/driver.go b/builder/vmware/driver.go new file mode 100644 index 000000000..4f07d1e28 --- /dev/null +++ b/builder/vmware/driver.go @@ -0,0 +1,56 @@ +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") +} diff --git a/builder/vmware/step_create_disk.go b/builder/vmware/step_create_disk.go index 529938003..36da70439 100644 --- a/builder/vmware/step_create_disk.go +++ b/builder/vmware/step_create_disk.go @@ -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 } diff --git a/builder/vmware/step_run.go b/builder/vmware/step_run.go index c8c596ccb..7d099462f 100644 --- a/builder/vmware/step_run.go +++ b/builder/vmware/step_run.go @@ -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)) } }