Skip to content

Commit 85f88d8

Browse files
alvaroalemankubermatic-bot
authored andcommitted
VSphere: Split clone and reconfigure (#368)
* VSphere: Split clone and reconfigure This makes debugging of permission errors easier * Clean up rkt temp files
1 parent a015933 commit 85f88d8

File tree

8 files changed

+117
-133
lines changed

8 files changed

+117
-133
lines changed

pkg/cloudprovider/provider/vsphere/helper.go

Lines changed: 72 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -33,60 +33,47 @@ const (
3333

3434
var 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

165177
func 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
249261
func 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

Comments
 (0)