diff --git a/post-processor/vsphere-template/post-processor.go b/post-processor/vsphere-template/post-processor.go index d6b4fa769..9f0b7f271 100644 --- a/post-processor/vsphere-template/post-processor.go +++ b/post-processor/vsphere-template/post-processor.go @@ -31,6 +31,9 @@ type Config struct { Password string `mapstructure:"password"` Datacenter string `mapstructure:"datacenter"` Folder string `mapstructure:"folder"` + SnapshotEnable bool `mapstructure:"snapshot_enable"` + SnapshotName string `mapstructure:"snapshot_name"` + SnapshotDescription string `mapstructure:"snapshot_description"` ctx interpolate.Context } @@ -126,6 +129,7 @@ func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (pac &stepCreateFolder{ Folder: p.config.Folder, }, + NewStepCreateSnapshot(artifact, p), NewStepMarkAsTemplate(artifact), } runner := common.NewRunnerWithPauseFn(steps, p.config.PackerConfig, ui, state) diff --git a/post-processor/vsphere-template/step_create_snapshot.go b/post-processor/vsphere-template/step_create_snapshot.go new file mode 100644 index 000000000..c7fd73e15 --- /dev/null +++ b/post-processor/vsphere-template/step_create_snapshot.go @@ -0,0 +1,76 @@ +package vsphere_template + +import ( + "context" + "strings" + + "github.com/hashicorp/packer/helper/multistep" + "github.com/hashicorp/packer/packer" + "github.com/hashicorp/packer/post-processor/vsphere" + "github.com/vmware/govmomi" +) + +type stepCreateSnapshot struct { + VMName string + RemoteFolder string + SnapshotName string + SnapshotDescription string + SnapshotEnable bool +} + +func NewStepCreateSnapshot(artifact packer.Artifact, p *PostProcessor) *stepCreateSnapshot { + remoteFolder := "Discovered virtual machine" + vmname := artifact.Id() + + if artifact.BuilderId() == vsphere.BuilderId { + id := strings.Split(artifact.Id(), "::") + remoteFolder = id[1] + vmname = id[2] + } + + return &stepCreateSnapshot{ + VMName: vmname, + RemoteFolder: remoteFolder, + SnapshotEnable: p.config.SnapshotEnable, + SnapshotName: p.config.SnapshotName, + SnapshotDescription: p.config.SnapshotDescription, + } +} + +func (s *stepCreateSnapshot) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { + ui := state.Get("ui").(packer.Ui) + cli := state.Get("client").(*govmomi.Client) + dcPath := state.Get("dcPath").(string) + + if !s.SnapshotEnable { + return multistep.ActionContinue + } + + ui.Message("Creating a Snapshot...") + + vm, err := findRuntimeVM(cli, dcPath, s.VMName, s.RemoteFolder) + + if err != nil { + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + + task, err := vm.CreateSnapshot(context.Background(), s.SnapshotName, s.SnapshotDescription, false, false) + + if err != nil { + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + + if err = task.Wait(context.Background()); err != nil { + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + + return multistep.ActionContinue +} + +func (s *stepCreateSnapshot) Cleanup(multistep.StateBag) {} diff --git a/website/source/docs/post-processors/vsphere-template.html.md b/website/source/docs/post-processors/vsphere-template.html.md index 6f3d6f203..9057aca14 100644 --- a/website/source/docs/post-processors/vsphere-template.html.md +++ b/website/source/docs/post-processors/vsphere-template.html.md @@ -60,7 +60,16 @@ Optional: - `insecure` (boolean) - If it's true skip verification of server certificate. Default is false - + +- `snapshot_enable` (boolean) - Create a snapshot before marking as a + template. Default is false + +- `snapshot_name` (string) - Name for the snapshot. + Required when `snapshot_enable` is `true` + +- `snapshot_description` (string) - Description for the snapshot. + Required when `snapshot_enable` is `true` + ## Using the vSphere Template with local builders Once the [vSphere](/docs/post-processors/vsphere.html) takes an artifact from