From b3b4559434eec84ed8645b0b5ed09b354117240b Mon Sep 17 00:00:00 2001 From: Sergei Parshev Date: Thu, 4 Feb 2021 13:54:42 -0800 Subject: [PATCH] Added "attach_snapshot" parameter to vmware vmx builder --- builder/vmware/common/driver.go | 2 +- builder/vmware/common/driver_esx5.go | 2 +- builder/vmware/common/driver_fusion5.go | 2 +- builder/vmware/common/driver_fusion6.go | 11 ++++++----- builder/vmware/common/driver_mock.go | 4 +++- builder/vmware/common/driver_player5.go | 2 +- builder/vmware/common/driver_player6.go | 12 ++++++------ builder/vmware/common/driver_workstation10.go | 12 ++++++------ builder/vmware/common/driver_workstation9.go | 2 +- builder/vmware/vmx/builder.go | 1 + builder/vmware/vmx/config.go | 5 +++++ builder/vmware/vmx/config.hcl2spec.go | 2 ++ builder/vmware/vmx/step_clone_vmx.go | 3 ++- .../builder/vmware/vmx/Config-not-required.mdx | 5 +++++ 14 files changed, 41 insertions(+), 24 deletions(-) diff --git a/builder/vmware/common/driver.go b/builder/vmware/common/driver.go index f20a1bd7a..511c3d8fa 100644 --- a/builder/vmware/common/driver.go +++ b/builder/vmware/common/driver.go @@ -23,7 +23,7 @@ type Driver interface { // Clone clones the VMX and the disk to the destination path. The // destination is a path to the VMX file. The disk will be copied // to that same directory. - Clone(dst string, src string, cloneType bool) error + Clone(dst string, src string, cloneType bool, snapshot string) error // CompactDisk compacts a virtual disk. CompactDisk(string) error diff --git a/builder/vmware/common/driver_esx5.go b/builder/vmware/common/driver_esx5.go index 150ec3d70..2a92e60eb 100644 --- a/builder/vmware/common/driver_esx5.go +++ b/builder/vmware/common/driver_esx5.go @@ -112,7 +112,7 @@ func NewESX5Driver(dconfig *DriverConfig, config *SSHConfig, vmName string) (Dri }, nil } -func (d *ESX5Driver) Clone(dst, src string, linked bool) error { +func (d *ESX5Driver) Clone(dst, src string, linked bool, snapshot string) error { linesToArray := func(lines string) []string { return strings.Split(strings.Trim(lines, "\r\n"), "\n") } diff --git a/builder/vmware/common/driver_fusion5.go b/builder/vmware/common/driver_fusion5.go index 0e4d4039f..cd6fc4a39 100644 --- a/builder/vmware/common/driver_fusion5.go +++ b/builder/vmware/common/driver_fusion5.go @@ -31,7 +31,7 @@ func NewFusion5Driver(dconfig *DriverConfig, config *SSHConfig) Driver { } } -func (d *Fusion5Driver) Clone(dst, src string, linked bool) error { +func (d *Fusion5Driver) Clone(dst, src string, linked bool, snapshot string) error { return errors.New("Cloning is not supported with Fusion 5. Please use Fusion 6+.") } diff --git a/builder/vmware/common/driver_fusion6.go b/builder/vmware/common/driver_fusion6.go index 27dc578a1..40e6fcef6 100644 --- a/builder/vmware/common/driver_fusion6.go +++ b/builder/vmware/common/driver_fusion6.go @@ -27,7 +27,7 @@ func NewFusion6Driver(dconfig *DriverConfig, config *SSHConfig) Driver { } } -func (d *Fusion6Driver) Clone(dst, src string, linked bool) error { +func (d *Fusion6Driver) Clone(dst, src string, linked bool, snapshot string) error { var cloneType string if linked { @@ -36,10 +36,11 @@ func (d *Fusion6Driver) Clone(dst, src string, linked bool) error { cloneType = "full" } - cmd := exec.Command(d.vmrunPath(), - "-T", "fusion", - "clone", src, dst, - cloneType) + args := []string{"-T", "fusion", "clone", src, dst, cloneType} + if snapshot != "" { + args = append(args, "-snapshot", snapshot) + } + cmd := exec.Command(d.vmrunPath(), args...) if _, _, err := runAndLog(cmd); err != nil { if strings.Contains(err.Error(), "parameters was invalid") { return fmt.Errorf( diff --git a/builder/vmware/common/driver_mock.go b/builder/vmware/common/driver_mock.go index 59f0b4a20..85f599967 100644 --- a/builder/vmware/common/driver_mock.go +++ b/builder/vmware/common/driver_mock.go @@ -14,6 +14,7 @@ type DriverMock struct { CloneDst string CloneSrc string Linked bool + Snapshot string CloneErr error CompactDiskCalled bool @@ -113,11 +114,12 @@ func (m NetworkMapperMock) DeviceIntoName(device string) (string, error) { return "", nil } -func (d *DriverMock) Clone(dst string, src string, linked bool) error { +func (d *DriverMock) Clone(dst string, src string, linked bool, snapshot string) error { d.CloneCalled = true d.CloneDst = dst d.CloneSrc = src d.Linked = linked + d.Snapshot = snapshot return d.CloneErr } diff --git a/builder/vmware/common/driver_player5.go b/builder/vmware/common/driver_player5.go index 8ec5aadb7..617fece72 100644 --- a/builder/vmware/common/driver_player5.go +++ b/builder/vmware/common/driver_player5.go @@ -31,7 +31,7 @@ func NewPlayer5Driver(config *SSHConfig) Driver { } } -func (d *Player5Driver) Clone(dst, src string, linked bool) error { +func (d *Player5Driver) Clone(dst, src string, linked bool, snapshot string) error { return errors.New("Cloning is not supported with VMWare Player version 5. Please use VMWare Player version 6, or greater.") } diff --git a/builder/vmware/common/driver_player6.go b/builder/vmware/common/driver_player6.go index 76039a651..d30077b63 100644 --- a/builder/vmware/common/driver_player6.go +++ b/builder/vmware/common/driver_player6.go @@ -21,7 +21,7 @@ func NewPlayer6Driver(config *SSHConfig) Driver { } } -func (d *Player6Driver) Clone(dst, src string, linked bool) error { +func (d *Player6Driver) Clone(dst, src string, linked bool, snapshot string) error { // TODO(rasa) check if running player+, not just player var cloneType string @@ -31,11 +31,11 @@ func (d *Player6Driver) Clone(dst, src string, linked bool) error { cloneType = "full" } - cmd := exec.Command(d.Player5Driver.VmrunPath, - "-T", "ws", - "clone", src, dst, - cloneType) - + args := []string{"-T", "ws", "clone", src, dst, cloneType} + if snapshot != "" { + args = append(args, "-snapshot", snapshot) + } + cmd := exec.Command(d.Player5Driver.VmrunPath, args...) if _, _, err := runAndLog(cmd); err != nil { return err } diff --git a/builder/vmware/common/driver_workstation10.go b/builder/vmware/common/driver_workstation10.go index b1e4c8a5c..467a9316d 100644 --- a/builder/vmware/common/driver_workstation10.go +++ b/builder/vmware/common/driver_workstation10.go @@ -21,7 +21,7 @@ func NewWorkstation10Driver(config *SSHConfig) Driver { } } -func (d *Workstation10Driver) Clone(dst, src string, linked bool) error { +func (d *Workstation10Driver) Clone(dst, src string, linked bool, snapshot string) error { var cloneType string if linked { @@ -30,11 +30,11 @@ func (d *Workstation10Driver) Clone(dst, src string, linked bool) error { cloneType = "full" } - cmd := exec.Command(d.Workstation9Driver.VmrunPath, - "-T", "ws", - "clone", src, dst, - cloneType) - + args := []string{"-T", "ws", "clone", src, dst, cloneType} + if snapshot != "" { + args = append(args, "-snapshot", snapshot) + } + cmd := exec.Command(d.Workstation9Driver.VmrunPath, args...) if _, _, err := runAndLog(cmd); err != nil { return err } diff --git a/builder/vmware/common/driver_workstation9.go b/builder/vmware/common/driver_workstation9.go index 70ca1b331..4f34ab669 100644 --- a/builder/vmware/common/driver_workstation9.go +++ b/builder/vmware/common/driver_workstation9.go @@ -30,7 +30,7 @@ func NewWorkstation9Driver(config *SSHConfig) Driver { } } -func (d *Workstation9Driver) Clone(dst, src string, linked bool) error { +func (d *Workstation9Driver) Clone(dst, src string, linked bool, snapshot string) error { return errors.New("Cloning is not supported with VMware WS version 9. Please use VMware WS version 10, or greater.") } diff --git a/builder/vmware/vmx/builder.go b/builder/vmware/vmx/builder.go index ce4aa4465..dbf8b1b58 100644 --- a/builder/vmware/vmx/builder.go +++ b/builder/vmware/vmx/builder.go @@ -97,6 +97,7 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) OutputDir: &b.config.OutputDir, VMName: b.config.VMName, Linked: b.config.Linked, + Snapshot: b.config.AttachSnapshot, }, &vmwcommon.StepConfigureVMX{ CustomData: b.config.VMXData, diff --git a/builder/vmware/vmx/config.go b/builder/vmware/vmx/config.go index dbd0e8a81..2f1c07d53 100644 --- a/builder/vmware/vmx/config.go +++ b/builder/vmware/vmx/config.go @@ -47,6 +47,11 @@ type Config struct { // scenarios. Most users will wish to create a full clone instead. Defaults // to false. Linked bool `mapstructure:"linked" required:"false"` + // Default to `null/empty`. The name of an + // **existing** snapshot to which the builder shall attach the VM before + // starting it. If no snapshot is specified the builder will simply start the + // VM from it's current state i.e. snapshot. + AttachSnapshot string `mapstructure:"attach_snapshot" required:"false"` // Path to the source VMX file to clone. If // remote_type is enabled then this specifies a path on the remote_host. SourcePath string `mapstructure:"source_path" required:"true"` diff --git a/builder/vmware/vmx/config.hcl2spec.go b/builder/vmware/vmx/config.hcl2spec.go index 30a674b09..0af743f1a 100644 --- a/builder/vmware/vmx/config.hcl2spec.go +++ b/builder/vmware/vmx/config.hcl2spec.go @@ -123,6 +123,7 @@ type FlatConfig struct { DiskName *string `mapstructure:"vmdk_name" required:"false" cty:"vmdk_name" hcl:"vmdk_name"` DiskTypeId *string `mapstructure:"disk_type_id" required:"false" cty:"disk_type_id" hcl:"disk_type_id"` Linked *bool `mapstructure:"linked" required:"false" cty:"linked" hcl:"linked"` + AttachSnapshot *string `mapstructure:"attach_snapshot" required:"false" cty:"attach_snapshot" hcl:"attach_snapshot"` SourcePath *string `mapstructure:"source_path" required:"true" cty:"source_path" hcl:"source_path"` VMName *string `mapstructure:"vm_name" required:"false" cty:"vm_name" hcl:"vm_name"` } @@ -252,6 +253,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "vmdk_name": &hcldec.AttrSpec{Name: "vmdk_name", Type: cty.String, Required: false}, "disk_type_id": &hcldec.AttrSpec{Name: "disk_type_id", Type: cty.String, Required: false}, "linked": &hcldec.AttrSpec{Name: "linked", Type: cty.Bool, Required: false}, + "attach_snapshot": &hcldec.AttrSpec{Name: "attach_snapshot", Type: cty.String, Required: false}, "source_path": &hcldec.AttrSpec{Name: "source_path", Type: cty.String, Required: false}, "vm_name": &hcldec.AttrSpec{Name: "vm_name", Type: cty.String, Required: false}, } diff --git a/builder/vmware/vmx/step_clone_vmx.go b/builder/vmware/vmx/step_clone_vmx.go index 5569ef410..3ae63e596 100644 --- a/builder/vmware/vmx/step_clone_vmx.go +++ b/builder/vmware/vmx/step_clone_vmx.go @@ -20,6 +20,7 @@ type StepCloneVMX struct { Path string VMName string Linked bool + Snapshot string tempDir string } @@ -38,7 +39,7 @@ func (s *StepCloneVMX) Run(ctx context.Context, state multistep.StateBag) multis log.Printf("Cloning from: %s", s.Path) log.Printf("Cloning to: %s", vmxPath) - if err := driver.Clone(vmxPath, s.Path, s.Linked); err != nil { + if err := driver.Clone(vmxPath, s.Path, s.Linked, s.Snapshot); err != nil { return halt(err) } diff --git a/website/content/partials/builder/vmware/vmx/Config-not-required.mdx b/website/content/partials/builder/vmware/vmx/Config-not-required.mdx index f29f2cb78..bf5deb555 100644 --- a/website/content/partials/builder/vmware/vmx/Config-not-required.mdx +++ b/website/content/partials/builder/vmware/vmx/Config-not-required.mdx @@ -14,6 +14,11 @@ scenarios. Most users will wish to create a full clone instead. Defaults to false. +- `attach_snapshot` (string) - Default to `null/empty`. The name of an + **existing** snapshot to which the builder shall attach the VM before + starting it. If no snapshot is specified the builder will simply start the + VM from it's current state i.e. snapshot. + - `vm_name` (string) - This is the name of the VMX file for the new virtual machine, without the file extension. By default this is packer-BUILDNAME, where "BUILDNAME" is the name of the build.