Skip to content

Commit

Permalink
clustermodules: prevent creation of new modules if DoesExist returns …
Browse files Browse the repository at this point in the history
…an error
  • Loading branch information
chrischdi committed Aug 8, 2023
1 parent f1341ab commit fe98aab
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 13 deletions.
33 changes: 20 additions & 13 deletions controllers/clustermodule_reconciler.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ func (r Reconciler) Reconcile(ctx *context.ClusterContext) (reconcile.Result, er
return reconcile.Result{}, err
}

modErrs := []clusterModError{}

clusterModuleSpecs := []infrav1.ClusterModule{}
for _, mod := range ctx.VSphereCluster.Spec.ClusterModules {
curr := mod.TargetObjectName
Expand All @@ -91,29 +93,34 @@ func (r Reconciler) Reconcile(ctx *context.ClusterContext) (reconcile.Result, er
} else {
// verify the cluster module
exists, err := r.ClusterModuleService.DoesExist(ctx, obj, mod.ModuleUUID)
// Nothing to do if there was no error while trying to find the cluster module.
// This leads to entering the creation flow below.
if err == nil && !exists {
ctx.Logger.Info("module for object not found",
"moduleUUID", mod.ModuleUUID,
"object", mod.TargetObjectName)
continue
}

// add the error to modErrors so we bubble it up to the vSphereCluster below.
if err != nil {
ctx.Logger.Error(err, "failed to verify cluster module for object",
"name", mod.TargetObjectName, "moduleUUID", mod.ModuleUUID)
modErrs = append(modErrs, clusterModError{obj.GetName(), errors.Wrapf(err, "failed to verify cluster module %q", mod.ModuleUUID)})
}

// append the module and object info to the VSphereCluster object
// and remove it from the object map since no new cluster module
// needs to be created.
if exists {
clusterModuleSpecs = append(clusterModuleSpecs, infrav1.ClusterModule{
ControlPlane: obj.IsControlPlane(),
TargetObjectName: obj.GetName(),
ModuleUUID: mod.ModuleUUID,
})
delete(objectMap, curr)
} else {
ctx.Logger.Info("module for object not found",
"moduleUUID", mod.ModuleUUID,
"object", mod.TargetObjectName)
}
clusterModuleSpecs = append(clusterModuleSpecs, infrav1.ClusterModule{
ControlPlane: obj.IsControlPlane(),
TargetObjectName: obj.GetName(),
ModuleUUID: mod.ModuleUUID,
})
delete(objectMap, curr)
}
}

modErrs := []clusterModError{}
for _, obj := range objectMap {
moduleUUID, err := r.ClusterModuleService.Create(ctx, obj)
if err != nil {
Expand Down
61 changes: 61 additions & 0 deletions controllers/clustermodule_reconciler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ func TestReconciler_Reconcile(t *testing.T) {
kcpUUID, mdUUID := uuid.New().String(), uuid.New().String()
kcp := controlPlane("kcp", metav1.NamespaceDefault, fake.Clusterv1a2Name)
md := machineDeployment("md", metav1.NamespaceDefault, fake.Clusterv1a2Name)
vCenter500err := errors.New("500 Internal Server Error")

tests := []struct {
name string
Expand Down Expand Up @@ -72,6 +73,66 @@ func TestReconciler_Reconcile(t *testing.T) {
g.Expect(ctx.VSphereCluster.Spec.ClusterModules).To(gomega.HaveLen(2))
},
},
{
name: "when cluster modules already exist but vCenter returns an error",
clusterModules: []infrav1.ClusterModule{
{
ControlPlane: true,
TargetObjectName: "kcp",
ModuleUUID: kcpUUID,
},
{
ControlPlane: false,
TargetObjectName: "md",
ModuleUUID: mdUUID,
},
},
haveError: true,
setupMocks: func(svc *cmodfake.CMService) {
svc.On("DoesExist", mock.Anything, mock.Anything, kcpUUID).Return(false, vCenter500err)
svc.On("DoesExist", mock.Anything, mock.Anything, mdUUID).Return(false, vCenter500err)
},
customAssert: func(g *gomega.WithT, ctx *context.ClusterContext) {
g.Expect(ctx.VSphereCluster.Spec.ClusterModules).To(gomega.HaveLen(2))
// Ensure the old modules still exist.
g.Expect(ctx.VSphereCluster.Spec.ClusterModules[0].ModuleUUID).To(gomega.BeElementOf(kcpUUID, mdUUID))
g.Expect(ctx.VSphereCluster.Spec.ClusterModules[1].ModuleUUID).To(gomega.BeElementOf(kcpUUID, mdUUID))
// Check that condition got set.
g.Expect(conditions.Has(ctx.VSphereCluster, infrav1.ClusterModulesAvailableCondition)).To(gomega.BeTrue())
g.Expect(conditions.IsFalse(ctx.VSphereCluster, infrav1.ClusterModulesAvailableCondition)).To(gomega.BeTrue())
g.Expect(conditions.Get(ctx.VSphereCluster, infrav1.ClusterModulesAvailableCondition).Message).To(gomega.ContainSubstring(vCenter500err.Error()))
},
},
{
name: "when cluster modules do not exist anymore",
clusterModules: []infrav1.ClusterModule{
{
ControlPlane: true,
TargetObjectName: "kcp",
ModuleUUID: kcpUUID,
},
{
ControlPlane: false,
TargetObjectName: "md",
ModuleUUID: mdUUID,
},
},
setupMocks: func(svc *cmodfake.CMService) {
svc.On("DoesExist", mock.Anything, mock.Anything, kcpUUID).Return(false, nil)
svc.On("DoesExist", mock.Anything, mock.Anything, mdUUID).Return(false, nil)
svc.On("Create", mock.Anything, clustermodule.NewWrapper(kcp)).Return(kcpUUID+"a", nil)
svc.On("Create", mock.Anything, clustermodule.NewWrapper(md)).Return(mdUUID+"a", nil)
},
customAssert: func(g *gomega.WithT, ctx *context.ClusterContext) {
g.Expect(ctx.VSphereCluster.Spec.ClusterModules).To(gomega.HaveLen(2))
// Ensure the old modules still exist.
g.Expect(ctx.VSphereCluster.Spec.ClusterModules[0].ModuleUUID).To(gomega.BeElementOf(kcpUUID+"a", mdUUID+"a"))
g.Expect(ctx.VSphereCluster.Spec.ClusterModules[1].ModuleUUID).To(gomega.BeElementOf(kcpUUID+"a", mdUUID+"a"))
// Check that condition got set.
g.Expect(conditions.Has(ctx.VSphereCluster, infrav1.ClusterModulesAvailableCondition)).To(gomega.BeTrue())
g.Expect(conditions.IsTrue(ctx.VSphereCluster, infrav1.ClusterModulesAvailableCondition)).To(gomega.BeTrue())
},
},
{
name: "when no cluster modules exist",
clusterModules: []infrav1.ClusterModule{},
Expand Down

0 comments on commit fe98aab

Please sign in to comment.