From b5298464c5c99698d7d4d34c222be262c6a85cbc Mon Sep 17 00:00:00 2001 From: Alexander Laamanen Date: Fri, 27 Jan 2017 16:11:55 +0200 Subject: [PATCH] Move the remote_driver from iso to common. --- builder/vmware/common/driver_esx5.go | 98 +++++++++---------- .../vmware/{iso => common}/remote_driver.go | 16 +-- .../{iso => common}/remote_driver_mock.go | 8 +- .../vmware/common/remote_driver_mock_test.go | 10 ++ builder/vmware/common/step_configure_vmx.go | 18 +++- builder/vmware/iso/remote_driver_mock_test.go | 12 --- builder/vmware/iso/step_register.go | 4 +- builder/vmware/iso/step_remote_upload.go | 2 +- builder/vmware/iso/step_upload_vmx.go | 4 +- builder/vmware/vmx/step_clone_vmx.go | 32 +++++- 10 files changed, 117 insertions(+), 87 deletions(-) rename builder/vmware/{iso => common}/remote_driver.go (78%) rename builder/vmware/{iso => common}/remote_driver_mock.go (92%) create mode 100644 builder/vmware/common/remote_driver_mock_test.go delete mode 100644 builder/vmware/iso/remote_driver_mock_test.go diff --git a/builder/vmware/common/driver_esx5.go b/builder/vmware/common/driver_esx5.go index 1d389e434..deb5f5634 100644 --- a/builder/vmware/common/driver_esx5.go +++ b/builder/vmware/common/driver_esx5.go @@ -7,7 +7,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "log" "net" "os" @@ -48,27 +47,23 @@ func (d *ESX5Driver) Clone(dst, src string, linked bool) error { linesToArray := func(lines string) []string { return strings.Split(strings.Trim(lines, "\n"), "\n") } - err := d.sh("test -r", src) - if err != nil { - return errors.New("Source VMX not found") - } + d.SetOutputDir(dst) + srcVmx := d.datastorePath(path.Dir(src)) + dstVmx := d.datastorePath(dst) + srcDir := path.Dir(srcVmx) + dstDir := path.Dir(dstVmx) - vmName := strings.TrimSuffix(path.Base(src), ".vmx") - srcDir := path.Dir(src) - dstDir := path.Join(path.Dir(srcDir), path.Dir(dst)) - dstVmx := path.Join(dstDir, path.Base(dst)) - - log.Printf("Source: %s\n", src) + log.Printf("Source: %s\n", srcVmx) log.Printf("Dest: %s\n", dstVmx) - err = d.sh("mkdir", dstDir) + err := d.sh("mkdir", dstDir) if err != nil { return fmt.Errorf("Failed to create the destination directory %s: %s", dstDir, err) } - err = d.sh("cp", src, dstVmx) + err = d.sh("cp", srcVmx, dstVmx) if err != nil { - return fmt.Errorf("Failed to copy the vmx file %s: %s", src, err) + return fmt.Errorf("Failed to copy the vmx file %s: %s", srcVmx, err) } filesToClone, err := d.run(nil, "find", srcDir, "! -name '*.vmdk' ! -name '*.vmx' -type f") @@ -84,7 +79,7 @@ func (d *ESX5Driver) Clone(dst, src string, linked bool) error { } } - disksToClone, err := d.run(nil, "sed -ne 's/.*file[Nn]ame = \"\\(.*vmdk\\)\"/\\1/p'", src) + disksToClone, err := d.run(nil, "sed -ne 's/.*file[Nn]ame = \"\\(.*vmdk\\)\"/\\1/p'", srcVmx) if err != nil { return fmt.Errorf("Failing to get the vmdk list to clone %s", err) } @@ -94,37 +89,28 @@ func (d *ESX5Driver) Clone(dst, src string, linked bool) error { srcDisk = disk } destDisk := path.Join(dstDir, path.Base(disk)) - err := d.sh("vmkfstools", "-d thin", "-i", srcDisk, destDisk) + err = d.sh("vmkfstools", "-d thin", "-i", srcDisk, destDisk) if err != nil { return fmt.Errorf("Failing to clone disk %s: %s", srcDisk, err) } } - vmxDir, err = ioutil.TempDir("", "packer-vmx") - if err != nil { - err := fmt.Errorf("Error preparing VMX template: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - // Set the tempDir so we clean it up - s.tempDir = vmxDir - - // FIXME: VMName should be taken from the config. - vmxEdits := []string{ - "s/\\(display[Nn]ame = \\).*/\\1\"" + vmName + "\"/", - "/ethernet..generated[aA]ddress =/d", - "/uuid.bios =/d", - "/uuid.location =/d", - "/vc.uuid =/d", - } - for _, edit := range vmxEdits { - err := d.sh("sed -i -e", "'", edit, "'", dstVmx) - if err != nil { - return fmt.Errorf("Failed to edit the destination file %s: %s", dstVmx, err) - } - } + // + // // FIXME: VMName should be taken from the config. + // vmxEdits := []string{ + // "s/\\(display[Nn]ame = \\).*/\\1\"" + vmName + "\"/", + // "/ethernet..generated[aA]ddress =/d", + // "/uuid.bios =/d", + // "/uuid.location =/d", + // "/vc.uuid =/d", + // } + // for _, edit := range vmxEdits { + // err := d.sh("sed -i -e", "'", edit, "'", dstVmx) + // if err != nil { + // return fmt.Errorf("Failed to edit the destination file %s: %s", dstVmx, err) + // } + // } + log.Printf("Successfully cloned %s to %s\n", src, dst) return nil } @@ -150,6 +136,21 @@ func (d *ESX5Driver) ReloadVM() error { return d.sh("vim-cmd", "vmsvc/reload", d.vmId) } +func (d *ESX5Driver) ReadFile(name string) ([]byte, error) { + var b bytes.Buffer + writer := bufio.NewWriter(&b) + err := d.comm.Download(d.datastorePath(name), writer) + if err != nil { + return nil, fmt.Errorf("Cant read remote file %s: %s", name, err) + } + writer.Flush() + return b.Bytes(), nil +} + +func (d *ESX5Driver) WriteFile(name string, content []byte) error { + return d.comm.Upload(d.datastorePath(name), bytes.NewReader(content), nil) +} + func (d *ESX5Driver) Start(vmxPathLocal string, headless bool) error { for i := 0; i < 20; i++ { //intentionally not checking for error since poweron may fail specially after initial VM registration @@ -172,7 +173,7 @@ func (d *ESX5Driver) Stop(vmxPathLocal string) error { func (d *ESX5Driver) Register(vmxPathLocal string) error { vmxPath := filepath.ToSlash(filepath.Join(d.outputDir, filepath.Base(vmxPathLocal))) - if err := d.upload(vmxPath, vmxPathLocal); err != nil { + if err := d.Upload(vmxPath, vmxPathLocal); err != nil { return err } r, err := d.run(nil, "vim-cmd", "solo/registervm", strconv.Quote(vmxPath)) @@ -215,7 +216,7 @@ func (d *ESX5Driver) UploadISO(localPath string, checksum string, checksumType s return finalPath, nil } - if err := d.upload(finalPath, localPath); err != nil { + if err := d.Upload(finalPath, localPath); err != nil { return "", err } @@ -662,7 +663,7 @@ func (d *ESX5Driver) mkdir(path string) error { return d.sh("mkdir", "-p", strconv.Quote(path)) } -func (d *ESX5Driver) upload(dst, src string) error { +func (d *ESX5Driver) Upload(dst, src string) error { f, err := os.Open(src) if err != nil { return err @@ -671,15 +672,6 @@ func (d *ESX5Driver) upload(dst, src string) error { return d.comm.Upload(dst, f, nil) } -func (d *ESX5Driver) download(dst, src string) error { - f, err := os.Open(dst) - if err != nil { - return err - } - defer f.Close() - return d.comm.Download(dst, f, nil) -} - func (d *ESX5Driver) verifyChecksum(ctype string, hash string, file string) bool { if ctype == "none" { if err := d.sh("stat", strconv.Quote(file)); err != nil { diff --git a/builder/vmware/iso/remote_driver.go b/builder/vmware/common/remote_driver.go similarity index 78% rename from builder/vmware/iso/remote_driver.go rename to builder/vmware/common/remote_driver.go index 6e830042c..5257d245f 100644 --- a/builder/vmware/iso/remote_driver.go +++ b/builder/vmware/common/remote_driver.go @@ -1,11 +1,7 @@ -package iso - -import ( - vmwcommon "github.com/hashicorp/packer/builder/vmware/common" -) +package common type RemoteDriver interface { - vmwcommon.Driver + 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 @@ -28,8 +24,14 @@ type RemoteDriver interface { IsDestroyed() (bool, error) // Uploads a local file to remote side. - upload(dst, src string) error + Upload(dst, src string) error // Reload VM on remote side. ReloadVM() error + + // Read bytes from of a remote file. + ReadFile(string) ([]byte, error) + + // Write bytes to a remote file. + WriteFile(string, []byte) error } diff --git a/builder/vmware/iso/remote_driver_mock.go b/builder/vmware/common/remote_driver_mock.go similarity index 92% rename from builder/vmware/iso/remote_driver_mock.go rename to builder/vmware/common/remote_driver_mock.go index 03830ddcf..94b4778a7 100644 --- a/builder/vmware/iso/remote_driver_mock.go +++ b/builder/vmware/common/remote_driver_mock.go @@ -1,11 +1,7 @@ -package iso - -import ( - vmwcommon "github.com/hashicorp/packer/builder/vmware/common" -) +package common type RemoteDriverMock struct { - vmwcommon.DriverMock + DriverMock UploadISOCalled bool UploadISOPath string diff --git a/builder/vmware/common/remote_driver_mock_test.go b/builder/vmware/common/remote_driver_mock_test.go new file mode 100644 index 000000000..110e4990b --- /dev/null +++ b/builder/vmware/common/remote_driver_mock_test.go @@ -0,0 +1,10 @@ +package common + +import ( + "testing" +) + +func TestRemoteDriverMock_impl(t *testing.T) { + var _ Driver = new(RemoteDriverMock) + var _ RemoteDriver = new(RemoteDriverMock) +} diff --git a/builder/vmware/common/step_configure_vmx.go b/builder/vmware/common/step_configure_vmx.go index c3f63b2b2..5a4f61b2a 100644 --- a/builder/vmware/common/step_configure_vmx.go +++ b/builder/vmware/common/step_configure_vmx.go @@ -1,6 +1,7 @@ package common import ( + "bytes" "context" "fmt" "log" @@ -25,9 +26,14 @@ type StepConfigureVMX struct { } func (s *StepConfigureVMX) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { + log.Printf("Configuring VMX...\n") + + var vmxContents []byte + var err error + driver := state.Get("driver").(Driver) ui := state.Get("ui").(packer.Ui) - vmxPath := state.Get("vmx_path").(string) + vmxPath := state.Get("vmx_path").(string) vmxData, err := ReadVMX(vmxPath) if err != nil { err := fmt.Errorf("Error reading VMX file: %s", err) @@ -69,7 +75,15 @@ func (s *StepConfigureVMX) Run(_ context.Context, state multistep.StateBag) mult } } - if err := WriteVMX(vmxPath, vmxData); err != nil { + if remoteDriver, ok := driver.(RemoteDriver); ok { + var buf bytes.Buffer + buf.WriteString(EncodeVMX(vmxData)) + err = remoteDriver.WriteFile(vmxPath, buf.Bytes()) + } else { + err = WriteVMX(vmxPath, vmxData) + } + + if err != nil { err := fmt.Errorf("Error writing VMX file: %s", err) state.Put("error", err) ui.Error(err.Error()) diff --git a/builder/vmware/iso/remote_driver_mock_test.go b/builder/vmware/iso/remote_driver_mock_test.go deleted file mode 100644 index dd7a26e0a..000000000 --- a/builder/vmware/iso/remote_driver_mock_test.go +++ /dev/null @@ -1,12 +0,0 @@ -package iso - -import ( - "testing" - - vmwcommon "github.com/hashicorp/packer/builder/vmware/common" -) - -func TestRemoteDriverMock_impl(t *testing.T) { - var _ vmwcommon.Driver = new(RemoteDriverMock) - var _ RemoteDriver = new(RemoteDriverMock) -} diff --git a/builder/vmware/iso/step_register.go b/builder/vmware/iso/step_register.go index c97800910..46b713c79 100644 --- a/builder/vmware/iso/step_register.go +++ b/builder/vmware/iso/step_register.go @@ -20,7 +20,7 @@ func (s *StepRegister) Run(_ context.Context, state multistep.StateBag) multiste ui := state.Get("ui").(packer.Ui) vmxPath := state.Get("vmx_path").(string) - if remoteDriver, ok := driver.(RemoteDriver); ok { + if remoteDriver, ok := driver.(vmwcommon.RemoteDriver); ok { ui.Say("Registering remote VM...") if err := remoteDriver.Register(vmxPath); err != nil { err := fmt.Errorf("Error registering VM: %s", err) @@ -51,7 +51,7 @@ func (s *StepRegister) Cleanup(state multistep.StateBag) { return } - if remoteDriver, ok := driver.(RemoteDriver); ok { + if remoteDriver, ok := driver.(vmwcommon.RemoteDriver); ok { if s.Format == "" || config.SkipExport { ui.Say("Unregistering virtual machine...") if err := remoteDriver.Unregister(s.registeredPath); err != nil { diff --git a/builder/vmware/iso/step_remote_upload.go b/builder/vmware/iso/step_remote_upload.go index 05050326d..8391753a6 100644 --- a/builder/vmware/iso/step_remote_upload.go +++ b/builder/vmware/iso/step_remote_upload.go @@ -22,7 +22,7 @@ func (s *stepRemoteUpload) Run(_ context.Context, state multistep.StateBag) mult driver := state.Get("driver").(vmwcommon.Driver) ui := state.Get("ui").(packer.Ui) - remote, ok := driver.(RemoteDriver) + remote, ok := driver.(vmwcommon.RemoteDriver) if !ok { return multistep.ActionContinue } diff --git a/builder/vmware/iso/step_upload_vmx.go b/builder/vmware/iso/step_upload_vmx.go index f0fec436c..b05795508 100644 --- a/builder/vmware/iso/step_upload_vmx.go +++ b/builder/vmware/iso/step_upload_vmx.go @@ -30,10 +30,10 @@ func (c *StepUploadVMX) Run(_ context.Context, state multistep.StateBag) multist vmxPath := state.Get("vmx_path").(string) if c.RemoteType == "esx5" { - remoteDriver, ok := driver.(RemoteDriver) + remoteDriver, ok := driver.(vmwcommon.RemoteDriver) if ok { remoteVmxPath := filepath.ToSlash(filepath.Join(fmt.Sprintf("%s", remoteDriver), filepath.Base(vmxPath))) - if err := remoteDriver.upload(remoteVmxPath, vmxPath); err != nil { + if err := remoteDriver.Upload(remoteVmxPath, vmxPath); err != nil { state.Put("error", fmt.Errorf("Error writing VMX: %s", err)) return multistep.ActionHalt } diff --git a/builder/vmware/vmx/step_clone_vmx.go b/builder/vmware/vmx/step_clone_vmx.go index 848476e9a..9c150e75f 100644 --- a/builder/vmware/vmx/step_clone_vmx.go +++ b/builder/vmware/vmx/step_clone_vmx.go @@ -3,7 +3,9 @@ package vmx import ( "context" "fmt" + "io/ioutil" "log" + "os" "path/filepath" "regexp" @@ -18,9 +20,15 @@ type StepCloneVMX struct { Path string VMName string Linked bool + tempDir string } func (s *StepCloneVMX) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { + halt := func(err error) multistep.StepAction { + state.Put("error", err) + return multistep.ActionHalt + } + driver := state.Get("driver").(vmwcommon.Driver) ui := state.Get("ui").(packer.Ui) @@ -29,6 +37,7 @@ func (s *StepCloneVMX) Run(_ context.Context, state multistep.StateBag) multiste ui.Say("Cloning source VM...") log.Printf("Cloning from: %s", s.Path) log.Printf("Cloning to: %s", vmxPath) + if err := driver.Clone(vmxPath, s.Path, s.Linked); err != nil { state.Put("error", err) return multistep.ActionHalt @@ -40,10 +49,26 @@ func (s *StepCloneVMX) Run(_ context.Context, state multistep.StateBag) multiste // network type so that it can work out things like IP's and MAC // addresses // * The disk compaction step needs the paths to all attached disks + if remoteDriver, ok := driver.(vmwcommon.RemoteDriver); ok { + tempDir, err := ioutil.TempDir("", "packer-vmx") + if err != nil { + return halt(err) + } + s.tempDir = tempDir + content, err := remoteDriver.ReadFile(vmxPath) + if err != nil { + return halt(err) + } + vmxPath = filepath.Join(tempDir, s.VMName+".vmx") + err = ioutil.WriteFile(vmxPath, content, 0600) + if err != nil { + return halt(err) + } + } + vmxData, err := vmwcommon.ReadVMX(vmxPath) if err != nil { - state.Put("error", err) - return multistep.ActionHalt + return halt(err) } var diskFilenames []string @@ -104,4 +129,7 @@ func (s *StepCloneVMX) Run(_ context.Context, state multistep.StateBag) multiste } func (s *StepCloneVMX) Cleanup(state multistep.StateBag) { + if s.tempDir != "" { + os.RemoveAll(s.tempDir) + } }