@@ -24,6 +24,7 @@ type StepMarkAsTemplate struct {
2424 TemplateName string
2525 RemoteFolder string
2626 ReregisterVM config.Trilean
27+ Override bool
2728}
2829
2930func NewStepMarkAsTemplate (artifact packersdk.Artifact , p * PostProcessor ) * StepMarkAsTemplate {
@@ -48,6 +49,7 @@ func NewStepMarkAsTemplate(artifact packersdk.Artifact, p *PostProcessor) *StepM
4849 TemplateName : p .config .TemplateName ,
4950 RemoteFolder : remoteFolder ,
5051 ReregisterVM : p .config .ReregisterVM ,
52+ Override : p .config .Override ,
5153 }
5254}
5355
@@ -57,13 +59,48 @@ func (s *StepMarkAsTemplate) Run(ctx context.Context, state multistep.StateBag)
5759 folder := state .Get ("folder" ).(* object.Folder )
5860 dcPath := state .Get ("dcPath" ).(string )
5961
60- vm , err := findRuntimeVM (cli , dcPath , s .VMName , s .RemoteFolder )
62+ vm , err := findVirtualMachine (cli , dcPath , s .VMName , s .RemoteFolder )
6163 if err != nil {
6264 state .Put ("error" , err )
6365 ui .Errorf ("%s" , err )
6466 return multistep .ActionHalt
6567 }
6668
69+ templateName := s .VMName
70+ if s .TemplateName != "" {
71+ templateName = s .TemplateName
72+ }
73+
74+ existingTemplate , err := findTemplate (cli , folder , templateName )
75+ if err != nil {
76+ state .Put ("error" , fmt .Errorf ("error checking for existing template: %s" , err ))
77+ ui .Errorf ("error checking for existing template: %s" , err )
78+ return multistep .ActionHalt
79+ }
80+
81+ if existingTemplate != nil {
82+ if ! s .Override {
83+ err := fmt .Errorf ("template '%s' already exists. Set 'override = true' to replace existing templates" , templateName )
84+ state .Put ("error" , err )
85+ ui .Errorf ("%s" , err )
86+ return multistep .ActionHalt
87+ }
88+
89+ ui .Say (fmt .Sprintf ("Removing existing template '%s'..." , templateName ))
90+ task , err := existingTemplate .Destroy (context .Background ())
91+ if err != nil {
92+ state .Put ("error" , fmt .Errorf ("failed to remove existing template '%s': %s" , templateName , err ))
93+ ui .Errorf ("failed to remove existing template '%s': %s" , templateName , err )
94+ return multistep .ActionHalt
95+ }
96+ if err = task .Wait (context .Background ()); err != nil {
97+ state .Put ("error" , fmt .Errorf ("failed to remove existing template '%s': %s" , templateName , err ))
98+ ui .Errorf ("failed to remove existing template '%s': %s" , templateName , err )
99+ return multistep .ActionHalt
100+ }
101+ ui .Say (fmt .Sprintf ("Successfully removed existing template '%s'." , templateName ))
102+ }
103+
67104 // Use the MarkAsTemplate method unless the `reregister_vm` is set to `true`.
68105 if s .ReregisterVM .False () {
69106 ui .Say ("Marking as a template..." )
@@ -96,15 +133,46 @@ func (s *StepMarkAsTemplate) Run(ctx context.Context, state multistep.StateBag)
96133 return multistep .ActionHalt
97134 }
98135
99- if err := unregisterPreviousVM (cli , folder , s .VMName ); err != nil {
136+ artifactName := s .VMName
137+ if s .TemplateName != "" {
138+ artifactName = s .TemplateName
139+ }
140+
141+ if err := unregisterVirtualMachine (cli , folder , artifactName ); err != nil {
100142 state .Put ("error" , err )
101- ui .Errorf ("unregisterPreviousVM : %s" , err )
143+ ui .Errorf ("unregisterVirtualMachine : %s" , err )
102144 return multistep .ActionHalt
103145 }
104146
105- artifactName := s .VMName
106- if s .TemplateName != "" {
107- artifactName = s .TemplateName
147+ // Check if a template with the target name already exists in the destination folder.
148+ destinationTemplate , err := findTemplate (cli , folder , artifactName )
149+ if err != nil {
150+ state .Put ("error" , fmt .Errorf ("error checking for existing template in destination: %s" , err ))
151+ ui .Errorf ("error checking for existing template in destination: %s" , err )
152+ return multistep .ActionHalt
153+ }
154+
155+ if destinationTemplate != nil {
156+ if ! s .Override {
157+ err := fmt .Errorf ("template '%s' already exists. Set 'override = true' to replace existing templates" , artifactName )
158+ state .Put ("error" , err )
159+ ui .Errorf ("%s" , err )
160+ return multistep .ActionHalt
161+ }
162+
163+ ui .Say (fmt .Sprintf ("Removing existing template '%s'..." , artifactName ))
164+ task , err := destinationTemplate .Destroy (context .Background ())
165+ if err != nil {
166+ state .Put ("error" , fmt .Errorf ("failed to remove existing template '%s': %s" , artifactName , err ))
167+ ui .Errorf ("failed to remove existing template '%s': %s" , artifactName , err )
168+ return multistep .ActionHalt
169+ }
170+ if err = task .Wait (context .Background ()); err != nil {
171+ state .Put ("error" , fmt .Errorf ("failed to remove existing template '%s': %s" , artifactName , err ))
172+ ui .Errorf ("failed to remove existing template '%s': %s" , artifactName , err )
173+ return multistep .ActionHalt
174+ }
175+ ui .Say (fmt .Sprintf ("Successfully removed existing template '%s'" , artifactName ))
108176 }
109177
110178 ui .Say ("Registering virtual machine as a template: " + artifactName )
@@ -155,7 +223,7 @@ func datastorePath(vm *object.VirtualMachine) (*object.DatastorePath, error) {
155223 }, nil
156224}
157225
158- func findRuntimeVM (cli * govmomi.Client , dcPath , name , remoteFolder string ) (* object.VirtualMachine , error ) {
226+ func findVirtualMachine (cli * govmomi.Client , dcPath , name , remoteFolder string ) (* object.VirtualMachine , error ) {
159227 si := object .NewSearchIndex (cli .Client )
160228 fullPath := path .Join (dcPath , "vm" , remoteFolder , name )
161229
@@ -175,7 +243,7 @@ func findRuntimeVM(cli *govmomi.Client, dcPath, name, remoteFolder string) (*obj
175243 return vm , nil
176244}
177245
178- func unregisterPreviousVM (cli * govmomi.Client , folder * object.Folder , name string ) error {
246+ func unregisterVirtualMachine (cli * govmomi.Client , folder * object.Folder , name string ) error {
179247 si := object .NewSearchIndex (cli .Client )
180248 fullPath := path .Join (folder .InventoryPath , name )
181249
@@ -187,11 +255,27 @@ func unregisterPreviousVM(cli *govmomi.Client, folder *object.Folder, name strin
187255 if ref != nil {
188256 if vm , ok := ref .(* object.VirtualMachine ); ok {
189257 return vm .Unregister (context .Background ())
190- } else {
191- return fmt .Errorf ("object name '%v' already exists" , name )
192258 }
259+ return fmt .Errorf ("object name '%v' already exists" , name )
193260 }
194261 return nil
195262}
196263
264+ func findTemplate (cli * govmomi.Client , folder * object.Folder , name string ) (* object.VirtualMachine , error ) {
265+ si := object .NewSearchIndex (cli .Client )
266+ fullPath := path .Join (folder .InventoryPath , name )
267+
268+ ref , err := si .FindByInventoryPath (context .Background (), fullPath )
269+ if err != nil {
270+ return nil , err
271+ }
272+
273+ if ref != nil {
274+ if vm , ok := ref .(* object.VirtualMachine ); ok {
275+ return vm , nil
276+ }
277+ }
278+ return nil , nil
279+ }
280+
197281func (s * StepMarkAsTemplate ) Cleanup (multistep.StateBag ) {}
0 commit comments