Skip to content

Commit d2a9bf8

Browse files
authored
Merge pull request #354 from Danil-Grigorev/refactor-healthcheck
🌱 Refactor healthcheck to reconcile only owned deployments
2 parents 7b1830f + e1d3bb4 commit d2a9bf8

File tree

1 file changed

+85
-64
lines changed

1 file changed

+85
-64
lines changed

internal/controller/healthcheck/healthcheck_controller.go

Lines changed: 85 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,23 @@ package healthcheck
1818

1919
import (
2020
"context"
21-
"fmt"
2221
"time"
2322

2423
appsv1 "k8s.io/api/apps/v1"
2524
corev1 "k8s.io/api/core/v1"
26-
"k8s.io/apimachinery/pkg/runtime"
25+
"k8s.io/apimachinery/pkg/runtime/schema"
2726
"k8s.io/apimachinery/pkg/types"
27+
28+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
29+
"k8s.io/apimachinery/pkg/runtime"
30+
kerrors "k8s.io/apimachinery/pkg/util/errors"
2831
operatorv1 "sigs.k8s.io/cluster-api-operator/api/v1alpha2"
2932
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
3033
"sigs.k8s.io/cluster-api/util/conditions"
3134
"sigs.k8s.io/cluster-api/util/patch"
3235
ctrl "sigs.k8s.io/controller-runtime"
36+
37+
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
3338
"sigs.k8s.io/controller-runtime/pkg/builder"
3439
"sigs.k8s.io/controller-runtime/pkg/client"
3540
"sigs.k8s.io/controller-runtime/pkg/controller"
@@ -38,22 +43,76 @@ import (
3843
"sigs.k8s.io/controller-runtime/pkg/reconcile"
3944
)
4045

46+
func init() {
47+
var err error
48+
deploymentPredicate, err = predicate.LabelSelectorPredicate(metav1.LabelSelector{
49+
MatchExpressions: []metav1.LabelSelectorRequirement{{
50+
Key: providerLabelKey,
51+
Operator: metav1.LabelSelectorOpExists,
52+
}},
53+
})
54+
utilruntime.Must(err)
55+
}
56+
57+
const providerLabelKey = "cluster.x-k8s.io/provider"
58+
59+
var deploymentPredicate predicate.Predicate
60+
4161
type ProviderHealthCheckReconciler struct {
4262
Client client.Client
4363
}
4464

45-
const (
46-
providerLabelKey = "cluster.x-k8s.io/provider"
47-
)
65+
type GenericProviderHealthCheckReconciler struct {
66+
Client client.Client
67+
Provider operatorv1.GenericProvider
68+
providerGVK schema.GroupVersionKind
69+
}
4870

4971
func (r *ProviderHealthCheckReconciler) SetupWithManager(mgr ctrl.Manager, options controller.Options) error {
72+
return kerrors.NewAggregate([]error{
73+
(&GenericProviderHealthCheckReconciler{
74+
Client: mgr.GetClient(),
75+
Provider: &operatorv1.CoreProvider{},
76+
}).SetupWithManager(mgr, options),
77+
(&GenericProviderHealthCheckReconciler{
78+
Client: mgr.GetClient(),
79+
Provider: &operatorv1.InfrastructureProvider{},
80+
}).SetupWithManager(mgr, options),
81+
(&GenericProviderHealthCheckReconciler{
82+
Client: mgr.GetClient(),
83+
Provider: &operatorv1.BootstrapProvider{},
84+
}).SetupWithManager(mgr, options),
85+
(&GenericProviderHealthCheckReconciler{
86+
Client: mgr.GetClient(),
87+
Provider: &operatorv1.ControlPlaneProvider{},
88+
}).SetupWithManager(mgr, options),
89+
(&GenericProviderHealthCheckReconciler{
90+
Client: mgr.GetClient(),
91+
Provider: &operatorv1.AddonProvider{},
92+
}).SetupWithManager(mgr, options),
93+
(&GenericProviderHealthCheckReconciler{
94+
Client: mgr.GetClient(),
95+
Provider: &operatorv1.IPAMProvider{},
96+
}).SetupWithManager(mgr, options),
97+
})
98+
}
99+
100+
func (r *GenericProviderHealthCheckReconciler) SetupWithManager(mgr ctrl.Manager, options controller.Options) error {
101+
kinds, _, err := r.Client.Scheme().ObjectKinds(r.Provider)
102+
if err != nil {
103+
return err
104+
}
105+
106+
r.providerGVK = kinds[0]
107+
50108
return ctrl.NewControllerManagedBy(mgr).
51-
For(&appsv1.Deployment{}, builder.WithPredicates(providerDeploymentPredicates())).
109+
For(&appsv1.Deployment{}, builder.WithPredicates(r.providerDeploymentPredicates())).
110+
WithEventFilter(deploymentPredicate).
52111
WithOptions(options).
53112
Complete(r)
54113
}
55114

56-
func (r *ProviderHealthCheckReconciler) Reconcile(ctx context.Context, req reconcile.Request) (_ reconcile.Result, reterr error) {
115+
func (r *GenericProviderHealthCheckReconciler) Reconcile(ctx context.Context, req reconcile.Request) (_ reconcile.Result, reterr error) {
57116
log := ctrl.LoggerFrom(ctx)
58117

59118
log.Info("Checking provider health")
@@ -67,19 +126,15 @@ func (r *ProviderHealthCheckReconciler) Reconcile(ctx context.Context, req recon
67126
return result, err
68127
}
69128

70-
// There should be just one owner reference - to a Provider resource.
71-
if len(deployment.GetOwnerReferences()) != 1 {
72-
return result, fmt.Errorf("incorrect number of owner references for provider deployment %s", req.NamespacedName)
129+
// There should be one owner pointing to the Provider resource.
130+
if err := r.Client.Get(ctx, r.getProviderKey(deployment), r.Provider); err != nil {
131+
// Error reading the object - requeue the request.
132+
return result, err
73133
}
74134

75-
deploymentOwner := deployment.GetOwnerReferences()[0]
76-
77135
deploymentAvailableCondition := getDeploymentCondition(deployment.Status, appsv1.DeploymentAvailable)
78136

79-
typedProvider, err := r.getGenericProvider(ctx, deploymentOwner.Kind, deploymentOwner.Name, req.Namespace)
80-
if err != nil {
81-
return result, err
82-
}
137+
typedProvider := r.Provider
83138

84139
// Stop earlier if this provider is not fully installed yet.
85140
if !conditions.IsTrue(typedProvider, operatorv1.ProviderInstalledCondition) {
@@ -122,52 +177,20 @@ func (r *ProviderHealthCheckReconciler) Reconcile(ctx context.Context, req recon
122177
return result, patchHelper.Patch(ctx, typedProvider, options)
123178
}
124179

125-
func (r *ProviderHealthCheckReconciler) getGenericProvider(ctx context.Context, providerKind, providerName, providerNamespace string) (operatorv1.GenericProvider, error) {
126-
switch providerKind {
127-
case "CoreProvider":
128-
provider := &operatorv1.CoreProvider{}
129-
if err := r.Client.Get(ctx, types.NamespacedName{Name: providerName, Namespace: providerNamespace}, provider); err != nil {
130-
return nil, err
131-
}
132-
133-
return provider, nil
134-
case "BootstrapProvider":
135-
provider := &operatorv1.BootstrapProvider{}
136-
if err := r.Client.Get(ctx, types.NamespacedName{Name: providerName, Namespace: providerNamespace}, provider); err != nil {
137-
return nil, err
138-
}
139-
140-
return provider, nil
141-
case "ControlPlaneProvider":
142-
provider := &operatorv1.ControlPlaneProvider{}
143-
if err := r.Client.Get(ctx, types.NamespacedName{Name: providerName, Namespace: providerNamespace}, provider); err != nil {
144-
return nil, err
145-
}
146-
147-
return provider, nil
148-
case "InfrastructureProvider":
149-
provider := &operatorv1.InfrastructureProvider{}
150-
if err := r.Client.Get(ctx, types.NamespacedName{Name: providerName, Namespace: providerNamespace}, provider); err != nil {
151-
return nil, err
152-
}
153-
154-
return provider, nil
155-
case "AddonProvider":
156-
provider := &operatorv1.AddonProvider{}
157-
if err := r.Client.Get(ctx, types.NamespacedName{Name: providerName, Namespace: providerNamespace}, provider); err != nil {
158-
return nil, err
180+
func (r *GenericProviderHealthCheckReconciler) getProviderName(deploy client.Object) string {
181+
for _, owner := range deploy.GetOwnerReferences() {
182+
if owner.Kind == r.providerGVK.Kind {
183+
return owner.Name
159184
}
185+
}
160186

161-
return provider, nil
162-
case "IPAMProvider":
163-
provider := &operatorv1.IPAMProvider{}
164-
if err := r.Client.Get(ctx, types.NamespacedName{Name: providerName, Namespace: providerNamespace}, provider); err != nil {
165-
return nil, err
166-
}
187+
return ""
188+
}
167189

168-
return provider, nil
169-
default:
170-
return nil, fmt.Errorf("failed to cast interface for type: %s", providerKind)
190+
func (r *GenericProviderHealthCheckReconciler) getProviderKey(deploy client.Object) types.NamespacedName {
191+
return types.NamespacedName{
192+
Namespace: deploy.GetNamespace(),
193+
Name: r.getProviderName(deploy),
171194
}
172195
}
173196

@@ -183,16 +206,14 @@ func getDeploymentCondition(status appsv1.DeploymentStatus, condType appsv1.Depl
183206
return nil
184207
}
185208

186-
func providerDeploymentPredicates() predicate.Funcs {
209+
func (r *GenericProviderHealthCheckReconciler) providerDeploymentPredicates() predicate.Funcs {
187210
isProviderDeployment := func(obj runtime.Object) bool {
188-
clusterOperator, ok := obj.(*appsv1.Deployment)
211+
deployment, ok := obj.(*appsv1.Deployment)
189212
if !ok {
190213
panic("expected to get an of object of type appsv1.Deployment")
191214
}
192215

193-
_, found := clusterOperator.GetLabels()[providerLabelKey]
194-
195-
return found
216+
return r.getProviderName(deployment) != ""
196217
}
197218

198219
return predicate.Funcs{

0 commit comments

Comments
 (0)