Skip to content

Commit 59204c5

Browse files
authored
Added the ability to create a node reset marker for unmanaged hosts
Signed-off-by: Rhys Oxenham (rhys.oxenham@suse.com) (cherry picked from commit 7c71dc9)
1 parent 11599b7 commit 59204c5

File tree

2 files changed

+167
-17
lines changed

2 files changed

+167
-17
lines changed

controllers/machineinventory_controller.go

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ import (
5353
const adoptionTimeout = 5
5454

5555
const LocalResetPlanPath = "/oem/reset-cloud-config.yaml"
56+
const LocalResetUnmanagedMarker = "/var/lib/elemental/.unmanaged_reset"
5657

5758
// MachineInventoryReconciler reconciles a MachineInventory object.
5859
type MachineInventoryReconciler struct {
@@ -187,8 +188,7 @@ func (r *MachineInventoryReconciler) reconcileResetPlanSecret(ctx context.Contex
187188
logger.Info("Reconciling Reset plan")
188189

189190
resettable, resettableFound := mInventory.Annotations[elementalv1.MachineInventoryResettableAnnotation]
190-
unmanaged, unmanagedFound := mInventory.Annotations[elementalv1.MachineInventoryOSUnmanagedAnnotation]
191-
if (!resettableFound || resettable != "true") || (unmanagedFound && unmanaged == "true") {
191+
if !resettableFound || resettable != "true" {
192192
logger.V(log.DebugDepth).Info("Machine Inventory does not need reset. Removing finalizer.")
193193
controllerutil.RemoveFinalizer(mInventory, elementalv1.MachineInventoryFinalizer)
194194
return nil
@@ -234,7 +234,17 @@ func (r *MachineInventoryReconciler) updatePlanSecretWithReset(ctx context.Conte
234234

235235
logger.Info("Updating Secret with Reset plan")
236236

237-
checksum, resetPlan, err := r.newResetPlan(ctx)
237+
var checksum string
238+
var resetPlan []byte
239+
var err error
240+
241+
unmanaged, unmanagedFound := mInventory.Annotations[elementalv1.MachineInventoryOSUnmanagedAnnotation]
242+
if unmanagedFound && unmanaged == "true" {
243+
checksum, resetPlan, err = r.newUnmanagedResetPlan(ctx)
244+
} else {
245+
checksum, resetPlan, err = r.newResetPlan(ctx)
246+
}
247+
238248
if err != nil {
239249
return fmt.Errorf("getting new reset plan: %w", err)
240250
}
@@ -334,6 +344,35 @@ func (r *MachineInventoryReconciler) newResetPlan(ctx context.Context) (string,
334344
return checksum, plan, nil
335345
}
336346

347+
func (r *MachineInventoryReconciler) newUnmanagedResetPlan(ctx context.Context) (string, []byte, error) {
348+
logger := ctrl.LoggerFrom(ctx)
349+
350+
logger.Info("Creating new Unmanaged Reset plan secret")
351+
352+
// This is the remote plan that should trigger the creation of a node reset marker with current timestamp
353+
timeStamp := time.Now().Format("2006-01-02 15:04:05")
354+
resetPlan := applyinator.Plan{
355+
Files: []applyinator.File{
356+
{
357+
Content: base64.StdEncoding.EncodeToString([]byte(timeStamp)),
358+
Path: LocalResetUnmanagedMarker,
359+
Permissions: "0600",
360+
},
361+
},
362+
}
363+
364+
var buf bytes.Buffer
365+
if err := json.NewEncoder(&buf).Encode(resetPlan); err != nil {
366+
return "", nil, fmt.Errorf("failed to encode plan: %w", err)
367+
}
368+
369+
plan := buf.Bytes()
370+
371+
checksum := util.PlanChecksum(plan)
372+
373+
return checksum, plan, nil
374+
}
375+
337376
func (r *MachineInventoryReconciler) createPlanSecret(ctx context.Context, mInventory *elementalv1.MachineInventory) error {
338377
logger := ctrl.LoggerFrom(ctx)
339378

controllers/machineinventory_controller_test.go

Lines changed: 125 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -562,43 +562,154 @@ var _ = Describe("handle finalizer", func() {
562562
Expect(apierrors.IsNotFound(err)).To(BeTrue())
563563
})
564564

565-
It("should delete by removing finalizer when unmanaged annotation is true", func() {
566-
// Manually enable os.unmanaged annotation
565+
It("should delete by removing finalizer when up for deletion", func() {
566+
// 6. Manually remove finalizer
567567
Expect(cl.Get(ctx, client.ObjectKey{
568568
Name: mInventory.Name,
569569
Namespace: mInventory.Namespace,
570570
}, mInventory)).To(Succeed())
571-
mInventory.Annotations[elementalv1.MachineInventoryOSUnmanagedAnnotation] = "true"
571+
controllerutil.RemoveFinalizer(mInventory, elementalv1.MachineInventoryFinalizer)
572572
Expect(cl.Update(ctx, mInventory)).To(Succeed())
573573

574-
// Reconcile to trigger finalizer removal
574+
// Check MachineInventory was actually deleted
575+
err := cl.Get(ctx, client.ObjectKey{
576+
Name: mInventory.Name,
577+
Namespace: mInventory.Namespace,
578+
}, mInventory)
579+
Expect(apierrors.IsNotFound(err)).To(BeTrue())
580+
})
581+
582+
AfterEach(func() {
583+
Expect(test.CleanupAndWait(ctx, cl, mInventory, planSecret)).To(Succeed())
584+
})
585+
})
586+
587+
var _ = Describe("handle unmanaged finalizer", func() {
588+
var r *MachineInventoryReconciler
589+
var mInventory *elementalv1.MachineInventory
590+
var planSecret *corev1.Secret
591+
592+
BeforeEach(func() {
593+
r = &MachineInventoryReconciler{
594+
Client: cl,
595+
}
596+
597+
mInventory = &elementalv1.MachineInventory{
598+
ObjectMeta: metav1.ObjectMeta{
599+
DeletionTimestamp: &metav1.Time{Time: time.Now()},
600+
Annotations: map[string]string{elementalv1.MachineInventoryResettableAnnotation: "true", elementalv1.MachineInventoryOSUnmanagedAnnotation: "true"},
601+
Finalizers: []string{elementalv1.MachineInventoryFinalizer},
602+
Name: "machine-inventory-suite-finalizer",
603+
Namespace: "default",
604+
},
605+
}
606+
607+
planSecret = &corev1.Secret{
608+
ObjectMeta: metav1.ObjectMeta{
609+
Name: mInventory.Name,
610+
Namespace: mInventory.Namespace,
611+
},
612+
}
613+
614+
// 1. Create initial MachineInventory
615+
Expect(cl.Create(ctx, mInventory)).To(Succeed())
616+
// 2. Create initial plan Secret
575617
_, err := r.Reconcile(ctx, reconcile.Request{
576618
NamespacedName: types.NamespacedName{
577619
Namespace: mInventory.Namespace,
578620
Name: mInventory.Name,
579621
},
580622
})
581623
Expect(err).ToNot(HaveOccurred())
624+
// 3. Update meta.DeletionTimestamp
625+
Expect(cl.Delete(ctx, mInventory)).To(Succeed())
626+
// 4. Update secret with reset plan
627+
_, err = r.Reconcile(ctx, reconcile.Request{
628+
NamespacedName: types.NamespacedName{
629+
Namespace: mInventory.Namespace,
630+
Name: mInventory.Name,
631+
},
632+
})
633+
Expect(err).ToNot(HaveOccurred())
634+
// 5. Update MachineInventory plan status
635+
_, err = r.Reconcile(ctx, reconcile.Request{
636+
NamespacedName: types.NamespacedName{
637+
Namespace: mInventory.Namespace,
638+
Name: mInventory.Name,
639+
},
640+
})
641+
Expect(err).ToNot(HaveOccurred())
642+
})
582643

583-
// Check MachineInventory was actually deleted
584-
err = cl.Get(ctx, client.ObjectKey{
644+
It("should update secret with reset plan when unmanaged annotation is true", func() {
645+
// Manually enable os.unmanaged annotation
646+
Expect(cl.Get(ctx, client.ObjectKey{
647+
Name: planSecret.Name,
648+
Namespace: planSecret.Namespace,
649+
}, planSecret)).To(Succeed())
650+
Expect(cl.Get(ctx, client.ObjectKey{
585651
Name: mInventory.Name,
586652
Namespace: mInventory.Namespace,
587-
}, mInventory)
588-
Expect(apierrors.IsNotFound(err)).To(BeTrue())
589-
})
653+
}, mInventory)).To(Succeed())
654+
mInventory.Annotations[elementalv1.MachineInventoryOSUnmanagedAnnotation] = "true"
655+
Expect(cl.Update(ctx, mInventory)).To(Succeed())
590656

591-
It("should delete by removing finalizer when up for deletion", func() {
592-
// 6. Manually remove finalizer
657+
wantChecksum, wantPlan, err := r.newUnmanagedResetPlan(ctx)
658+
Expect(err).ToNot(HaveOccurred())
659+
660+
// Check Plan status
661+
Expect(mInventory.Status.Plan.Checksum).To(Equal(wantChecksum))
662+
Expect(mInventory.Status.Plan.PlanSecretRef.Name).To(Equal(planSecret.Name))
663+
Expect(mInventory.Status.Plan.PlanSecretRef.Namespace).To(Equal(planSecret.Namespace))
664+
Expect(mInventory.Status.Plan.State).To(Equal(elementalv1.PlanState("")))
665+
666+
// Check MachineInventory status
667+
Expect(mInventory.Status.Conditions[0].Type).To(Equal(elementalv1.ReadyCondition))
668+
Expect(mInventory.Status.Conditions[0].Reason).To(Equal(elementalv1.WaitingForPlanReason))
669+
Expect(mInventory.Status.Conditions[0].Status).To(Equal(metav1.ConditionFalse))
670+
Expect(mInventory.Status.Conditions[0].Message).To(Equal("waiting for plan to be applied"))
671+
672+
// Check plan secret was updated
673+
Expect(planSecret.Annotations[elementalv1.PlanTypeAnnotation]).To(Equal(elementalv1.PlanTypeReset))
674+
Expect(planSecret.Data["plan"]).To(Equal(wantPlan))
675+
Expect(planSecret.Data["applied-checksum"]).To(Equal([]byte("")))
676+
Expect(planSecret.Data["failed-checksum"]).To(Equal([]byte("")))
677+
678+
// Check we are holding on the MachineInventory (preventing actual deletion)
679+
_, err = r.Reconcile(ctx, reconcile.Request{
680+
NamespacedName: types.NamespacedName{
681+
Namespace: mInventory.Namespace,
682+
Name: mInventory.Name,
683+
},
684+
})
685+
Expect(err).ToNot(HaveOccurred())
593686
Expect(cl.Get(ctx, client.ObjectKey{
594687
Name: mInventory.Name,
595688
Namespace: mInventory.Namespace,
596689
}, mInventory)).To(Succeed())
597-
controllerutil.RemoveFinalizer(mInventory, elementalv1.MachineInventoryFinalizer)
598-
Expect(cl.Update(ctx, mInventory)).To(Succeed())
690+
})
691+
692+
It("should remove finalizer on unmanaged reset plan applied", func() {
693+
// 6. Mark the reset plan as applied
694+
Expect(cl.Get(ctx, client.ObjectKey{
695+
Name: mInventory.Name,
696+
Namespace: mInventory.Namespace,
697+
}, planSecret)).To(Succeed())
698+
mInventory.Annotations[elementalv1.MachineInventoryOSUnmanagedAnnotation] = "true"
699+
planSecret.Data["applied-checksum"] = []byte("applied")
700+
Expect(cl.Update(ctx, planSecret)).To(Succeed())
701+
702+
// 7. Trigger finalizer removal
703+
_, err := r.Reconcile(ctx, reconcile.Request{
704+
NamespacedName: types.NamespacedName{
705+
Namespace: mInventory.Namespace,
706+
Name: mInventory.Name,
707+
},
708+
})
709+
Expect(err).ToNot(HaveOccurred())
599710

600711
// Check MachineInventory was actually deleted
601-
err := cl.Get(ctx, client.ObjectKey{
712+
err = cl.Get(ctx, client.ObjectKey{
602713
Name: mInventory.Name,
603714
Namespace: mInventory.Namespace,
604715
}, mInventory)

0 commit comments

Comments
 (0)