@@ -33,60 +33,47 @@ const (
3333
3434var errSnapshotNotFound = errors .New ("no snapshot with given name found" )
3535
36- func createLinkClonedVM (vmName , vmImage , datacenter , clusterName , folder string , cpus int32 , memoryMB int64 , client * govmomi.Client , containerLinuxUserdata string ) error {
37- f := find .NewFinder (client .Client , true )
38- ctx , cancel := context .WithCancel (context .Background ())
39- defer cancel ()
40-
41- dc , err := f .Datacenter (ctx , datacenter )
36+ func createClonedVM (ctx context.Context , vmName string , config * Config , dc * object.Datacenter , f * find.Finder , containerLinuxUserdata string ) (* object.VirtualMachine , error ) {
37+ templateVM , err := f .VirtualMachine (ctx , config .TemplateVMName )
4238 if err != nil {
43- return fmt .Errorf ("failed to get datacenter: %v" , err )
44- }
45- f .SetDatacenter (dc )
46-
47- templateVM , err := f .VirtualMachine (ctx , vmImage )
48- if err != nil {
49- return fmt .Errorf ("failed to get virtualmachine: %v" , err )
39+ return nil , fmt .Errorf ("failed to get template vm: %v" , err )
5040 }
5141
5242 glog .V (3 ).Infof ("Template VM ref is %+v" , templateVM )
53- datacenterFolders , err := dc .Folders (ctx )
54- if err != nil {
55- return fmt .Errorf ("failed to get datacenter folders: %v" , err )
56- }
5743
58- // Find the target folder, if its include in the provider config.
59- targetVMFolder := datacenterFolders . VmFolder
60- if folder != "" {
44+ // Find the target folder, if its included in the provider config.
45+ var targetVMFolder * object. Folder
46+ if config . Folder != "" {
6147 // If non-absolute folder name is used, e.g. 'duplicate-folder' it can match
6248 // multiple folders and thus fail. It will also gladly match a folder from
6349 // a different datacenter. It is therefore preferable to use absolute folder
6450 // paths, e.g. '/Datacenter/vm/nested/folder'.
6551 // The target folder must already exist.
66- targetVMFolder , err = f .Folder (ctx , folder )
52+ targetVMFolder , err = f .Folder (ctx , config .Folder )
53+ if err != nil {
54+ return nil , fmt .Errorf ("failed to get target folder: %v" , err )
55+ }
56+ } else {
57+ // Do not query datacenter folders unless required
58+ datacenterFolders , err := dc .Folders (ctx )
6759 if err != nil {
68- return fmt .Errorf ("failed to get target folder : %v" , err )
60+ return nil , fmt .Errorf ("failed to get datacenter folders : %v" , err )
6961 }
62+ targetVMFolder = datacenterFolders .VmFolder
7063 }
7164
7265 // Create snapshot of the template VM if not already snapshotted.
7366 snapshot , err := findSnapshot (ctx , templateVM , snapshotName )
7467 if err != nil {
7568 if err != errSnapshotNotFound {
76- return fmt .Errorf ("failed to find snapshot: %v" , err )
69+ return nil , fmt .Errorf ("failed to find snapshot: %v" , err )
7770 }
7871 snapshot , err = createSnapshot (ctx , templateVM , snapshotName , snapshotDesc )
7972 if err != nil {
80- return fmt .Errorf ("failed to create snapshot: %v" , err )
73+ return nil , fmt .Errorf ("failed to create snapshot: %v" , err )
8174 }
8275 }
8376
84- clsComputeRes , err := f .ClusterComputeResource (ctx , clusterName )
85- if err != nil {
86- return fmt .Errorf ("failed to get cluster %s: %v" , clusterName , err )
87- }
88- glog .V (3 ).Infof ("Cluster is %+v" , clsComputeRes )
89-
9077 snapshotRef := snapshot .Reference ()
9178
9279 var vAppAconfig * types.VmConfigSpec
@@ -97,14 +84,13 @@ func createLinkClonedVM(vmName, vmImage, datacenter, clusterName, folder string,
9784 // In order to overwrite them, we need to specify their numeric Key values,
9885 // which we'll extract from that template.
9986 var mvm mo.VirtualMachine
100- err = templateVM .Properties (ctx , templateVM .Reference (), []string {"config" , "config.vAppConfig" , "config.vAppConfig.property" }, & mvm )
101- if err != nil {
102- return fmt .Errorf ("failed to extract vapp properties for coreos: %v" , err )
87+ if err := templateVM .Properties (ctx , templateVM .Reference (), []string {"config" , "config.vAppConfig" , "config.vAppConfig.property" }, & mvm ); err != nil {
88+ return nil , fmt .Errorf ("failed to extract vapp properties for coreos: %v" , err )
10389 }
10490
10591 var propertySpecs []types.VAppPropertySpec
10692 if mvm .Config .VAppConfig .GetVmConfigInfo () == nil {
107- return fmt .Errorf ("no vm config found in template '%s'. Make sure you import the correct OVA with the appropriate coreos settings" , vmImage )
93+ return nil , fmt .Errorf ("no vm config found in template '%s'. Make sure you import the correct OVA with the appropriate coreos settings" , config . TemplateVMName )
10894 }
10995
11096 for _ , item := range mvm .Config .VAppConfig .GetVmConfigInfo ().Property {
@@ -138,28 +124,54 @@ func createLinkClonedVM(vmName, vmImage, datacenter, clusterName, folder string,
138124 }
139125
140126 diskUUIDEnabled := true
141- cloneSpec := & types.VirtualMachineCloneSpec {
142- Config : & types.VirtualMachineConfigSpec {
143- Flags : & types.VirtualMachineFlagInfo {
144- DiskUuidEnabled : & diskUUIDEnabled ,
145- },
146- NumCPUs : cpus ,
147- MemoryMB : memoryMB ,
148- VAppConfig : vAppAconfig ,
127+ desiredConfig := types.VirtualMachineConfigSpec {
128+ Flags : & types.VirtualMachineFlagInfo {
129+ DiskUuidEnabled : & diskUUIDEnabled ,
149130 },
150- Snapshot : & snapshotRef ,
131+ NumCPUs : config .CPUs ,
132+ MemoryMB : config .MemoryMB ,
133+ VAppConfig : vAppAconfig ,
151134 }
152135
153- // Create a link cloned VM from the template VM's snapshot
154- clonedVMTask , err := templateVM .Clone (ctx , targetVMFolder , vmName , * cloneSpec )
136+ // Create a cloned VM from the template VM's snapshot
137+ clonedVMTask , err := templateVM .Clone (ctx , targetVMFolder , vmName , types. VirtualMachineCloneSpec { Snapshot : & snapshotRef } )
155138 if err != nil {
156- return fmt .Errorf ("failed to clone template vm: %v" , err )
139+ return nil , fmt .Errorf ("failed to clone template vm: %v" , err )
157140 }
158141
159- if _ , err = clonedVMTask .WaitForResult (ctx , nil ); err != nil {
160- return fmt .Errorf ("error when waiting for result of clone task: %v" , err )
142+ if err : = clonedVMTask .Wait (ctx ); err != nil {
143+ return nil , fmt .Errorf ("error when waiting for result of clone task: %v" , err )
161144 }
162- return nil
145+
146+ virtualMachine , err := f .VirtualMachine (ctx , vmName )
147+ if err != nil {
148+ return nil , fmt .Errorf ("failed to get virtual machine object after cloning: %v" , err )
149+ }
150+
151+ reconfigureTask , err := virtualMachine .Reconfigure (ctx , desiredConfig )
152+ if err != nil {
153+ return nil , fmt .Errorf ("failed to reconfigure vm: %v" , err )
154+ }
155+
156+ if err := reconfigureTask .Wait (ctx ); err != nil {
157+ return nil , fmt .Errorf ("error waiting for reconfigure task to finish: %v" , err )
158+ }
159+
160+ // Update network if requested
161+ if config .VMNetName != "" {
162+ if err := updateNetworkForVM (ctx , virtualMachine , config .TemplateNetName , config .VMNetName ); err != nil {
163+ return nil , fmt .Errorf ("couldn't set network for vm: %v" , err )
164+ }
165+ }
166+
167+ // Ubuntu wont boot with attached floppy device, because it tries to write to it
168+ // which fails, because the floppy device does not contain a floppy disk
169+ // Upstream issue: https://bugs.launchpad.net/cloud-images/+bug/1573095
170+ if err := removeFloppyDevice (ctx , virtualMachine ); err != nil {
171+ return nil , fmt .Errorf ("failed to remove floppy device: %v" , err )
172+ }
173+
174+ return virtualMachine , nil
163175}
164176
165177func updateNetworkForVM (ctx context.Context , vm * object.VirtualMachine , currentNetName string , newNetName string ) error {
@@ -249,8 +261,7 @@ func createSnapshot(ctx context.Context, vm *object.VirtualMachine, snapshotName
249261func findSnapshot (ctx context.Context , vm * object.VirtualMachine , name string ) (object.Reference , error ) {
250262 var moVirtualMachine mo.VirtualMachine
251263
252- err := vm .Properties (ctx , vm .Reference (), []string {"snapshot" }, & moVirtualMachine )
253- if err != nil {
264+ if err := vm .Properties (ctx , vm .Reference (), []string {"snapshot" }, & moVirtualMachine ); err != nil {
254265 return nil , fmt .Errorf ("failed to get vm properties: %v" , err )
255266 }
256267
@@ -284,9 +295,7 @@ func addMatchingSnapshotToList(list *[]object.Reference, tree types.VirtualMachi
284295 }
285296}
286297
287- func uploadAndAttachISO (f * find.Finder , vmRef * object.VirtualMachine , localIsoFilePath , datastoreName string , client * govmomi.Client ) error {
288- ctx , cancel := context .WithCancel (context .Background ())
289- defer cancel ()
298+ func uploadAndAttachISO (ctx context.Context , f * find.Finder , vmRef * object.VirtualMachine , localIsoFilePath , datastoreName string ) error {
290299
291300 datastore , err := f .Datastore (ctx , datastoreName )
292301 if err != nil {
@@ -295,8 +304,7 @@ func uploadAndAttachISO(f *find.Finder, vmRef *object.VirtualMachine, localIsoFi
295304 p := soap .DefaultUpload
296305 remoteIsoFilePath := fmt .Sprintf ("%s/%s" , vmRef .Name (), "cloud-init.iso" )
297306 glog .V (3 ).Infof ("Uploading userdata ISO to datastore %+v, destination iso is %s\n " , datastore , remoteIsoFilePath )
298- err = datastore .UploadFile (ctx , localIsoFilePath , remoteIsoFilePath , & p )
299- if err != nil {
307+ if err := datastore .UploadFile (ctx , localIsoFilePath , remoteIsoFilePath , & p ); err != nil {
300308 return fmt .Errorf ("failed to upload iso: %v" , err )
301309 }
302310 glog .V (3 ).Infof ("Uploaded ISO file %s" , localIsoFilePath )
@@ -335,8 +343,7 @@ func generateLocalUserdataISO(userdata, name string) (string, error) {
335343 return "" , fmt .Errorf ("failed to create local temp directory for userdata at %s: %v" , userdataDir , err )
336344 }
337345 defer func () {
338- err := os .RemoveAll (userdataDir )
339- if err != nil {
346+ if err := os .RemoveAll (userdataDir ); err != nil {
340347 utilruntime .HandleError (fmt .Errorf ("error cleaning up local userdata tempdir %s: %v" , userdataDir , err ))
341348 }
342349 }()
@@ -357,18 +364,15 @@ func generateLocalUserdataISO(userdata, name string) (string, error) {
357364 InstanceID : name ,
358365 Hostname : name ,
359366 }
360- err = metadataTmpl .Execute (metadata , templateContext )
361- if err != nil {
367+ if err = metadataTmpl .Execute (metadata , templateContext ); err != nil {
362368 return "" , fmt .Errorf ("failed to render metadata: %v" , err )
363369 }
364370
365- err = ioutil .WriteFile (userdataFilePath , []byte (userdata ), 0644 )
366- if err != nil {
371+ if err := ioutil .WriteFile (userdataFilePath , []byte (userdata ), 0644 ); err != nil {
367372 return "" , fmt .Errorf ("failed to locally write userdata file to %s: %v" , userdataFilePath , err )
368373 }
369374
370- err = ioutil .WriteFile (metadataFilePath , metadata .Bytes (), 0644 )
371- if err != nil {
375+ if err := ioutil .WriteFile (metadataFilePath , metadata .Bytes (), 0644 ); err != nil {
372376 return "" , fmt .Errorf ("failed to locally write metadata file to %s: %v" , userdataFilePath , err )
373377 }
374378
@@ -386,16 +390,15 @@ func generateLocalUserdataISO(userdata, name string) (string, error) {
386390 }
387391
388392 cmd := exec .Command (command , args ... )
389- output , err := cmd .CombinedOutput ()
390- if err != nil {
393+ if output , err := cmd .CombinedOutput (); err != nil {
391394 return "" , fmt .Errorf ("error executing command `%s %s`: output: `%s`, error: `%v`" , command , args , string (output ), err )
392395 }
393396
394397 return isoFilePath , nil
395398}
396399
397- func removeFloppyDevice (virtualMachine * object.VirtualMachine ) error {
398- vmDevices , err := virtualMachine .Device (context . TODO () )
400+ func removeFloppyDevice (ctx context. Context , virtualMachine * object.VirtualMachine ) error {
401+ vmDevices , err := virtualMachine .Device (ctx )
399402 if err != nil {
400403 return fmt .Errorf ("failed to get device list: %v" , err )
401404 }
@@ -410,8 +413,7 @@ func removeFloppyDevice(virtualMachine *object.VirtualMachine) error {
410413 return fmt .Errorf ("failed to find floppy: %v" , err )
411414 }
412415
413- err = virtualMachine .RemoveDevice (context .TODO (), false , floppyDevice )
414- if err != nil {
416+ if err := virtualMachine .RemoveDevice (ctx , false , floppyDevice ); err != nil {
415417 return fmt .Errorf ("failed to remove floppy device: %v" , err )
416418 }
417419
0 commit comments