Skip to content

Commit 2a12408

Browse files
authored
Implement ManagedClusterModuleStatus for KMM-Hub (kubernetes-sigs#230)
This change adds the implementation of the ManagedClusterModuleStatus. The latter reflects the number of desired, applied and degraded ManifestWork CRs owned by the respective ManagedClusterModule CR. Signed-off-by: Michail Resvanis <[email protected]> Signed-off-by: Michail Resvanis <[email protected]>
1 parent d950a25 commit 2a12408

11 files changed

+393
-29
lines changed

api-hub/v1beta1/managedclustermodule_types.go

+8
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,14 @@ type ManagedClusterModuleSpec struct {
3838

3939
// ManagedClusterModuleStatus defines the observed state of ManagedClusterModule.
4040
type ManagedClusterModuleStatus struct {
41+
// Number of ManifestWorks to be applied.
42+
NumberDesired int32 `json:"numberDesired"`
43+
44+
// Number of ManifestWorks that have been successfully applied.
45+
NumberApplied int32 `json:"numberApplied"`
46+
47+
// Number of ManifestWorks that could not be successfully applied.
48+
NumberDegraded int32 `json:"numberDegraded"`
4149
}
4250

4351
//+kubebuilder:object:root=true

cmd/manager-hub/main.go

+2
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ import (
4747
"github.com/kubernetes-sigs/kernel-module-management/internal/registry"
4848
"github.com/kubernetes-sigs/kernel-module-management/internal/sign"
4949
signjob "github.com/kubernetes-sigs/kernel-module-management/internal/sign/job"
50+
"github.com/kubernetes-sigs/kernel-module-management/internal/statusupdater"
5051
"github.com/kubernetes-sigs/kernel-module-management/internal/utils"
5152
//+kubebuilder:scaffold:imports
5253
)
@@ -133,6 +134,7 @@ func main() {
133134
client,
134135
manifestwork.NewCreator(client, scheme),
135136
cluster.NewClusterAPI(client, module.NewKernelMapper(), buildAPI, signAPI, operatorNamespace),
137+
statusupdater.NewManagedClusterModuleStatusUpdater(client),
136138
filterAPI,
137139
)
138140

config/crd-hub/bases/hub.kmm.sigs.x-k8s.io_managedclustermodules.yaml

+18
Original file line numberDiff line numberDiff line change
@@ -2412,6 +2412,24 @@ spec:
24122412
status:
24132413
description: ManagedClusterModuleStatus defines the observed state of
24142414
ManagedClusterModule.
2415+
properties:
2416+
numberApplied:
2417+
description: Number of ManifestWorks that have been successfully applied.
2418+
format: int32
2419+
type: integer
2420+
numberDegraded:
2421+
description: Number of ManifestWorks that could not be successfully
2422+
applied.
2423+
format: int32
2424+
type: integer
2425+
numberDesired:
2426+
description: Number of ManifestWorks to be applied.
2427+
format: int32
2428+
type: integer
2429+
required:
2430+
- numberApplied
2431+
- numberDegraded
2432+
- numberDesired
24152433
type: object
24162434
type: object
24172435
served: true

controllers/hub/managedclustermodule_reconciler.go

+19-7
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import (
2020
"context"
2121
"fmt"
2222

23-
hubv1beta1 "github.com/kubernetes-sigs/kernel-module-management/api-hub/v1beta1"
2423
batchv1 "k8s.io/api/batch/v1"
2524
k8serrors "k8s.io/apimachinery/pkg/api/errors"
2625
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -35,9 +34,11 @@ import (
3534
"sigs.k8s.io/controller-runtime/pkg/predicate"
3635
"sigs.k8s.io/controller-runtime/pkg/source"
3736

37+
hubv1beta1 "github.com/kubernetes-sigs/kernel-module-management/api-hub/v1beta1"
3838
"github.com/kubernetes-sigs/kernel-module-management/internal/cluster"
3939
"github.com/kubernetes-sigs/kernel-module-management/internal/filter"
4040
"github.com/kubernetes-sigs/kernel-module-management/internal/manifestwork"
41+
"github.com/kubernetes-sigs/kernel-module-management/internal/statusupdater"
4142
)
4243

4344
const ManagedClusterModuleReconcilerName = "ManagedClusterModule"
@@ -46,8 +47,9 @@ const ManagedClusterModuleReconcilerName = "ManagedClusterModule"
4647
type ManagedClusterModuleReconciler struct {
4748
client client.Client
4849

49-
manifestAPI manifestwork.ManifestWorkCreator
50-
clusterAPI cluster.ClusterAPI
50+
manifestAPI manifestwork.ManifestWorkCreator
51+
clusterAPI cluster.ClusterAPI
52+
statusupdaterAPI statusupdater.ManagedClusterModuleStatusUpdater
5153

5254
filter *filter.Filter
5355
}
@@ -63,12 +65,14 @@ func NewManagedClusterModuleReconciler(
6365
client client.Client,
6466
manifestAPI manifestwork.ManifestWorkCreator,
6567
clusterAPI cluster.ClusterAPI,
68+
statusupdaterAPI statusupdater.ManagedClusterModuleStatusUpdater,
6669
filter *filter.Filter) *ManagedClusterModuleReconciler {
6770
return &ManagedClusterModuleReconciler{
68-
client: client,
69-
manifestAPI: manifestAPI,
70-
clusterAPI: clusterAPI,
71-
filter: filter,
71+
client: client,
72+
manifestAPI: manifestAPI,
73+
clusterAPI: clusterAPI,
74+
statusupdaterAPI: statusupdaterAPI,
75+
filter: filter,
7276
}
7377
}
7478

@@ -140,6 +144,14 @@ func (r *ManagedClusterModuleReconciler) Reconcile(ctx context.Context, req ctrl
140144
logger.Info("Garbage-collected Build objects", "names", deleted)
141145
}
142146

147+
ownedManifestWorkList, err := r.manifestAPI.GetOwnedManifestWorks(ctx, *mcm)
148+
if err != nil {
149+
return res, fmt.Errorf("failed to fetch owned ManifestWorks of the ManagedClusterModule: %v", err)
150+
}
151+
if err := r.statusupdaterAPI.ManagedClusterModuleUpdateStatus(ctx, mcm, ownedManifestWorkList.Items); err != nil {
152+
return res, fmt.Errorf("failed to update status of the ManagedClusterModule: %v", err)
153+
}
154+
143155
return res, nil
144156
}
145157

controllers/hub/managedclustermodule_reconciler_test.go

+84-9
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import (
3737
"github.com/kubernetes-sigs/kernel-module-management/internal/client"
3838
"github.com/kubernetes-sigs/kernel-module-management/internal/cluster"
3939
"github.com/kubernetes-sigs/kernel-module-management/internal/manifestwork"
40+
"github.com/kubernetes-sigs/kernel-module-management/internal/statusupdater"
4041
)
4142

4243
var _ = Describe("ManagedClusterModuleReconciler_Reconcile", func() {
@@ -45,13 +46,15 @@ var _ = Describe("ManagedClusterModuleReconciler_Reconcile", func() {
4546
clnt *client.MockClient
4647
mockMW *manifestwork.MockManifestWorkCreator
4748
mockClusterAPI *cluster.MockClusterAPI
49+
mockSU *statusupdater.MockManagedClusterModuleStatusUpdater
4850
)
4951

5052
BeforeEach(func() {
5153
ctrl = gomock.NewController(GinkgoT())
5254
clnt = client.NewMockClient(ctrl)
5355
mockMW = manifestwork.NewMockManifestWorkCreator(ctrl)
5456
mockClusterAPI = cluster.NewMockClusterAPI(ctrl)
57+
mockSU = statusupdater.NewMockManagedClusterModuleStatusUpdater(ctrl)
5558
})
5659

5760
const (
@@ -73,7 +76,7 @@ var _ = Describe("ManagedClusterModuleReconciler_Reconcile", func() {
7376
apierrors.NewNotFound(schema.GroupResource{}, mcmName),
7477
)
7578

76-
mcmr := NewManagedClusterModuleReconciler(clnt, nil, mockClusterAPI, nil)
79+
mcmr := NewManagedClusterModuleReconciler(clnt, nil, mockClusterAPI, nil, nil)
7780
Expect(
7881
mcmr.Reconcile(ctx, req),
7982
).To(
@@ -85,7 +88,7 @@ var _ = Describe("ManagedClusterModuleReconciler_Reconcile", func() {
8588
mockClusterAPI.EXPECT().RequestedManagedClusterModule(ctx, req.NamespacedName).
8689
Return(nil, errors.New("test"))
8790

88-
mr := NewManagedClusterModuleReconciler(clnt, nil, mockClusterAPI, nil)
91+
mr := NewManagedClusterModuleReconciler(clnt, nil, mockClusterAPI, nil, nil)
8992

9093
res, err := mr.Reconcile(ctx, req)
9194
Expect(err).To(HaveOccurred())
@@ -112,7 +115,7 @@ var _ = Describe("ManagedClusterModuleReconciler_Reconcile", func() {
112115
),
113116
)
114117

115-
mr := NewManagedClusterModuleReconciler(clnt, nil, mockClusterAPI, nil)
118+
mr := NewManagedClusterModuleReconciler(clnt, nil, mockClusterAPI, nil, nil)
116119

117120
res, err := mr.Reconcile(context.Background(), req)
118121
Expect(err).To(HaveOccurred())
@@ -131,15 +134,18 @@ var _ = Describe("ManagedClusterModuleReconciler_Reconcile", func() {
131134
}
132135

133136
clusterList := clusterv1.ManagedClusterList{}
137+
manifestWorkList := workv1.ManifestWorkList{}
134138

135139
gomock.InOrder(
136140
mockClusterAPI.EXPECT().RequestedManagedClusterModule(ctx, req.NamespacedName).Return(mcm, nil),
137141
mockClusterAPI.EXPECT().SelectedManagedClusters(ctx, gomock.Any()).Return(&clusterList, nil),
138142
mockMW.EXPECT().GarbageCollect(ctx, clusterList, *mcm),
139143
mockClusterAPI.EXPECT().GarbageCollectBuilds(ctx, *mcm),
144+
mockMW.EXPECT().GetOwnedManifestWorks(ctx, *mcm).Return(&manifestWorkList, nil),
145+
mockSU.EXPECT().ManagedClusterModuleUpdateStatus(ctx, mcm, manifestWorkList.Items).Return(nil),
140146
)
141147

142-
mr := NewManagedClusterModuleReconciler(clnt, mockMW, mockClusterAPI, nil)
148+
mr := NewManagedClusterModuleReconciler(clnt, mockMW, mockClusterAPI, mockSU, nil)
143149

144150
res, err := mr.Reconcile(context.Background(), req)
145151
Expect(err).NotTo(HaveOccurred())
@@ -165,7 +171,7 @@ var _ = Describe("ManagedClusterModuleReconciler_Reconcile", func() {
165171
mockMW.EXPECT().GarbageCollect(ctx, clusterList, *mcm).Return(errors.New("test")),
166172
)
167173

168-
mr := NewManagedClusterModuleReconciler(clnt, mockMW, mockClusterAPI, nil)
174+
mr := NewManagedClusterModuleReconciler(clnt, mockMW, mockClusterAPI, nil, nil)
169175

170176
res, err := mr.Reconcile(context.Background(), req)
171177
Expect(err).To(HaveOccurred())
@@ -192,7 +198,65 @@ var _ = Describe("ManagedClusterModuleReconciler_Reconcile", func() {
192198
mockClusterAPI.EXPECT().GarbageCollectBuilds(ctx, *mcm).Return(nil, errors.New("test")),
193199
)
194200

195-
mr := NewManagedClusterModuleReconciler(clnt, mockMW, mockClusterAPI, nil)
201+
mr := NewManagedClusterModuleReconciler(clnt, mockMW, mockClusterAPI, nil, nil)
202+
203+
res, err := mr.Reconcile(context.Background(), req)
204+
Expect(err).To(HaveOccurred())
205+
Expect(res).To(Equal(reconcile.Result{}))
206+
})
207+
208+
It("should return an error when fetching the owned ManifestWorks fails", func() {
209+
mcm := &v1beta1.ManagedClusterModule{
210+
ObjectMeta: metav1.ObjectMeta{
211+
Name: mcmName,
212+
},
213+
Spec: v1beta1.ManagedClusterModuleSpec{
214+
ModuleSpec: kmmv1beta1.ModuleSpec{},
215+
Selector: map[string]string{"key": "value"},
216+
},
217+
}
218+
219+
clusterList := clusterv1.ManagedClusterList{}
220+
221+
gomock.InOrder(
222+
mockClusterAPI.EXPECT().RequestedManagedClusterModule(ctx, req.NamespacedName).Return(mcm, nil),
223+
mockClusterAPI.EXPECT().SelectedManagedClusters(ctx, gomock.Any()).Return(&clusterList, nil),
224+
mockMW.EXPECT().GarbageCollect(ctx, clusterList, *mcm),
225+
mockClusterAPI.EXPECT().GarbageCollectBuilds(ctx, *mcm),
226+
mockMW.EXPECT().GetOwnedManifestWorks(ctx, *mcm).Return(nil, errors.New("generic-error")),
227+
)
228+
229+
mr := NewManagedClusterModuleReconciler(clnt, mockMW, mockClusterAPI, nil, nil)
230+
231+
res, err := mr.Reconcile(context.Background(), req)
232+
Expect(err).To(HaveOccurred())
233+
Expect(res).To(Equal(reconcile.Result{}))
234+
})
235+
236+
It("should return an error when status update fails", func() {
237+
mcm := &v1beta1.ManagedClusterModule{
238+
ObjectMeta: metav1.ObjectMeta{
239+
Name: mcmName,
240+
},
241+
Spec: v1beta1.ManagedClusterModuleSpec{
242+
ModuleSpec: kmmv1beta1.ModuleSpec{},
243+
Selector: map[string]string{"key": "value"},
244+
},
245+
}
246+
247+
clusterList := clusterv1.ManagedClusterList{}
248+
manifestWorkList := workv1.ManifestWorkList{}
249+
250+
gomock.InOrder(
251+
mockClusterAPI.EXPECT().RequestedManagedClusterModule(ctx, req.NamespacedName).Return(mcm, nil),
252+
mockClusterAPI.EXPECT().SelectedManagedClusters(ctx, gomock.Any()).Return(&clusterList, nil),
253+
mockMW.EXPECT().GarbageCollect(ctx, clusterList, *mcm),
254+
mockClusterAPI.EXPECT().GarbageCollectBuilds(ctx, *mcm),
255+
mockMW.EXPECT().GetOwnedManifestWorks(ctx, *mcm).Return(&manifestWorkList, nil),
256+
mockSU.EXPECT().ManagedClusterModuleUpdateStatus(ctx, mcm, manifestWorkList.Items).Return(errors.New("generic-error")),
257+
)
258+
259+
mr := NewManagedClusterModuleReconciler(clnt, mockMW, mockClusterAPI, mockSU, nil)
196260

197261
res, err := mr.Reconcile(context.Background(), req)
198262
Expect(err).To(HaveOccurred())
@@ -227,15 +291,19 @@ var _ = Describe("ManagedClusterModuleReconciler_Reconcile", func() {
227291
},
228292
}
229293

294+
manifestWorkList := workv1.ManifestWorkList{}
295+
230296
gomock.InOrder(
231297
mockClusterAPI.EXPECT().RequestedManagedClusterModule(ctx, req.NamespacedName).Return(&mcm, nil),
232298
mockClusterAPI.EXPECT().SelectedManagedClusters(ctx, gomock.Any()).Return(&clusterList, nil),
233299
mockClusterAPI.EXPECT().BuildAndSign(gomock.Any(), mcm, clusterList.Items[0]).Return(true, nil),
234300
mockMW.EXPECT().GarbageCollect(ctx, clusterList, mcm),
235301
mockClusterAPI.EXPECT().GarbageCollectBuilds(ctx, mcm),
302+
mockMW.EXPECT().GetOwnedManifestWorks(ctx, mcm).Return(&manifestWorkList, nil),
303+
mockSU.EXPECT().ManagedClusterModuleUpdateStatus(ctx, &mcm, manifestWorkList.Items).Return(nil),
236304
)
237305

238-
mr := NewManagedClusterModuleReconciler(clnt, mockMW, mockClusterAPI, nil)
306+
mr := NewManagedClusterModuleReconciler(clnt, mockMW, mockClusterAPI, mockSU, nil)
239307

240308
res, err := mr.Reconcile(context.Background(), req)
241309
Expect(err).ToNot(HaveOccurred())
@@ -263,6 +331,7 @@ var _ = Describe("ManagedClusterModuleReconciler_Reconcile", func() {
263331
},
264332
},
265333
}
334+
manifestWorkList := workv1.ManifestWorkList{}
266335

267336
mw := workv1.ManifestWork{
268337
ObjectMeta: metav1.ObjectMeta{
@@ -280,9 +349,11 @@ var _ = Describe("ManagedClusterModuleReconciler_Reconcile", func() {
280349
clnt.EXPECT().Create(gomock.Any(), gomock.Any()).Return(nil),
281350
mockMW.EXPECT().GarbageCollect(ctx, clusterList, mcm),
282351
mockClusterAPI.EXPECT().GarbageCollectBuilds(ctx, mcm),
352+
mockMW.EXPECT().GetOwnedManifestWorks(ctx, mcm).Return(&manifestWorkList, nil),
353+
mockSU.EXPECT().ManagedClusterModuleUpdateStatus(ctx, &mcm, manifestWorkList.Items).Return(nil),
283354
)
284355

285-
mr := NewManagedClusterModuleReconciler(clnt, mockMW, mockClusterAPI, nil)
356+
mr := NewManagedClusterModuleReconciler(clnt, mockMW, mockClusterAPI, mockSU, nil)
286357

287358
res, err := mr.Reconcile(context.Background(), req)
288359
Expect(err).NotTo(HaveOccurred())
@@ -311,6 +382,8 @@ var _ = Describe("ManagedClusterModuleReconciler_Reconcile", func() {
311382
},
312383
}
313384

385+
manifestWorkList := workv1.ManifestWorkList{}
386+
314387
mw := workv1.ManifestWork{
315388
ObjectMeta: metav1.ObjectMeta{
316389
Name: mcm.Name,
@@ -330,9 +403,11 @@ var _ = Describe("ManagedClusterModuleReconciler_Reconcile", func() {
330403
clnt.EXPECT().Patch(gomock.Any(), gomock.Any(), gomock.Any()),
331404
mockMW.EXPECT().GarbageCollect(ctx, clusterList, mcm),
332405
mockClusterAPI.EXPECT().GarbageCollectBuilds(ctx, mcm),
406+
mockMW.EXPECT().GetOwnedManifestWorks(ctx, mcm).Return(&manifestWorkList, nil),
407+
mockSU.EXPECT().ManagedClusterModuleUpdateStatus(ctx, &mcm, manifestWorkList.Items).Return(nil),
333408
)
334409

335-
mr := NewManagedClusterModuleReconciler(clnt, mockMW, mockClusterAPI, nil)
410+
mr := NewManagedClusterModuleReconciler(clnt, mockMW, mockClusterAPI, mockSU, nil)
336411

337412
res, err := mr.Reconcile(context.Background(), req)
338413
Expect(err).NotTo(HaveOccurred())

internal/manifestwork/manifestwork.go

+5
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424

2525
type ManifestWorkCreator interface {
2626
GarbageCollect(ctx context.Context, clusters clusterv1.ManagedClusterList, mcm hubv1beta1.ManagedClusterModule) error
27+
GetOwnedManifestWorks(ctx context.Context, mcm hubv1beta1.ManagedClusterModule) (*workv1.ManifestWorkList, error)
2728
SetManifestWorkAsDesired(ctx context.Context, mw *workv1.ManifestWork, mcm hubv1beta1.ManagedClusterModule) error
2829
}
2930

@@ -63,6 +64,10 @@ func (mwg *manifestWorkGenerator) GarbageCollect(ctx context.Context, clusters c
6364
return nil
6465
}
6566

67+
func (mwg *manifestWorkGenerator) GetOwnedManifestWorks(ctx context.Context, mcm hubv1beta1.ManagedClusterModule) (*workv1.ManifestWorkList, error) {
68+
return mwg.getOwnedManifestWorks(ctx, mcm)
69+
}
70+
6671
func (mwg *manifestWorkGenerator) SetManifestWorkAsDesired(ctx context.Context, mw *workv1.ManifestWork, mcm hubv1beta1.ManagedClusterModule) error {
6772
if mw == nil {
6873
return errors.New("mw cannot be nil")

0 commit comments

Comments
 (0)