github.com/argoproj/argo-cd/v2@v2.10.9/applicationset/controllers/clustereventhandler.go (about)

     1  package controllers
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  
     7  	log "github.com/sirupsen/logrus"
     8  
     9  	"k8s.io/apimachinery/pkg/types"
    10  	"k8s.io/client-go/util/workqueue"
    11  	ctrl "sigs.k8s.io/controller-runtime"
    12  	"sigs.k8s.io/controller-runtime/pkg/client"
    13  	"sigs.k8s.io/controller-runtime/pkg/event"
    14  
    15  	"github.com/argoproj/argo-cd/v2/applicationset/generators"
    16  	argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
    17  )
    18  
    19  // clusterSecretEventHandler is used when watching Secrets to check if they are ArgoCD Cluster Secrets, and if so
    20  // requeue any related ApplicationSets.
    21  type clusterSecretEventHandler struct {
    22  	//handler.EnqueueRequestForOwner
    23  	Log    log.FieldLogger
    24  	Client client.Client
    25  }
    26  
    27  func (h *clusterSecretEventHandler) Create(e event.CreateEvent, q workqueue.RateLimitingInterface) {
    28  	h.queueRelatedAppGenerators(q, e.Object)
    29  }
    30  
    31  func (h *clusterSecretEventHandler) Update(e event.UpdateEvent, q workqueue.RateLimitingInterface) {
    32  	h.queueRelatedAppGenerators(q, e.ObjectNew)
    33  }
    34  
    35  func (h *clusterSecretEventHandler) Delete(e event.DeleteEvent, q workqueue.RateLimitingInterface) {
    36  	h.queueRelatedAppGenerators(q, e.Object)
    37  }
    38  
    39  func (h *clusterSecretEventHandler) Generic(e event.GenericEvent, q workqueue.RateLimitingInterface) {
    40  	h.queueRelatedAppGenerators(q, e.Object)
    41  }
    42  
    43  // addRateLimitingInterface defines the Add method of workqueue.RateLimitingInterface, allow us to easily mock
    44  // it for testing purposes.
    45  type addRateLimitingInterface interface {
    46  	Add(item interface{})
    47  }
    48  
    49  func (h *clusterSecretEventHandler) queueRelatedAppGenerators(q addRateLimitingInterface, object client.Object) {
    50  	// Check for label, lookup all ApplicationSets that might match the cluster, queue them all
    51  	if object.GetLabels()[generators.ArgoCDSecretTypeLabel] != generators.ArgoCDSecretTypeCluster {
    52  		return
    53  	}
    54  
    55  	h.Log.WithFields(log.Fields{
    56  		"namespace": object.GetNamespace(),
    57  		"name":      object.GetName(),
    58  	}).Info("processing event for cluster secret")
    59  
    60  	appSetList := &argoprojiov1alpha1.ApplicationSetList{}
    61  	err := h.Client.List(context.Background(), appSetList)
    62  	if err != nil {
    63  		h.Log.WithError(err).Error("unable to list ApplicationSets")
    64  		return
    65  	}
    66  
    67  	h.Log.WithField("count", len(appSetList.Items)).Info("listed ApplicationSets")
    68  	for _, appSet := range appSetList.Items {
    69  
    70  		foundClusterGenerator := false
    71  		for _, generator := range appSet.Spec.Generators {
    72  			if generator.Clusters != nil {
    73  				foundClusterGenerator = true
    74  				break
    75  			}
    76  
    77  			if generator.Matrix != nil {
    78  				ok, err := nestedGeneratorsHaveClusterGenerator(generator.Matrix.Generators)
    79  				if err != nil {
    80  					h.Log.
    81  						WithFields(log.Fields{
    82  							"namespace": appSet.GetNamespace(),
    83  							"name":      appSet.GetName(),
    84  						}).
    85  						WithError(err).
    86  						Error("Unable to check if ApplicationSet matrix generators have cluster generator")
    87  				}
    88  				if ok {
    89  					foundClusterGenerator = true
    90  					break
    91  				}
    92  			}
    93  
    94  			if generator.Merge != nil {
    95  				ok, err := nestedGeneratorsHaveClusterGenerator(generator.Merge.Generators)
    96  				if err != nil {
    97  					h.Log.
    98  						WithFields(log.Fields{
    99  							"namespace": appSet.GetNamespace(),
   100  							"name":      appSet.GetName(),
   101  						}).
   102  						WithError(err).
   103  						Error("Unable to check if ApplicationSet merge generators have cluster generator")
   104  				}
   105  				if ok {
   106  					foundClusterGenerator = true
   107  					break
   108  				}
   109  			}
   110  		}
   111  		if foundClusterGenerator {
   112  
   113  			// TODO: only queue the AppGenerator if the labels match this cluster
   114  			req := ctrl.Request{NamespacedName: types.NamespacedName{Namespace: appSet.Namespace, Name: appSet.Name}}
   115  			q.Add(req)
   116  		}
   117  	}
   118  }
   119  
   120  // nestedGeneratorsHaveClusterGenerator iterate over provided nested generators to check if they have a cluster generator.
   121  func nestedGeneratorsHaveClusterGenerator(generators []argoprojiov1alpha1.ApplicationSetNestedGenerator) (bool, error) {
   122  	for _, generator := range generators {
   123  		if ok, err := nestedGeneratorHasClusterGenerator(generator); ok || err != nil {
   124  			return ok, err
   125  		}
   126  	}
   127  	return false, nil
   128  }
   129  
   130  // nestedGeneratorHasClusterGenerator checks if the provided generator has a cluster generator.
   131  func nestedGeneratorHasClusterGenerator(nested argoprojiov1alpha1.ApplicationSetNestedGenerator) (bool, error) {
   132  	if nested.Clusters != nil {
   133  		return true, nil
   134  	}
   135  
   136  	if nested.Matrix != nil {
   137  		nestedMatrix, err := argoprojiov1alpha1.ToNestedMatrixGenerator(nested.Matrix)
   138  		if err != nil {
   139  			return false, fmt.Errorf("unable to get nested matrix generator: %w", err)
   140  		}
   141  		if nestedMatrix != nil {
   142  			hasClusterGenerator, err := nestedGeneratorsHaveClusterGenerator(nestedMatrix.ToMatrixGenerator().Generators)
   143  			if err != nil {
   144  				return false, fmt.Errorf("error evaluating nested matrix generator: %w", err)
   145  			}
   146  			return hasClusterGenerator, nil
   147  		}
   148  	}
   149  
   150  	if nested.Merge != nil {
   151  		nestedMerge, err := argoprojiov1alpha1.ToNestedMergeGenerator(nested.Merge)
   152  		if err != nil {
   153  			return false, fmt.Errorf("unable to get nested merge generator: %w", err)
   154  		}
   155  		if nestedMerge != nil {
   156  			hasClusterGenerator, err := nestedGeneratorsHaveClusterGenerator(nestedMerge.ToMergeGenerator().Generators)
   157  			if err != nil {
   158  				return false, fmt.Errorf("error evaluating nested merge generator: %w", err)
   159  			}
   160  			return hasClusterGenerator, nil
   161  		}
   162  	}
   163  
   164  	return false, nil
   165  }