@@ -23,6 +23,7 @@ import (
23
23
"errors"
24
24
"fmt"
25
25
"hash"
26
+ "strings"
26
27
27
28
corev1 "k8s.io/api/core/v1"
28
29
apierrors "k8s.io/apimachinery/pkg/api/errors"
@@ -39,7 +40,10 @@ import (
39
40
"sigs.k8s.io/controller-runtime/pkg/controller"
40
41
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
41
42
"sigs.k8s.io/controller-runtime/pkg/handler"
43
+ "sigs.k8s.io/controller-runtime/pkg/log"
42
44
"sigs.k8s.io/controller-runtime/pkg/reconcile"
45
+
46
+ utilyaml "sigs.k8s.io/cluster-api/util/yaml"
43
47
)
44
48
45
49
type GenericProviderReconciler struct {
@@ -56,6 +60,7 @@ type GenericProviderReconciler struct {
56
60
57
61
const (
58
62
appliedSpecHashAnnotation = "operator.cluster.x-k8s.io/applied-spec-hash"
63
+ cacheOwner = "capi-operator"
59
64
)
60
65
61
66
func (r * GenericProviderReconciler ) BuildWithManager (ctx context.Context , mgr ctrl.Manager ) (* ctrl.Builder , error ) {
@@ -173,8 +178,15 @@ func (r *GenericProviderReconciler) Reconcile(ctx context.Context, req reconcile
173
178
return ctrl.Result {}, err
174
179
}
175
180
176
- if r .Provider .GetAnnotations ()[appliedSpecHashAnnotation ] == specHash {
181
+ // Check provider config map for changes
182
+ cacheUsed , err := applyFromCache (ctx , r .Client , r .Provider )
183
+ if err != nil {
184
+ return ctrl.Result {}, err
185
+ }
186
+
187
+ if r .Provider .GetAnnotations ()[appliedSpecHashAnnotation ] == specHash || cacheUsed {
177
188
log .Info ("No changes detected, skipping further steps" )
189
+
178
190
return ctrl.Result {}, nil
179
191
}
180
192
@@ -316,17 +328,140 @@ func addObjectToHash(hash hash.Hash, object interface{}) error {
316
328
return nil
317
329
}
318
330
331
+ // providerHash calculates hash for provider and referenced objects.
332
+ func providerHash (ctx context.Context , client client.Client , hash hash.Hash , provider genericprovider.GenericProvider ) error {
333
+ log := log .FromContext (ctx )
334
+
335
+ err := addObjectToHash (hash , provider .GetSpec ())
336
+ if err != nil {
337
+ log .Error (err , "failed to calculate provider hash" )
338
+
339
+ return err
340
+ }
341
+
342
+ if err := addConfigSecretToHash (ctx , client , hash , provider ); err != nil {
343
+ log .Error (err , "failed to calculate secret hash" )
344
+
345
+ return err
346
+ }
347
+
348
+ return nil
349
+ }
350
+
319
351
func calculateHash (ctx context.Context , k8sClient client.Client , provider genericprovider.GenericProvider ) (string , error ) {
320
352
hash := sha256 .New ()
321
353
322
- err := addObjectToHash (hash , provider .GetSpec ())
354
+ err := providerHash (ctx , k8sClient , hash , provider )
355
+
356
+ return fmt .Sprintf ("%x" , hash .Sum (nil )), err
357
+ }
358
+
359
+ // applyFromCache applies provider configuration from cache and returns true if the cache did not change.
360
+ func applyFromCache (ctx context.Context , cl client.Client , provider genericprovider.GenericProvider ) (bool , error ) {
361
+ log := log .FromContext (ctx )
362
+
363
+ configMap , err := providerConfigMap (ctx , cl , provider )
323
364
if err != nil {
324
- return "" , err
365
+ log .Error (err , "failed to get provider config map" )
366
+
367
+ return false , err
368
+ }
369
+
370
+ // config map does not exist, nothing to apply
371
+ if configMap == nil {
372
+ return false , nil
373
+ }
374
+
375
+ // calculate combined hash for provider and config map cache
376
+ hash := sha256 .New ()
377
+ if err := providerHash (ctx , cl , hash , provider ); err != nil {
378
+ log .Error (err , "failed to calculate provider hash" )
379
+
380
+ return false , err
381
+ }
382
+
383
+ if err := addObjectToHash (hash , configMap .Data ); err != nil {
384
+ log .Error (err , "failed to calculate config map hash" )
385
+
386
+ return false , err
325
387
}
326
388
327
- if err := addConfigSecretToHash (ctx , k8sClient , hash , provider ); err != nil {
328
- return "" , err
389
+ cacheHash := fmt .Sprintf ("%x" , hash .Sum (nil ))
390
+ if configMap .GetAnnotations ()[appliedSpecHashAnnotation ] != cacheHash {
391
+ log .Info ("Provider or cache state has changed" , "cacheHash" , cacheHash , "providerHash" , configMap .GetAnnotations ()[appliedSpecHashAnnotation ])
392
+
393
+ return false , nil
394
+ }
395
+
396
+ components , err := getComponentsData (* configMap )
397
+ if err != nil {
398
+ log .Error (err , "failed to get provider components" )
399
+
400
+ return false , err
329
401
}
330
402
331
- return fmt .Sprintf ("%x" , hash .Sum (nil )), nil
403
+ additionalManifests , err := fetchAdditionalManifests (ctx , cl , provider )
404
+ if err != nil {
405
+ log .Error (err , "failed to get additional manifests" )
406
+
407
+ return false , err
408
+ }
409
+
410
+ if additionalManifests != "" {
411
+ components = components + "\n ---\n " + additionalManifests
412
+ }
413
+
414
+ for _ , manifests := range strings .Split (components , "---" ) {
415
+ manifests , err := utilyaml .ToUnstructured ([]byte (manifests ))
416
+ if err != nil {
417
+ log .Error (err , "failed to convert yaml to unstructured" )
418
+
419
+ return false , err
420
+ }
421
+
422
+ if err := cl .Patch (ctx , & manifests [0 ], client .Apply , client .ForceOwnership , client .FieldOwner (cacheOwner )); err != nil {
423
+ log .Error (err , "failed to apply object from cache" )
424
+
425
+ return false , nil
426
+ }
427
+ }
428
+
429
+ log .Info ("Applied all objects from cache" )
430
+
431
+ return true , nil
432
+ }
433
+
434
+ // setCacheHash calculates current provider and configMap hash, and updates it on the configMap.
435
+ func setCacheHash (ctx context.Context , cl client.Client , provider genericprovider.GenericProvider ) error {
436
+ configMap , err := providerConfigMap (ctx , cl , provider )
437
+ if err != nil {
438
+ return err
439
+ }
440
+
441
+ helper , err := patch .NewHelper (configMap , cl )
442
+ if err != nil {
443
+ return err
444
+ }
445
+
446
+ hash := sha256 .New ()
447
+
448
+ if err := providerHash (ctx , cl , hash , provider ); err != nil {
449
+ return err
450
+ }
451
+
452
+ if err := addObjectToHash (hash , configMap .Data ); err != nil {
453
+ return err
454
+ }
455
+
456
+ cacheHash := fmt .Sprintf ("%x" , hash .Sum (nil ))
457
+
458
+ annotations := configMap .GetAnnotations ()
459
+ if annotations == nil {
460
+ annotations = map [string ]string {}
461
+ }
462
+
463
+ annotations [appliedSpecHashAnnotation ] = cacheHash
464
+ configMap .SetAnnotations (annotations )
465
+
466
+ return helper .Patch (ctx , configMap )
332
467
}
0 commit comments