Skip to content

Commit 98207e1

Browse files
authored
Merge pull request #565 from tjamet/handle-config-secret-updates
✨ Handle config secret updates
2 parents b8c54a1 + 5762281 commit 98207e1

File tree

11 files changed

+618
-85
lines changed

11 files changed

+618
-85
lines changed

cmd/main.go

Lines changed: 41 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ var (
6767
webhookPort int
6868
webhookCertDir string
6969
healthAddr string
70+
watchConfigSecretChanges bool
7071
diagnosticsOptions = flags.DiagnosticsOptions{}
7172
)
7273

@@ -98,6 +99,9 @@ func InitFlags(fs *pflag.FlagSet) {
9899
fs.StringVar(&watchFilterValue, "watch-filter", "",
99100
fmt.Sprintf("Label value that the controller watches to reconcile cluster-api objects. Label key is always %s. If unspecified, the controller watches for all cluster-api objects.", clusterv1.WatchLabel))
100101

102+
fs.BoolVar(&watchConfigSecretChanges, "watch-configsecret", false,
103+
"Watch for changes to the ConfigSecret resource and reconcile all providers using it.")
104+
101105
fs.StringVar(&watchNamespace, "namespace", "",
102106
"Namespace that the controller watches to reconcile cluster-api objects. If unspecified, the controller watches for cluster-api objects across all namespaces.")
103107

@@ -185,7 +189,7 @@ func main() {
185189
ctx := ctrl.SetupSignalHandler()
186190

187191
setupChecks(mgr)
188-
setupReconcilers(mgr)
192+
setupReconcilers(mgr, watchConfigSecretChanges)
189193
setupWebhooks(mgr)
190194

191195
// +kubebuilder:scaffold:builder
@@ -209,72 +213,79 @@ func setupChecks(mgr ctrl.Manager) {
209213
}
210214
}
211215

212-
func setupReconcilers(mgr ctrl.Manager) {
216+
func setupReconcilers(mgr ctrl.Manager, watchConfigSecretChanges bool) {
213217
if err := (&providercontroller.GenericProviderReconciler{
214-
Provider: &operatorv1.CoreProvider{},
215-
ProviderList: &operatorv1.CoreProviderList{},
216-
Client: mgr.GetClient(),
217-
Config: mgr.GetConfig(),
218+
Provider: &operatorv1.CoreProvider{},
219+
ProviderList: &operatorv1.CoreProviderList{},
220+
Client: mgr.GetClient(),
221+
Config: mgr.GetConfig(),
222+
WatchConfigSecretChanges: watchConfigSecretChanges,
218223
}).SetupWithManager(mgr, concurrency(concurrencyNumber)); err != nil {
219224
setupLog.Error(err, "unable to create controller", "controller", "CoreProvider")
220225
os.Exit(1)
221226
}
222227

223228
if err := (&providercontroller.GenericProviderReconciler{
224-
Provider: &operatorv1.InfrastructureProvider{},
225-
ProviderList: &operatorv1.InfrastructureProviderList{},
226-
Client: mgr.GetClient(),
227-
Config: mgr.GetConfig(),
229+
Provider: &operatorv1.InfrastructureProvider{},
230+
ProviderList: &operatorv1.InfrastructureProviderList{},
231+
Client: mgr.GetClient(),
232+
Config: mgr.GetConfig(),
233+
WatchConfigSecretChanges: watchConfigSecretChanges,
228234
}).SetupWithManager(mgr, concurrency(concurrencyNumber)); err != nil {
229235
setupLog.Error(err, "unable to create controller", "controller", "InfrastructureProvider")
230236
os.Exit(1)
231237
}
232238

233239
if err := (&providercontroller.GenericProviderReconciler{
234-
Provider: &operatorv1.BootstrapProvider{},
235-
ProviderList: &operatorv1.BootstrapProviderList{},
236-
Client: mgr.GetClient(),
237-
Config: mgr.GetConfig(),
240+
Provider: &operatorv1.BootstrapProvider{},
241+
ProviderList: &operatorv1.BootstrapProviderList{},
242+
Client: mgr.GetClient(),
243+
Config: mgr.GetConfig(),
244+
WatchConfigSecretChanges: watchConfigSecretChanges,
238245
}).SetupWithManager(mgr, concurrency(concurrencyNumber)); err != nil {
239246
setupLog.Error(err, "unable to create controller", "controller", "BootstrapProvider")
240247
os.Exit(1)
241248
}
242249

243250
if err := (&providercontroller.GenericProviderReconciler{
244-
Provider: &operatorv1.ControlPlaneProvider{},
245-
ProviderList: &operatorv1.ControlPlaneProviderList{},
246-
Client: mgr.GetClient(),
247-
Config: mgr.GetConfig(),
251+
Provider: &operatorv1.ControlPlaneProvider{},
252+
ProviderList: &operatorv1.ControlPlaneProviderList{},
253+
Client: mgr.GetClient(),
254+
Config: mgr.GetConfig(),
255+
WatchConfigSecretChanges: watchConfigSecretChanges,
248256
}).SetupWithManager(mgr, concurrency(concurrencyNumber)); err != nil {
249257
setupLog.Error(err, "unable to create controller", "controller", "ControlPlaneProvider")
250258
os.Exit(1)
251259
}
252260

253261
if err := (&providercontroller.GenericProviderReconciler{
254-
Provider: &operatorv1.AddonProvider{},
255-
ProviderList: &operatorv1.AddonProviderList{},
256-
Client: mgr.GetClient(),
257-
Config: mgr.GetConfig(),
262+
Provider: &operatorv1.AddonProvider{},
263+
ProviderList: &operatorv1.AddonProviderList{},
264+
Client: mgr.GetClient(),
265+
Config: mgr.GetConfig(),
266+
WatchConfigSecretChanges: watchConfigSecretChanges,
258267
}).SetupWithManager(mgr, concurrency(concurrencyNumber)); err != nil {
259268
setupLog.Error(err, "unable to create controller", "controller", "AddonProvider")
260269
os.Exit(1)
261270
}
262271

263272
if err := (&providercontroller.GenericProviderReconciler{
264-
Provider: &operatorv1.IPAMProvider{},
265-
ProviderList: &operatorv1.IPAMProviderList{},
266-
Client: mgr.GetClient(),
267-
Config: mgr.GetConfig(),
273+
Provider: &operatorv1.IPAMProvider{},
274+
ProviderList: &operatorv1.IPAMProviderList{},
275+
Client: mgr.GetClient(),
276+
Config: mgr.GetConfig(),
277+
WatchConfigSecretChanges: watchConfigSecretChanges,
268278
}).SetupWithManager(mgr, concurrency(concurrencyNumber)); err != nil {
269279
setupLog.Error(err, "unable to create controller", "controller", "IPAMProvider")
270280
os.Exit(1)
271281
}
272282

273283
if err := (&providercontroller.GenericProviderReconciler{
274-
Provider: &operatorv1.RuntimeExtensionProvider{},
275-
ProviderList: &operatorv1.RuntimeExtensionProviderList{},
276-
Client: mgr.GetClient(),
277-
Config: mgr.GetConfig(),
284+
Provider: &operatorv1.RuntimeExtensionProvider{},
285+
ProviderList: &operatorv1.RuntimeExtensionProviderList{},
286+
Client: mgr.GetClient(),
287+
Config: mgr.GetConfig(),
288+
WatchConfigSecretChanges: watchConfigSecretChanges,
278289
}).SetupWithManager(mgr, concurrency(concurrencyNumber)); err != nil {
279290
setupLog.Error(err, "unable to create controller", "controller", "RuntimeExtensionProvider")
280291
os.Exit(1)

hack/charts/cluster-api-operator/templates/deployment.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@ spec:
7474
{{- if .Values.insecureDiagnostics }}
7575
- --insecure-diagnostics={{ .Values.insecureDiagnostics }}
7676
{{- end }}
77+
{{- if .Values.watchConfigSecret }}
78+
- --watch-configsecret
79+
{{- end }}
7780
{{- with .Values.leaderElection }}
7881
- --leader-elect={{ .enabled }}
7982
{{- if .leaseDuration }}

hack/charts/cluster-api-operator/values.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ healthAddr: ":8081"
2727
metricsBindAddr: "127.0.0.1:8080"
2828
diagnosticsAddress: "8443"
2929
insecureDiagnostics: false
30+
watchConfigSecret: false
3031
imagePullSecrets: {}
3132
resources:
3233
manager:

internal/controller/genericprovider_controller.go

Lines changed: 66 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,11 @@ import (
2222
"encoding/json"
2323
"errors"
2424
"fmt"
25+
"hash"
2526

27+
corev1 "k8s.io/api/core/v1"
2628
apierrors "k8s.io/apimachinery/pkg/api/errors"
29+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2730
kerrors "k8s.io/apimachinery/pkg/util/errors"
2831
"k8s.io/client-go/rest"
2932
operatorv1 "sigs.k8s.io/cluster-api-operator/api/v1alpha2"
@@ -35,24 +38,33 @@ import (
3538
"sigs.k8s.io/controller-runtime/pkg/client"
3639
"sigs.k8s.io/controller-runtime/pkg/controller"
3740
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
41+
"sigs.k8s.io/controller-runtime/pkg/handler"
3842
"sigs.k8s.io/controller-runtime/pkg/reconcile"
3943
)
4044

4145
type GenericProviderReconciler struct {
42-
Provider genericprovider.GenericProvider
43-
ProviderList genericprovider.GenericProviderList
44-
Client client.Client
45-
Config *rest.Config
46+
Provider genericprovider.GenericProvider
47+
ProviderList genericprovider.GenericProviderList
48+
Client client.Client
49+
Config *rest.Config
50+
WatchConfigSecretChanges bool
4651
}
4752

4853
const (
4954
appliedSpecHashAnnotation = "operator.cluster.x-k8s.io/applied-spec-hash"
5055
)
5156

5257
func (r *GenericProviderReconciler) SetupWithManager(mgr ctrl.Manager, options controller.Options) error {
53-
return ctrl.NewControllerManagedBy(mgr).
54-
For(r.Provider).
55-
WithOptions(options).
58+
builder := ctrl.NewControllerManagedBy(mgr).
59+
For(r.Provider)
60+
if r.WatchConfigSecretChanges {
61+
builder.Watches(
62+
&corev1.Secret{},
63+
handler.EnqueueRequestsFromMapFunc(newSecretToProviderFuncMapForProviderList(r.Client, r.ProviderList)),
64+
)
65+
}
66+
67+
return builder.WithOptions(options).
5668
Complete(r)
5769
}
5870

@@ -102,14 +114,13 @@ func (r *GenericProviderReconciler) Reconcile(ctx context.Context, req reconcile
102114
}
103115

104116
// Check if spec hash stays the same and don't go further in this case.
105-
specHash, err := calculateHash(r.Provider.GetSpec())
117+
specHash, err := calculateHash(ctx, r.Client, r.Provider)
106118
if err != nil {
107119
return ctrl.Result{}, err
108120
}
109121

110122
if r.Provider.GetAnnotations()[appliedSpecHashAnnotation] == specHash {
111123
log.Info("No changes detected, skipping further steps")
112-
113124
return ctrl.Result{}, nil
114125
}
115126

@@ -123,7 +134,7 @@ func (r *GenericProviderReconciler) Reconcile(ctx context.Context, req reconcile
123134
// Set the spec hash annotation if reconciliation was successful or reset it otherwise.
124135
if res.IsZero() && err == nil {
125136
// Recalculate spec hash in case it was changed during reconciliation process.
126-
specHash, err = calculateHash(r.Provider.GetSpec())
137+
specHash, err := calculateHash(ctx, r.Client, r.Provider)
127138
if err != nil {
128139
return ctrl.Result{}, err
129140
}
@@ -218,16 +229,57 @@ func (r *GenericProviderReconciler) reconcileDelete(ctx context.Context, provide
218229
return res, nil
219230
}
220231

221-
func calculateHash(object interface{}) (string, error) {
232+
func addConfigSecretToHash(ctx context.Context, k8sClient client.Client, hash hash.Hash, provider genericprovider.GenericProvider) error {
233+
if provider.GetSpec().ConfigSecret != nil {
234+
secret := &corev1.Secret{
235+
ObjectMeta: metav1.ObjectMeta{
236+
Namespace: provider.GetSpec().ConfigSecret.Namespace,
237+
Name: provider.GetSpec().ConfigSecret.Name,
238+
},
239+
}
240+
if secret.Namespace == "" {
241+
secret.Namespace = provider.GetNamespace()
242+
}
243+
244+
err := k8sClient.Get(ctx, client.ObjectKeyFromObject(secret), secret)
245+
if err != nil {
246+
return err
247+
}
248+
249+
err = addObjectToHash(hash, secret.Data)
250+
if err != nil {
251+
return err
252+
}
253+
254+
return nil
255+
}
256+
257+
return nil
258+
}
259+
260+
func addObjectToHash(hash hash.Hash, object interface{}) error {
222261
jsonData, err := json.Marshal(object)
223262
if err != nil {
224-
return "", fmt.Errorf("cannot parse provider spec: %w", err)
263+
return fmt.Errorf("cannot marshal object: %w", err)
264+
}
265+
266+
if _, err = hash.Write(jsonData); err != nil {
267+
return fmt.Errorf("cannot calculate object hash: %w", err)
225268
}
226269

270+
return nil
271+
}
272+
273+
func calculateHash(ctx context.Context, k8sClient client.Client, provider genericprovider.GenericProvider) (string, error) {
227274
hash := sha256.New()
228275

229-
if _, err = hash.Write(jsonData); err != nil {
230-
return "", fmt.Errorf("cannot calculate provider spec hash: %w", err)
276+
err := addObjectToHash(hash, provider.GetSpec())
277+
if err != nil {
278+
return "", err
279+
}
280+
281+
if err := addConfigSecretToHash(ctx, k8sClient, hash, provider); err != nil {
282+
return "", err
231283
}
232284

233285
return fmt.Sprintf("%x", hash.Sum(nil)), nil

0 commit comments

Comments
 (0)