diff --git a/builder/vmware/builder.go b/builder/vmware/builder.go index 3db2d3647..4ad033496 100644 --- a/builder/vmware/builder.go +++ b/builder/vmware/builder.go @@ -395,6 +395,10 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe &common.StepCreateFloppy{ Files: b.config.FloppyFiles, }, + &stepRemoteUpload{ + Key: "iso_path", + Message: "Uploading ISO to remote machine...", + }, &stepCreateDisk{}, &stepCreateVMX{}, &stepHTTPServer{}, diff --git a/builder/vmware/driver_esx5.go b/builder/vmware/driver_esx5.go index 41769ecb5..89223d720 100644 --- a/builder/vmware/driver_esx5.go +++ b/builder/vmware/driver_esx5.go @@ -67,6 +67,25 @@ func (d *ESX5Driver) Unregister(vmxPathLocal string) error { return d.sh("vim-cmd", "vmsvc/unregister", d.datastorePath(vmxPathLocal)) } +func (d *ESX5Driver) UploadISO(localPath string) (string, error) { + cacheRoot, _ := filepath.Abs(".") + targetFile, err := filepath.Rel(cacheRoot, localPath) + if err != nil { + return "", err + } + + if err := d.MkdirAll(filepath.Dir(targetFile)); err != nil { + return "", err + } + + finalPath := d.datastorePath(targetFile) + if err := d.upload(finalPath, localPath); err != nil { + return "", err + } + + return finalPath, nil +} + func (d *ESX5Driver) ToolsIsoPath(string) string { return "" } @@ -180,33 +199,6 @@ func (d *ESX5Driver) SSHAddress(state multistep.StateBag) (string, error) { return address, nil } -/* -func (d *ESX5Driver) Download(*common.DownloadConfig, multistep.StateBag) (string, error, bool) { - config := state.Get("config").(*config) - - cacheRoot, _ := filepath.Abs(".") - targetFile, err := filepath.Rel(cacheRoot, dconfig.TargetPath) - if err != nil { - return "", err, false - } - - if err := d.MkdirAll(filepath.Dir(targetFile)); err != nil { - return "", err, false - } - - path := d.datastorePath(targetFile) - if d.verifyChecksum(config.ISOChecksumType, config.ISOChecksum, path) { - log.Println("Initial checksum matched, no download needed.") - return path, nil, true - } - - // TODO(dougm) progress and handle interrupt - err = d.sh("wget", dconfig.Url, "-O", path) - - return path, err, true -} -*/ - func (d *ESX5Driver) DirExists(path string) (bool, error) { err := d.sh("test", "-e", d.datastorePath(path)) return err == nil, err diff --git a/builder/vmware/driver_esx5_test.go b/builder/vmware/driver_esx5_test.go new file mode 100644 index 000000000..2c3184199 --- /dev/null +++ b/builder/vmware/driver_esx5_test.go @@ -0,0 +1,13 @@ +package vmware + +import ( + "testing" +) + +func TestESX5Driver_implDriver(t *testing.T) { + var _ Driver = new(ESX5Driver) +} + +func TestESX5Driver_implRemoteDriver(t *testing.T) { + var _ RemoteDriver = new(ESX5Driver) +} diff --git a/builder/vmware/output_dir.go b/builder/vmware/output_dir.go new file mode 100644 index 000000000..37dcaf6e8 --- /dev/null +++ b/builder/vmware/output_dir.go @@ -0,0 +1,32 @@ +package vmware + +import ( + "os" +) + +// OutputDir is an interface type that abstracts the creation and handling +// of the output directory for VMware-based products. The abstraction is made +// so that the output directory can be properly made on remote (ESXi) based +// VMware products as well as local. +type OutputDir interface { + DirExists(string) (bool, error) + MkdirAll(string) error + RemoveAll(string) error +} + +// localOutputDir is an OutputDir implementation where the directory +// is on the local machine. +type localOutputDir struct{} + +func (localOutputDir) DirExists(path string) (bool, error) { + _, err := os.Stat(path) + return err == nil, err +} + +func (localOutputDir) MkdirAll(path string) error { + return os.MkdirAll(path, 0755) +} + +func (localOutputDir) RemoveAll(path string) error { + return os.RemoveAll(path) +} diff --git a/builder/vmware/remote_driver.go b/builder/vmware/remote_driver.go new file mode 100644 index 000000000..07fb2f8e7 --- /dev/null +++ b/builder/vmware/remote_driver.go @@ -0,0 +1,16 @@ +package vmware + +type RemoteDriver interface { + Driver + + // UploadISO uploads a local ISO to the remote side and returns the + // new path that should be used in the VMX along with an error if it + // exists. + UploadISO(string) (string, error) + + // Adds a VM to inventory specified by the path to the VMX given. + Register(string) error + + // Removes a VM from inventory specified by the path to the VMX given. + Unregister(string) error +} diff --git a/builder/vmware/step_remote_upload.go b/builder/vmware/step_remote_upload.go new file mode 100644 index 000000000..47c9d04a7 --- /dev/null +++ b/builder/vmware/step_remote_upload.go @@ -0,0 +1,42 @@ +package vmware + +import ( + "fmt" + "github.com/mitchellh/multistep" + "github.com/mitchellh/packer/packer" + "log" +) + +// stepRemoteUpload uploads some thing from the state bag to a remote driver +// (if it can) and stores that new remote path into the state bag. +type stepRemoteUpload struct { + Key string + Message string +} + +func (s *stepRemoteUpload) Run(state multistep.StateBag) multistep.StepAction { + driver := state.Get("driver").(Driver) + ui := state.Get("ui").(packer.Ui) + + remote, ok := driver.(RemoteDriver) + if !ok { + return multistep.ActionContinue + } + + ui.Say(s.Message) + path := state.Get(s.Key).(string) + log.Printf("Remote uploading: %s", path) + newPath, err := remote.UploadISO(path) + if err != nil { + err := fmt.Errorf("Error uploading file: %s", err) + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + + state.Put(s.Key, newPath) + return multistep.ActionContinue +} + +func (s *stepRemoteUpload) Cleanup(state multistep.StateBag) { +} diff --git a/builder/vmware/step_run.go b/builder/vmware/step_run.go index bb356f8d6..0222173ef 100644 --- a/builder/vmware/step_run.go +++ b/builder/vmware/step_run.go @@ -22,13 +22,6 @@ type stepRun struct { vmxPath string } -type Inventory interface { - // Adds a VM to inventory specified by the path to the VMX given. - Register(string) error - // Removes a VM from inventory specified by the path to the VMX given. - Unregister(string) error -} - func (s *stepRun) Run(state multistep.StateBag) multistep.StepAction { config := state.Get("config").(*config) driver := state.Get("driver").(Driver) @@ -49,8 +42,8 @@ func (s *stepRun) Run(state multistep.StateBag) multistep.StepAction { "%s:%d", vncIp, vncPort)) } - if inv, ok := driver.(Inventory); ok { - if err := inv.Register(vmxPath); err != nil { + if remoteDriver, ok := driver.(RemoteDriver); ok { + if err := remoteDriver.Register(vmxPath); err != nil { err := fmt.Errorf("Error registering VM: %s", err) state.Put("error", err) ui.Error(err.Error()) @@ -98,9 +91,9 @@ func (s *stepRun) Cleanup(state multistep.StateBag) { } } - if inv, ok := driver.(Inventory); ok { + if remoteDriver, ok := driver.(RemoteDriver); ok { ui.Say("Unregistering virtual machine...") - if err := inv.Unregister(s.vmxPath); err != nil { + if err := remoteDriver.Unregister(s.vmxPath); err != nil { ui.Error(fmt.Sprintf("Error unregistering VM: %s", err)) } }