github.com/cilium/cilium@v1.16.2/operator/pkg/secretsync/secretsync_reconcile.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package secretsync
     5  
     6  import (
     7  	"context"
     8  
     9  	"github.com/sirupsen/logrus"
    10  	corev1 "k8s.io/api/core/v1"
    11  	k8serrors "k8s.io/apimachinery/pkg/api/errors"
    12  	"k8s.io/apimachinery/pkg/types"
    13  	ctrl "sigs.k8s.io/controller-runtime"
    14  	"sigs.k8s.io/controller-runtime/pkg/client"
    15  	"sigs.k8s.io/controller-runtime/pkg/reconcile"
    16  
    17  	controllerruntime "github.com/cilium/cilium/operator/pkg/controller-runtime"
    18  	"github.com/cilium/cilium/pkg/logging/logfields"
    19  )
    20  
    21  // Reconcile is part of the main kubernetes reconciliation loop which aims to
    22  // move the current state of the cluster closer to the desired state.
    23  //
    24  // For more details, check Reconcile and its Result here:
    25  // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.12.2/pkg/reconcile
    26  func (r *secretSyncer) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
    27  	scopedLog := r.logger.WithFields(logrus.Fields{
    28  		logfields.Controller: "secret-syncer",
    29  		logfields.Resource:   req.NamespacedName,
    30  	})
    31  	scopedLog.Info("Reconciling secret")
    32  
    33  	original := &corev1.Secret{}
    34  	if err := r.client.Get(ctx, req.NamespacedName, original); err != nil {
    35  		if k8serrors.IsNotFound(err) {
    36  			scopedLog.WithError(err).Debug("Unable to get Secret - either deleted or not yet available")
    37  
    38  			synced := false
    39  			// Check whether synced secret needs to be deleted from the registered secret namespaces.
    40  			for _, ns := range r.secretNamespaces {
    41  				// Check if there's an existing synced secret for the deleted Secret
    42  				deleted, err := r.cleanupSyncedSecret(ctx, req, scopedLog, ns)
    43  				if err != nil {
    44  					return controllerruntime.Fail(err)
    45  				}
    46  
    47  				synced = synced || deleted
    48  			}
    49  
    50  			scopedLog.WithField(logfields.Action, action(synced)).Info("Successfully reconciled Secret")
    51  			return controllerruntime.Success()
    52  		}
    53  
    54  		return controllerruntime.Fail(err)
    55  	}
    56  
    57  	cleanupNamespaces := map[string]struct{}{}
    58  	for _, ns := range r.secretNamespaces {
    59  		cleanupNamespaces[ns] = struct{}{}
    60  	}
    61  
    62  	synced := false
    63  	for _, reg := range r.registrations {
    64  		if reg.RefObjectCheckFunc(ctx, r.client, r.logger, original) || reg.IsDefaultSecret(original) {
    65  			desiredSync := desiredSyncSecret(reg.SecretsNamespace, original)
    66  
    67  			scopedLog.WithField("secretNamespace", reg.SecretsNamespace).Debug("Syncing secret")
    68  			if err := r.ensureSyncedSecret(ctx, desiredSync); err != nil {
    69  				return controllerruntime.Fail(err)
    70  			}
    71  
    72  			synced = true
    73  			delete(cleanupNamespaces, reg.SecretsNamespace)
    74  		}
    75  	}
    76  
    77  	// Check whether synced secret needs to be deleted from the secret namespaces
    78  	// where the secret is no longer referenced by any registration.
    79  	for ns := range cleanupNamespaces {
    80  		// Check if there's an existing synced secret that should be deleted
    81  		deleted, err := r.cleanupSyncedSecret(ctx, req, scopedLog, ns)
    82  		if err != nil {
    83  			return controllerruntime.Fail(err)
    84  		}
    85  		synced = synced || deleted
    86  	}
    87  
    88  	scopedLog.WithField(logfields.Action, action(synced)).Info("Successfully reconciled Secret")
    89  	return controllerruntime.Success()
    90  }
    91  
    92  func action(synced bool) string {
    93  	action := "ignored"
    94  	if synced {
    95  		action = "synced"
    96  	}
    97  
    98  	return action
    99  }
   100  
   101  func (r *secretSyncer) cleanupSyncedSecret(ctx context.Context, req reconcile.Request, scopedLog *logrus.Entry, ns string) (bool, error) {
   102  	syncSecret := &corev1.Secret{}
   103  	if err := r.client.Get(ctx, types.NamespacedName{Namespace: ns, Name: req.Namespace + "-" + req.Name}, syncSecret); err == nil {
   104  		// Try to delete existing synced secret
   105  		scopedLog.WithField("secretNamespace", ns).Debug("Delete synced secret")
   106  		if err := r.client.Delete(ctx, syncSecret); err != nil {
   107  			return true, err
   108  		}
   109  
   110  		return true, nil
   111  	}
   112  
   113  	return false, nil
   114  }
   115  
   116  func desiredSyncSecret(secretsNamespace string, original *corev1.Secret) *corev1.Secret {
   117  	s := &corev1.Secret{}
   118  	s.SetNamespace(secretsNamespace)
   119  	s.SetName(original.Namespace + "-" + original.Name)
   120  	s.SetAnnotations(original.GetAnnotations())
   121  	s.SetLabels(original.GetLabels())
   122  	if s.Labels == nil {
   123  		s.Labels = map[string]string{}
   124  	}
   125  	s.Labels[OwningSecretNamespace] = original.Namespace
   126  	s.Labels[OwningSecretName] = original.Name
   127  	s.Immutable = original.Immutable
   128  	s.Data = original.Data
   129  	s.StringData = original.StringData
   130  	s.Type = original.Type
   131  
   132  	return s
   133  }
   134  
   135  func (r *secretSyncer) ensureSyncedSecret(ctx context.Context, desired *corev1.Secret) error {
   136  	existing := &corev1.Secret{}
   137  	if err := r.client.Get(ctx, client.ObjectKeyFromObject(desired), existing); err != nil {
   138  		if k8serrors.IsNotFound(err) {
   139  			return r.client.Create(ctx, desired)
   140  		}
   141  		return err
   142  	}
   143  
   144  	temp := existing.DeepCopy()
   145  	temp.SetAnnotations(desired.GetAnnotations())
   146  	temp.SetLabels(desired.GetLabels())
   147  	temp.Immutable = desired.Immutable
   148  	temp.Data = desired.Data
   149  	temp.StringData = desired.StringData
   150  	temp.Type = desired.Type
   151  
   152  	return r.client.Patch(ctx, temp, client.MergeFrom(existing))
   153  }