Skip to content

Commit 8b8e776

Browse files
authored
Merge pull request #936 from yastij/automated-cherry-pick-of-#926-upstream-release-0.6
Automated cherry pick of #926: Fix race condition that leads to dropping the biosuuid
2 parents 7d8456a + 29c5914 commit 8b8e776

File tree

6 files changed

+74
-17
lines changed

6 files changed

+74
-17
lines changed

controllers/haproxyloadbalancer_controller.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,19 @@ func (r haproxylbReconciler) reconcileVMPre7(ctx *context.HAProxyLoadBalancerCon
555555
// Copy the HAProxyLoadBalancer's VM clone spec into the VSphereVM's
556556
// clone spec.
557557
ctx.HAProxyLoadBalancer.Spec.VirtualMachineConfiguration.DeepCopyInto(&vm.Spec.VirtualMachineCloneSpec)
558+
559+
objectKey, err := ctrlclient.ObjectKeyFromObject(vm)
560+
if err != nil {
561+
return err
562+
}
563+
existingVM := &infrav1.VSphereVM{}
564+
if err := r.Client.Get(ctx, objectKey, existingVM); err != nil {
565+
if apierrors.IsNotFound(err) {
566+
return nil
567+
}
568+
return err
569+
}
570+
vm.Spec.BiosUUID = existingVM.Spec.BiosUUID
558571
return nil
559572
}
560573
if _, err := ctrlutil.CreateOrUpdate(ctx, ctx.Client, vm, mutateFn); err != nil {

controllers/vspheremachine_controller.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ func (r machineReconciler) reconcileNormal(ctx *context.MachineContext) (reconci
315315
}
316316

317317
// TODO(akutz) Determine the version of vSphere.
318-
vm, err := r.reconcileNormalPre7(ctx)
318+
vm, err := r.reconcileNormalPre7(ctx, vsphereVM)
319319
if err != nil {
320320
if apierrors.IsAlreadyExists(err) {
321321
return reconcile.Result{}, nil
@@ -368,7 +368,7 @@ func (r machineReconciler) reconcileNormal(ctx *context.MachineContext) (reconci
368368
return reconcile.Result{}, nil
369369
}
370370

371-
func (r machineReconciler) reconcileNormalPre7(ctx *context.MachineContext) (runtime.Object, error) {
371+
func (r machineReconciler) reconcileNormalPre7(ctx *context.MachineContext, vsphereVM *infrav1.VSphereVM) (runtime.Object, error) {
372372
// Create or update the VSphereVM resource.
373373
vm := &infrav1.VSphereVM{
374374
ObjectMeta: metav1.ObjectMeta{
@@ -433,6 +433,9 @@ func (r machineReconciler) reconcileNormalPre7(ctx *context.MachineContext) (run
433433
if vm.Spec.ResourcePool == "" {
434434
vm.Spec.ResourcePool = vsphereCloudConfig.ResourcePool
435435
}
436+
if vsphereVM != nil {
437+
vm.Spec.BiosUUID = vsphereVM.Spec.BiosUUID
438+
}
436439
return nil
437440
}
438441
if _, err := ctrlutil.CreateOrUpdate(ctx, ctx.Client, vm, mutateFn); err != nil {

controllers/vspherevm_controller.go

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,6 @@ func (r vmReconciler) Reconcile(req ctrl.Request) (_ ctrl.Result, reterr error)
222222
vmContext.Logger.Error(err, "failed to get VSphereVM while exiting reconcile")
223223
return false, nil
224224
}
225-
226225
// If the remote resource version is not the same as the local
227226
// resource version, then it means we were able to get a resource
228227
// newer than the one we already had.
@@ -324,7 +323,21 @@ func (r vmReconciler) reconcileNormal(ctx *context.VMContext) (reconcile.Result,
324323
}
325324

326325
// Update the VSphereVM's BIOS UUID.
327-
ctx.VSphereVM.Spec.BiosUUID = vm.BiosUUID
326+
ctx.Logger.Info("vm bios-uuid", "biosuuid", vm.BiosUUID)
327+
328+
// defensive check to ensure we are not removing the biosUUID
329+
if vm.BiosUUID != "" {
330+
ctx.VSphereVM.Spec.BiosUUID = vm.BiosUUID
331+
} else {
332+
return reconcile.Result{}, errors.Errorf("bios uuid is empty while VM is ready")
333+
}
334+
335+
// patch the vsphereVM early to ensure that the task is
336+
// reflected in the status right away, this avoid situations
337+
// of concurrent clones
338+
if err := ctx.Patch(); err != nil {
339+
ctx.Logger.Error(err, "patch failed", "vspherevm", ctx.VSphereVM)
340+
}
328341

329342
// Update the VSphereVM's network status.
330343
r.reconcileNetwork(ctx, vm)

pkg/services/govmomi/errors.go

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,21 @@ limitations under the License.
1616

1717
package govmomi
1818

19-
import "fmt"
19+
import (
20+
"fmt"
21+
22+
"github.com/vmware/govmomi/find"
23+
)
2024

2125
// errNotFound is returned by the findVM function when a VM is not found.
2226
type errNotFound struct {
23-
instanceUUID bool
24-
uuid string
27+
uuid string
28+
byInventoryPath string
2529
}
2630

2731
func (e errNotFound) Error() string {
28-
if e.instanceUUID {
29-
return fmt.Sprintf("vm with instance uuid %s not found", e.uuid)
32+
if e.byInventoryPath != "" {
33+
return fmt.Sprintf("vm with inventory path %s not found", e.byInventoryPath)
3034
}
3135
return fmt.Sprintf("vm with bios uuid %s not found", e.uuid)
3236
}
@@ -40,10 +44,19 @@ func isNotFound(err error) bool {
4044
}
4145
}
4246

47+
func isVirtualMachineNotFound(err error) bool {
48+
switch err.(type) {
49+
case *find.NotFoundError:
50+
return true
51+
default:
52+
return false
53+
}
54+
}
55+
4356
func wasNotFoundByBIOSUUID(err error) bool {
4457
switch err.(type) {
4558
case errNotFound, *errNotFound:
46-
if err.(errNotFound).uuid != "" && !err.(errNotFound).instanceUUID {
59+
if err.(errNotFound).uuid != "" && err.(errNotFound).byInventoryPath == "" {
4760
return true
4861
}
4962
return false

pkg/services/govmomi/util.go

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package govmomi
1818

1919
import (
2020
gonet "net"
21+
"path"
2122

2223
"github.com/pkg/errors"
2324
"github.com/vmware/govmomi/object"
@@ -49,15 +50,19 @@ func sanitizeIPAddrs(ctx *context.VMContext, ipAddrs []string) []string {
4950
// 1. If the BIOS UUID is available, then it is used to find the VM.
5051
// 2. Lacking the BIOS UUID, the VM is queried by its instance UUID,
5152
// which was assigned the value of the VSphereVM resource's UID string.
53+
// 3. If it is not found by instance UUID, fallback to an inventory path search
54+
// using the vm folder path and the VSphereVM name
5255
func findVM(ctx *context.VMContext) (types.ManagedObjectReference, error) {
5356
if biosUUID := ctx.VSphereVM.Spec.BiosUUID; biosUUID != "" {
5457
objRef, err := ctx.Session.FindByBIOSUUID(ctx, biosUUID)
5558
if err != nil {
5659
return types.ManagedObjectReference{}, err
5760
}
5861
if objRef == nil {
62+
ctx.Logger.Info("vm not found by bios uuid", "biosuuid", biosUUID)
5963
return types.ManagedObjectReference{}, errNotFound{uuid: biosUUID}
6064
}
65+
ctx.Logger.Info("vm found by bios uuid", "vmref", objRef.Reference())
6166
return objRef.Reference(), nil
6267
}
6368

@@ -67,8 +72,24 @@ func findVM(ctx *context.VMContext) (types.ManagedObjectReference, error) {
6772
return types.ManagedObjectReference{}, err
6873
}
6974
if objRef == nil {
70-
return types.ManagedObjectReference{}, errNotFound{instanceUUID: true, uuid: instanceUUID}
75+
// fallback to use inventory paths
76+
folder, err := ctx.Session.Finder.FolderOrDefault(ctx, ctx.VSphereVM.Spec.Folder)
77+
if err != nil {
78+
return types.ManagedObjectReference{}, errors.Wrapf(err, "unable to get folder for %s/%s", ctx.VSphereVM.Namespace, ctx.VSphereVM.Name)
79+
}
80+
inventoryPath := path.Join(folder.InventoryPath, ctx.VSphereVM.Name)
81+
ctx.Logger.Info("using inventory path to find vm", "path", inventoryPath)
82+
vm, err := ctx.Session.Finder.VirtualMachine(ctx, inventoryPath)
83+
if err != nil {
84+
if isVirtualMachineNotFound(err) {
85+
return types.ManagedObjectReference{}, errNotFound{byInventoryPath: inventoryPath}
86+
}
87+
return types.ManagedObjectReference{}, err
88+
}
89+
ctx.Logger.Info("vm found by name", "vmref", vm.Reference())
90+
return vm.Reference(), nil
7191
}
92+
ctx.Logger.Info("vm found by instance uuid", "vmref", objRef.Reference())
7293
return objRef.Reference(), nil
7394
}
7495

pkg/services/govmomi/vcenter/clone.go

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -182,12 +182,6 @@ func Clone(ctx *context.VMContext, bootstrapData []byte) error {
182182

183183
ctx.VSphereVM.Status.TaskRef = task.Reference().Value
184184

185-
// patch the vsphereVM here to ensure that the task is
186-
// reflected in the status right away, this avoid situations
187-
// of concurrent clones
188-
if err := ctx.Patch(); err != nil {
189-
ctx.Logger.Error(err, "patch failed", "vspherevm", ctx.VSphereVM)
190-
}
191185
return nil
192186
}
193187

0 commit comments

Comments
 (0)