Skip to content

Commit 9b6e7a3

Browse files
Merge pull request #1721 from njhale/fix-crd-adopt
Bug 1861636: fix(operator): re-adopt manually disowned crds
2 parents 2bf9530 + 76fb295 commit 9b6e7a3

File tree

2 files changed

+110
-22
lines changed

2 files changed

+110
-22
lines changed

pkg/controller/operators/adoption_controller.go

Lines changed: 52 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,14 @@ func (r *AdoptionReconciler) SetupWithManager(mgr ctrl.Manager) error {
5959
return err
6060
}
6161

62-
enqueueCSV := &handler.EnqueueRequestsFromMapFunc{
63-
ToRequests: handler.ToRequestsFunc(r.mapToClusterServiceVersions),
64-
}
62+
var (
63+
enqueueCSV = &handler.EnqueueRequestsFromMapFunc{
64+
ToRequests: handler.ToRequestsFunc(r.mapToClusterServiceVersions),
65+
}
66+
enqueueProviders = &handler.EnqueueRequestsFromMapFunc{
67+
ToRequests: handler.ToRequestsFunc(r.mapToProviders),
68+
}
69+
)
6570
err = ctrl.NewControllerManagedBy(mgr).
6671
For(&operatorsv1alpha1.ClusterServiceVersion{}).
6772
Watches(&source.Kind{Type: &appsv1.Deployment{}}, enqueueCSV).
@@ -74,7 +79,7 @@ func (r *AdoptionReconciler) SetupWithManager(mgr ctrl.Manager) error {
7479
Watches(&source.Kind{Type: &rbacv1.RoleBinding{}}, enqueueCSV).
7580
Watches(&source.Kind{Type: &rbacv1.ClusterRole{}}, enqueueCSV).
7681
Watches(&source.Kind{Type: &rbacv1.ClusterRoleBinding{}}, enqueueCSV).
77-
Watches(&source.Kind{Type: &apiextensionsv1.CustomResourceDefinition{}}, enqueueCSV).
82+
Watches(&source.Kind{Type: &apiextensionsv1.CustomResourceDefinition{}}, enqueueProviders).
7883
Watches(&source.Kind{Type: &apiregistrationv1.APIService{}}, enqueueCSV).
7984
Watches(&source.Kind{Type: &operatorsv1alpha1.Subscription{}}, enqueueCSV).
8085
Complete(reconcile.Func(r.ReconcileClusterServiceVersion))
@@ -110,7 +115,7 @@ func NewAdoptionReconciler(cli client.Client, log logr.Logger, scheme *runtime.S
110115
func (r *AdoptionReconciler) ReconcileSubscription(req ctrl.Request) (reconcile.Result, error) {
111116
// Set up a convenient log object so we don't have to type request over and over again
112117
log := r.log.WithValues("request", req)
113-
log.V(1).Info("reconciling subscription")
118+
log.V(4).Info("reconciling subscription")
114119

115120
// Fetch the Subscription from the cache
116121
ctx := context.TODO()
@@ -173,7 +178,7 @@ func (r *AdoptionReconciler) ReconcileSubscription(req ctrl.Request) (reconcile.
173178
func (r *AdoptionReconciler) ReconcileClusterServiceVersion(req ctrl.Request) (reconcile.Result, error) {
174179
// Set up a convenient log object so we don't have to type request over and over again
175180
log := r.log.WithValues("request", req)
176-
log.V(1).Info("reconciling ClusterServiceVersion")
181+
log.V(4).Info("reconciling csv")
177182

178183
// Fetch the CSV from the cache
179184
ctx := context.TODO()
@@ -228,7 +233,6 @@ func (r *AdoptionReconciler) adoptComponents(ctx context.Context, csv *operators
228233
defer mu.Unlock()
229234
errs = append(errs, err)
230235
}()
231-
continue
232236
}
233237

234238
for _, component := range components {
@@ -371,11 +375,7 @@ func (r *AdoptionReconciler) adoptees(ctx context.Context, operator decorators.O
371375
components = append(components, crd)
372376
}
373377

374-
if err := utilerrors.NewAggregate(errs); err != nil {
375-
return nil, err
376-
}
377-
378-
return components, nil
378+
return components, utilerrors.NewAggregate(errs)
379379
}
380380

381381
func (r *AdoptionReconciler) adoptInstallPlan(ctx context.Context, operator *decorators.Operator, latest *operatorsv1alpha1.InstallPlan) error {
@@ -423,12 +423,20 @@ func (r *AdoptionReconciler) mapToSubscriptions(obj handler.MapObject) (requests
423423
ctx := context.TODO()
424424
subs := &operatorsv1alpha1.SubscriptionList{}
425425
if err := r.List(ctx, subs, client.InNamespace(obj.Meta.GetNamespace())); err != nil {
426-
r.log.Error(err, "couldn't list subscriptions")
426+
r.log.Error(err, "error listing subscriptions")
427427
}
428428

429+
visited := map[types.NamespacedName]struct{}{}
429430
for _, sub := range subs.Items {
430431
nsn := types.NamespacedName{Namespace: sub.GetNamespace(), Name: sub.GetName()}
432+
433+
if _, ok := visited[nsn]; ok {
434+
// Already requested
435+
continue
436+
}
437+
431438
requests = append(requests, reconcile.Request{NamespacedName: nsn})
439+
visited[nsn] = struct{}{}
432440
}
433441

434442
return
@@ -440,24 +448,51 @@ func (r *AdoptionReconciler) mapToClusterServiceVersions(obj handler.MapObject)
440448
}
441449

442450
// Get all owner CSV from owner labels if cluster scoped
443-
if obj.Meta.GetNamespace() == metav1.NamespaceAll {
451+
namespace := obj.Meta.GetNamespace()
452+
if namespace == metav1.NamespaceAll {
444453
name, ns, ok := ownerutil.GetOwnerByKindLabel(obj.Meta, operatorsv1alpha1.ClusterServiceVersionKind)
445454
if ok {
446455
nsn := types.NamespacedName{Namespace: ns, Name: name}
447456
requests = append(requests, reconcile.Request{NamespacedName: nsn})
448457
}
449-
450458
return
451459
}
452460

453461
// Get all owner CSVs from OwnerReferences
454462
owners := ownerutil.GetOwnersByKind(obj.Meta, operatorsv1alpha1.ClusterServiceVersionKind)
455463
for _, owner := range owners {
456-
nsn := types.NamespacedName{Namespace: obj.Meta.GetNamespace(), Name: owner.Name}
464+
nsn := types.NamespacedName{Namespace: namespace, Name: owner.Name}
457465
requests = append(requests, reconcile.Request{NamespacedName: nsn})
458466
}
459467

460-
// TODO(njhale): Requeue CSVs on CRD changes
468+
return
469+
}
470+
471+
func (r *AdoptionReconciler) mapToProviders(obj handler.MapObject) (requests []reconcile.Request) {
472+
if obj.Meta == nil {
473+
return nil
474+
}
475+
476+
var (
477+
ctx = context.TODO()
478+
csvs = &operatorsv1alpha1.ClusterServiceVersionList{}
479+
)
480+
if err := r.List(ctx, csvs); err != nil {
481+
r.log.Error(err, "error listing csvs")
482+
return
483+
}
484+
485+
for _, csv := range csvs.Items {
486+
request := reconcile.Request{
487+
NamespacedName: types.NamespacedName{Namespace: csv.GetNamespace(), Name: csv.GetName()},
488+
}
489+
for _, provided := range csv.Spec.CustomResourceDefinitions.Owned {
490+
if provided.Name == obj.Meta.GetName() {
491+
requests = append(requests, request)
492+
break
493+
}
494+
}
495+
}
461496

462497
return
463498
}

pkg/controller/operators/adoption_controller_test.go

Lines changed: 58 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -184,9 +184,23 @@ var _ = Describe("Adoption Controller", func() {
184184

185185
Context("that has an existing installed csv", func() {
186186

187+
var (
188+
providedCRD *apiextensionsv1.CustomResourceDefinition
189+
)
190+
187191
BeforeEach(func() {
192+
providedCRD = fixtures.Fill(&apiextensionsv1.CustomResourceDefinition{}).(*apiextensionsv1.CustomResourceDefinition)
188193
installed = &operatorsv1alpha1.ClusterServiceVersion{
189194
Spec: operatorsv1alpha1.ClusterServiceVersionSpec{
195+
CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{
196+
Owned: []operatorsv1alpha1.CRDDescription{
197+
{
198+
Name: providedCRD.GetName(),
199+
Kind: providedCRD.Spec.Names.Kind,
200+
Version: providedCRD.Spec.Versions[0].Name,
201+
},
202+
},
203+
},
190204
InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{
191205
StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment,
192206
StrategySpec: operatorsv1alpha1.StrategyDetailsDeployment{
@@ -215,6 +229,49 @@ var _ = Describe("Adoption Controller", func() {
215229
})
216230
})
217231

232+
Context("with an existing provided CRD", func() {
233+
BeforeEach(func() {
234+
Eventually(func() error {
235+
return k8sClient.Create(ctx, providedCRD)
236+
}, timeout, interval).Should(Succeed())
237+
created = append(created, providedCRD)
238+
239+
Eventually(func() (map[string]string, error) {
240+
latest := &apiextensionsv1.CustomResourceDefinition{}
241+
err := k8sClient.Get(ctx, testobj.NamespacedName(providedCRD), latest)
242+
243+
return latest.GetLabels(), err
244+
}, timeout, interval).Should(HaveKey(componentLabelKey))
245+
})
246+
247+
Context("when its component label is removed", func() {
248+
BeforeEach(func() {
249+
Eventually(func() error {
250+
latest := &apiextensionsv1.CustomResourceDefinition{}
251+
if err := k8sClient.Get(ctx, testobj.NamespacedName(providedCRD), latest); err != nil {
252+
return err
253+
}
254+
255+
if len(latest.GetLabels()) == 0 {
256+
return nil
257+
}
258+
delete(latest.GetLabels(), componentLabelKey)
259+
260+
return k8sClient.Update(ctx, latest)
261+
}, timeout, interval).Should(Succeed())
262+
})
263+
264+
It("should be relabelled", func() {
265+
Eventually(func() (map[string]string, error) {
266+
latest := &apiextensionsv1.CustomResourceDefinition{}
267+
err := k8sClient.Get(ctx, testobj.NamespacedName(providedCRD), latest)
268+
269+
return latest.GetLabels(), err
270+
}, timeout, interval).Should(HaveKey(componentLabelKey))
271+
})
272+
})
273+
})
274+
218275
Context("that has resources owned by the installed csv", func() {
219276
var (
220277
components []testobj.RuntimeMetaObject
@@ -289,10 +346,6 @@ var _ = Describe("Adoption Controller", func() {
289346
ownerLabels,
290347
fixtures.Fill(&rbacv1.ClusterRoleBinding{}),
291348
),
292-
testobj.WithLabels(
293-
ownerLabels,
294-
fixtures.Fill(&apiextensionsv1.CustomResourceDefinition{}),
295-
),
296349
testobj.WithLabels(
297350
ownerLabels,
298351
fixtures.Fill(&apiregistrationv1.APIService{}),
@@ -306,7 +359,7 @@ var _ = Describe("Adoption Controller", func() {
306359
}
307360
})
308361

309-
Specify("component label", func() {
362+
Specify("a component label", func() {
310363
for _, component := range components {
311364
Eventually(func() (map[string]string, error) {
312365
err := k8sClient.Get(ctx, testobj.NamespacedName(component), component)

0 commit comments

Comments
 (0)