Skip to content

Commit 8a4a39f

Browse files
committed
ClusterOperator owns all objects created by CapiInstallerController
1 parent fac6c36 commit 8a4a39f

File tree

2 files changed

+56
-40
lines changed

2 files changed

+56
-40
lines changed

pkg/controllers/capiinstaller/capi_installer_controller.go

Lines changed: 51 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,12 @@ import (
3232
rbacv1 "k8s.io/api/rbac/v1"
3333
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
3434
apiextensionsclient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
35+
apierrors "k8s.io/apimachinery/pkg/api/errors"
36+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3537
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
3638
"k8s.io/apimachinery/pkg/runtime"
3739
"k8s.io/apimachinery/pkg/runtime/serializer"
40+
"k8s.io/utils/ptr"
3841

3942
"k8s.io/client-go/kubernetes"
4043
"k8s.io/client-go/rest"
@@ -90,7 +93,17 @@ type CapiInstallerController struct {
9093
func (r *CapiInstallerController) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
9194
log := ctrl.LoggerFrom(ctx).WithName(controllerName)
9295

93-
res, err := r.reconcile(ctx, log)
96+
clusterOperator := &configv1.ClusterOperator{}
97+
if err := r.Get(ctx, client.ObjectKey{Name: controllers.ClusterOperatorName}, clusterOperator); err != nil {
98+
if apierrors.IsNotFound(err) {
99+
log.Info("Waiting for creation of cluster operator")
100+
return ctrl.Result{}, nil
101+
}
102+
103+
return ctrl.Result{}, fmt.Errorf("failed to get cluster operator: %w", err)
104+
}
105+
106+
res, err := r.reconcile(ctx, log, clusterOperator)
94107
if err != nil {
95108
return ctrl.Result{}, fmt.Errorf("error during reconcile: %w", err)
96109
}
@@ -108,7 +121,7 @@ func (r *CapiInstallerController) Reconcile(ctx context.Context, req ctrl.Reques
108121
// and it applies them to the cluster.
109122
//
110123
//nolint:unparam
111-
func (r *CapiInstallerController) reconcile(ctx context.Context, log logr.Logger) (ctrl.Result, error) {
124+
func (r *CapiInstallerController) reconcile(ctx context.Context, log logr.Logger, clusterOperator *configv1.ClusterOperator) (ctrl.Result, error) {
112125
// Define the desired providers to be installed for this cluster.
113126
// We always want to install the core provider, which in our case is the default cluster-api core provider.
114127
// We also want to install the infrastructure provider that matches the currently detected platform the cluster is running on.
@@ -156,7 +169,7 @@ func (r *CapiInstallerController) reconcile(ctx context.Context, log logr.Logger
156169
}
157170

158171
// Apply all the collected provider components manifests.
159-
if err := r.applyProviderComponents(ctx, providerComponents); err != nil {
172+
if err := r.applyProviderComponents(ctx, providerComponents, clusterOperator); err != nil {
160173
if err := r.setDegradedCondition(ctx, log); err != nil {
161174
return ctrl.Result{}, fmt.Errorf("failed to set conditions for CAPI Installer controller: %w", err)
162175
}
@@ -172,7 +185,7 @@ func (r *CapiInstallerController) reconcile(ctx context.Context, log logr.Logger
172185

173186
// applyProviderComponents applies the provider components to the cluster.
174187
// It does so by differentiating between static components and dynamic components (i.e. Deployments).
175-
func (r *CapiInstallerController) applyProviderComponents(ctx context.Context, components []string) error {
188+
func (r *CapiInstallerController) applyProviderComponents(ctx context.Context, components []string, owner client.Object) error {
176189
providerObjects, err := getProviderObjects(r.Scheme, components)
177190
if err != nil {
178191
return fmt.Errorf("error getting provider components: %w", err)
@@ -181,6 +194,17 @@ func (r *CapiInstallerController) applyProviderComponents(ctx context.Context, c
181194
var errs error
182195

183196
for i, providerObject := range providerObjects {
197+
// All objects created by cluster-capi-operator are owned by its cluster operator
198+
providerObject.SetOwnerReferences([]metav1.OwnerReference{
199+
{
200+
APIVersion: owner.GetObjectKind().GroupVersionKind().Version,
201+
Kind: owner.GetObjectKind().GroupVersionKind().Kind,
202+
Name: owner.GetName(),
203+
UID: owner.GetUID(),
204+
Controller: ptr.To(true),
205+
},
206+
})
207+
184208
err := r.Patch(ctx, providerObject, client.Apply, client.ForceOwnership, client.FieldOwner("cluster-capi-operator.openshift.io/installer"))
185209
if err != nil {
186210
gvk := providerObject.GroupVersionKind()
@@ -268,41 +292,44 @@ func (r *CapiInstallerController) SetupWithManager(mgr ctrl.Manager) error {
268292
Watches(
269293
&corev1.ConfigMap{},
270294
handler.EnqueueRequestsFromMapFunc(toClusterOperator),
271-
builder.WithPredicates(configMapPredicate(r.ManagedNamespace, r.Platform)),
295+
builder.WithPredicates(transportConfigMapPredicate(r.ManagedNamespace, r.Platform)),
272296
)
273297

274-
// All of the following watches share the ownedPlatformLabelPredicate.
275-
watches := []struct {
298+
// All of the following ownsTypes share the ownedPlatformLabelPredicate.
299+
ownsTypes := []struct {
276300
obj client.Object
277301
namespace string
278302
}{
279-
{&appsv1.Deployment{}, r.ManagedNamespace},
280-
{&admissionregistrationv1.ValidatingWebhookConfiguration{}, notNamespaced},
281303
{&admissionregistrationv1.MutatingWebhookConfiguration{}, notNamespaced},
304+
{&admissionregistrationv1.ValidatingWebhookConfiguration{}, notNamespaced},
282305
{&admissionregistrationv1beta1.ValidatingAdmissionPolicy{}, notNamespaced},
283306
{&admissionregistrationv1beta1.ValidatingAdmissionPolicyBinding{}, notNamespaced},
284-
{&corev1.Service{}, r.ManagedNamespace},
285307
{&apiextensionsv1.CustomResourceDefinition{}, notNamespaced},
308+
{&appsv1.Deployment{}, r.ManagedNamespace},
309+
{&corev1.ConfigMap{}, r.ManagedNamespace},
310+
{&corev1.Service{}, r.ManagedNamespace},
286311
{&corev1.ServiceAccount{}, r.ManagedNamespace},
287-
{&rbacv1.ClusterRoleBinding{}, notNamespaced},
288312
{&rbacv1.ClusterRole{}, notNamespaced},
313+
{&rbacv1.ClusterRoleBinding{}, notNamespaced},
289314
{&rbacv1.Role{}, r.ManagedNamespace},
290315
{&rbacv1.RoleBinding{}, r.ManagedNamespace},
291316
}
292317

293-
for _, w := range watches {
294-
build = build.Watches(
295-
w.obj,
296-
handler.EnqueueRequestsFromMapFunc(toClusterOperator),
297-
builder.WithPredicates(
298-
ownedPlatformLabelPredicate(w.namespace, r.Platform),
299-
300-
// We're only interested in changes which affect an object's spec
301-
predicate.AnnotationChangedPredicate{},
302-
predicate.LabelChangedPredicate{},
303-
predicate.GenerationChangedPredicate{},
304-
),
305-
)
318+
for _, owned := range ownsTypes {
319+
predicates := []predicate.Predicate{
320+
// We're only interested in changes which affect an object's spec
321+
predicate.AnnotationChangedPredicate{},
322+
predicate.LabelChangedPredicate{},
323+
predicate.GenerationChangedPredicate{},
324+
}
325+
326+
if owned.namespace != notNamespaced {
327+
predicates = append(predicates, predicate.NewPredicateFuncs(func(obj client.Object) bool {
328+
return obj.GetNamespace() == owned.namespace
329+
}))
330+
}
331+
332+
build = build.Owns(owned.obj, builder.WithPredicates(predicates...))
306333
}
307334

308335
if err := build.Complete(r); err != nil {

pkg/controllers/capiinstaller/watch_predicates.go

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -48,22 +48,11 @@ func toClusterOperator(ctx context.Context, cO client.Object) []reconcile.Reques
4848
}}
4949
}
5050

51-
// configMapPredicate defines a predicate function for owned ConfigMaps.
52-
func configMapPredicate(namespace string, platform configv1.PlatformType) predicate.Funcs {
53-
return predicate.Funcs{
54-
CreateFunc: func(e event.CreateEvent) bool { return isOwnedProviderComponent(e.Object, namespace, platform) },
55-
UpdateFunc: func(e event.UpdateEvent) bool { return isOwnedProviderComponent(e.ObjectNew, namespace, platform) },
56-
DeleteFunc: func(e event.DeleteEvent) bool { return isOwnedProviderComponent(e.Object, namespace, platform) },
57-
GenericFunc: func(e event.GenericEvent) bool { return isOwnedProviderComponent(e.Object, namespace, platform) },
58-
}
59-
}
60-
61-
// ownedPlatformLabelPredicate defines a predicate function for owned objects.
62-
func ownedPlatformLabelPredicate(namespace string, platform configv1.PlatformType) predicate.Funcs {
63-
return predicate.Funcs{
64-
UpdateFunc: func(e event.UpdateEvent) bool { return isOwnedProviderComponent(e.ObjectNew, namespace, platform) },
65-
DeleteFunc: func(e event.DeleteEvent) bool { return isOwnedProviderComponent(e.Object, namespace, platform) },
66-
}
51+
// transportConfigMapPredicate defines a predicate function for transport ConfigMaps.
52+
func transportConfigMapPredicate(namespace string, platform configv1.PlatformType) predicate.Funcs {
53+
return predicate.NewPredicateFuncs(func(obj client.Object) bool {
54+
return isOwnedProviderComponent(obj, namespace, platform)
55+
})
6756
}
6857

6958
// isOwnedProviderComponent checks whether an object is an owned provider component.

0 commit comments

Comments
 (0)