Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,9 @@ The following configuration options are available for the post-processor.

- `snapshot_description` (string) - A description for the snapshot. Required when `snapshot_enable` is `true`.

- `reregister_vm` (boolean) - Keepe the virtual machine registered after marking as a template.
- `reregister_vm` (boolean) - Keep the virtual machine registered after marking as a template.

- `override` (bool) - Overwrite existing template. Defaults to `false`.

<!-- End of code generated from the comments of the Config struct in post-processor/vsphere-template/post-processor.go; -->

Expand Down
3 changes: 1 addition & 2 deletions .web-docs/components/post-processor/vsphere/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,7 @@ The following configuration options are available for the post-processor.
- `options` ([]string) - Options to send to `ovftool` when uploading the virtual machine.
Use `ovftool --help` to list all the options available.

- `overwrite` (bool) - Overwrite existing files.
If `true`, forces overwrites of existing files. Defaults to `false`.
- `overwrite` (bool) - Overwrite existing files. Defaults to `false`.

- `resource_pool` (string) - The name of the resource pool to place the virtual machine.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

- `snapshot_description` (string) - A description for the snapshot. Required when `snapshot_enable` is `true`.

- `reregister_vm` (boolean) - Keepe the virtual machine registered after marking as a template.
- `reregister_vm` (boolean) - Keep the virtual machine registered after marking as a template.

- `override` (bool) - Overwrite existing template. Defaults to `false`.

<!-- End of code generated from the comments of the Config struct in post-processor/vsphere-template/post-processor.go; -->
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@
- `options` ([]string) - Options to send to `ovftool` when uploading the virtual machine.
Use `ovftool --help` to list all the options available.

- `overwrite` (bool) - Overwrite existing files.
If `true`, forces overwrites of existing files. Defaults to `false`.
- `overwrite` (bool) - Overwrite existing files. Defaults to `false`.

- `resource_pool` (string) - The name of the resource pool to place the virtual machine.

Expand Down
4 changes: 3 additions & 1 deletion post-processor/vsphere-template/post-processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,10 @@ type Config struct {
SnapshotName string `mapstructure:"snapshot_name"`
// A description for the snapshot. Required when `snapshot_enable` is `true`.
SnapshotDescription string `mapstructure:"snapshot_description"`
// Keepe the virtual machine registered after marking as a template.
// Keep the virtual machine registered after marking as a template.
ReregisterVM config.Trilean `mapstructure:"reregister_vm"`
// Overwrite existing template. Defaults to `false`.
Override bool `mapstructure:"override"`

ctx interpolate.Context
}
Expand Down
2 changes: 2 additions & 0 deletions post-processor/vsphere-template/post-processor.hcl2spec.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

48 changes: 46 additions & 2 deletions post-processor/vsphere-template/post-processor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ func getTestConfig() Config {
}
}

func TestConfigure_Good(t *testing.T) {
func TestConfigure_Valid(t *testing.T) {
var p PostProcessor

config := getTestConfig()
Expand All @@ -26,7 +26,7 @@ func TestConfigure_Good(t *testing.T) {
}
}

func TestConfigure_ReRegisterVM(t *testing.T) {
func TestConfigure_ReregisterVM_Default(t *testing.T) {
var p PostProcessor

config := getTestConfig()
Expand All @@ -40,3 +40,47 @@ func TestConfigure_ReRegisterVM(t *testing.T) {
t.Errorf("error: should be unset, not false")
}
}

func TestConfigure_Override(t *testing.T) {
tests := []struct {
name string
override *bool
expected bool
}{
{
name: "default",
override: nil,
expected: false,
},
{
name: "true",
override: &[]bool{true}[0],
expected: true,
},
{
name: "false",
override: &[]bool{false}[0],
expected: false,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var p PostProcessor
config := getTestConfig()

if tt.override != nil {
config.Override = *tt.override
}

err := p.Configure(config)
if err != nil {
t.Errorf("error: %s", err)
}

if p.config.Override != tt.expected {
t.Errorf("expected override to be %v, got %v", tt.expected, p.config.Override)
}
})
}
}
2 changes: 1 addition & 1 deletion post-processor/vsphere-template/step_create_snapshot.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func (s *StepCreateSnapshot) Run(ctx context.Context, state multistep.StateBag)

ui.Say("Creating virtual machine snapshot...")

vm, err := findRuntimeVM(cli, dcPath, s.VMName, s.RemoteFolder)
vm, err := findVirtualMachine(cli, dcPath, s.VMName, s.RemoteFolder)
if err != nil {
state.Put("error", err)
ui.Errorf("%s", err)
Expand Down
83 changes: 73 additions & 10 deletions post-processor/vsphere-template/step_mark_as_template.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ type StepMarkAsTemplate struct {
TemplateName string
RemoteFolder string
ReregisterVM config.Trilean
Override bool
}

func NewStepMarkAsTemplate(artifact packersdk.Artifact, p *PostProcessor) *StepMarkAsTemplate {
Expand All @@ -48,6 +49,7 @@ func NewStepMarkAsTemplate(artifact packersdk.Artifact, p *PostProcessor) *StepM
TemplateName: p.config.TemplateName,
RemoteFolder: remoteFolder,
ReregisterVM: p.config.ReregisterVM,
Override: p.config.Override,
}
}

Expand All @@ -57,13 +59,25 @@ func (s *StepMarkAsTemplate) Run(ctx context.Context, state multistep.StateBag)
folder := state.Get("folder").(*object.Folder)
dcPath := state.Get("dcPath").(string)

vm, err := findRuntimeVM(cli, dcPath, s.VMName, s.RemoteFolder)
vm, err := findVirtualMachine(cli, dcPath, s.VMName, s.RemoteFolder)
if err != nil {
state.Put("error", err)
ui.Errorf("%s", err)
return multistep.ActionHalt
}

templateName := s.VMName
if s.TemplateName != "" {
templateName = s.TemplateName
}

action, err := handleExistingTemplate(cli, folder, templateName, s.Override, ui)
if err != nil {
state.Put("error", err)
ui.Errorf("%s", err)
return action
}

// Use the MarkAsTemplate method unless the `reregister_vm` is set to `true`.
if s.ReregisterVM.False() {
ui.Say("Marking as a template...")
Expand Down Expand Up @@ -96,15 +110,23 @@ func (s *StepMarkAsTemplate) Run(ctx context.Context, state multistep.StateBag)
return multistep.ActionHalt
}

if err := unregisterPreviousVM(cli, folder, s.VMName); err != nil {
artifactName := s.VMName
if s.TemplateName != "" {
artifactName = s.TemplateName
}

if err := unregisterVirtualMachine(cli, folder, artifactName); err != nil {
state.Put("error", err)
ui.Errorf("unregisterPreviousVM: %s", err)
ui.Errorf("unregisterVirtualMachine: %s", err)
return multistep.ActionHalt
}

artifactName := s.VMName
if s.TemplateName != "" {
artifactName = s.TemplateName
// Check if a template with the target name already exists in the destination folder.
action, err = handleExistingTemplate(cli, folder, artifactName, s.Override, ui)
if err != nil {
state.Put("error", err)
ui.Errorf("%s", err)
return action
}

ui.Say("Registering virtual machine as a template: " + artifactName)
Expand Down Expand Up @@ -155,7 +177,7 @@ func datastorePath(vm *object.VirtualMachine) (*object.DatastorePath, error) {
}, nil
}

func findRuntimeVM(cli *govmomi.Client, dcPath, name, remoteFolder string) (*object.VirtualMachine, error) {
func findVirtualMachine(cli *govmomi.Client, dcPath, name, remoteFolder string) (*object.VirtualMachine, error) {
si := object.NewSearchIndex(cli.Client)
fullPath := path.Join(dcPath, "vm", remoteFolder, name)

Expand All @@ -175,7 +197,7 @@ func findRuntimeVM(cli *govmomi.Client, dcPath, name, remoteFolder string) (*obj
return vm, nil
}

func unregisterPreviousVM(cli *govmomi.Client, folder *object.Folder, name string) error {
func unregisterVirtualMachine(cli *govmomi.Client, folder *object.Folder, name string) error {
si := object.NewSearchIndex(cli.Client)
fullPath := path.Join(folder.InventoryPath, name)

Expand All @@ -187,11 +209,52 @@ func unregisterPreviousVM(cli *govmomi.Client, folder *object.Folder, name strin
if ref != nil {
if vm, ok := ref.(*object.VirtualMachine); ok {
return vm.Unregister(context.Background())
} else {
return fmt.Errorf("object name '%v' already exists", name)
}
return fmt.Errorf("object name '%v' already exists", name)
}
return nil
}

func findTemplate(cli *govmomi.Client, folder *object.Folder, name string) (*object.VirtualMachine, error) {
si := object.NewSearchIndex(cli.Client)
fullPath := path.Join(folder.InventoryPath, name)

ref, err := si.FindByInventoryPath(context.Background(), fullPath)
if err != nil {
return nil, err
}

if ref != nil {
if vm, ok := ref.(*object.VirtualMachine); ok {
return vm, nil
}
}
return nil, nil
}

func handleExistingTemplate(cli *govmomi.Client, folder *object.Folder, templateName string, override bool, ui packersdk.Ui) (multistep.StepAction, error) {
existingTemplate, err := findTemplate(cli, folder, templateName)
if err != nil {
return multistep.ActionHalt, fmt.Errorf("error checking for existing template: %s", err)
}

if existingTemplate != nil {
if !override {
return multistep.ActionHalt, fmt.Errorf("template '%s' already exists. Set 'override = true' to replace existing templates", templateName)
}

ui.Say(fmt.Sprintf("Removing existing template '%s'...", templateName))
task, err := existingTemplate.Destroy(context.Background())
if err != nil {
return multistep.ActionHalt, fmt.Errorf("failed to remove existing template '%s': %s", templateName, err)
}
if err = task.Wait(context.Background()); err != nil {
return multistep.ActionHalt, fmt.Errorf("failed to remove existing template '%s': %s", templateName, err)
}
ui.Say(fmt.Sprintf("Successfully removed existing template '%s'", templateName))
}

return multistep.ActionContinue, nil
}

func (s *StepMarkAsTemplate) Cleanup(multistep.StateBag) {}
Loading
Loading