github.com/argoproj-labs/argocd-operator@v0.10.0/controllers/argocd/custommapper.go (about) 1 package argocd 2 3 import ( 4 "context" 5 "fmt" 6 "strings" 7 8 "github.com/argoproj/argo-cd/v2/util/glob" 9 10 argoproj "github.com/argoproj-labs/argocd-operator/api/v1beta1" 11 "github.com/argoproj-labs/argocd-operator/common" 12 13 corev1 "k8s.io/api/core/v1" 14 v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 15 "sigs.k8s.io/controller-runtime/pkg/client" 16 "sigs.k8s.io/controller-runtime/pkg/reconcile" 17 ) 18 19 func (r *ReconcileArgoCD) clusterResourceMapper(ctx context.Context, o client.Object) []reconcile.Request { 20 crbAnnotations := o.GetAnnotations() 21 namespacedArgoCDObject := client.ObjectKey{} 22 23 for k, v := range crbAnnotations { 24 if k == common.AnnotationName { 25 namespacedArgoCDObject.Name = v 26 } else if k == common.AnnotationNamespace { 27 namespacedArgoCDObject.Namespace = v 28 } 29 } 30 31 var result = []reconcile.Request{} 32 if namespacedArgoCDObject.Name != "" && namespacedArgoCDObject.Namespace != "" { 33 result = []reconcile.Request{ 34 {NamespacedName: namespacedArgoCDObject}, 35 } 36 } 37 return result 38 } 39 40 // isSecretOfInterest returns true if the name of the given secret matches one of the 41 // well-known tls secrets used to secure communication amongst the Argo CD components. 42 func isSecretOfInterest(o client.Object) bool { 43 if strings.HasSuffix(o.GetName(), "-repo-server-tls") { 44 return true 45 } 46 if o.GetName() == common.ArgoCDRedisServerTLSSecretName { 47 return true 48 } 49 return false 50 } 51 52 // isOwnerOfInterest returns true if the given owner is one of the Argo CD services that 53 // may have been made the owner of the tls secret created by the OpenShift service CA, used 54 // to secure communication amongst the Argo CD components. 55 func isOwnerOfInterest(owner v1.OwnerReference) bool { 56 if owner.Kind != "Service" { 57 return false 58 } 59 if strings.HasSuffix(owner.Name, "-repo-server") { 60 return true 61 } 62 if strings.HasSuffix(owner.Name, "-redis") { 63 return true 64 } 65 return false 66 } 67 68 // tlsSecretMapper maps a watch event on a secret of type TLS back to the 69 // ArgoCD object that we want to reconcile. 70 func (r *ReconcileArgoCD) tlsSecretMapper(ctx context.Context, o client.Object) []reconcile.Request { 71 var result = []reconcile.Request{} 72 73 if !isSecretOfInterest(o) { 74 return result 75 } 76 namespacedArgoCDObject := client.ObjectKey{} 77 78 secretOwnerRefs := o.GetOwnerReferences() 79 if len(secretOwnerRefs) > 0 { 80 // OpenShift service CA makes the owner reference for the TLS secret to the 81 // service, which in turn is owned by the controller. This method performs 82 // a lookup of the controller through the intermediate owning service. 83 for _, secretOwner := range secretOwnerRefs { 84 if isOwnerOfInterest(secretOwner) { 85 key := client.ObjectKey{Name: secretOwner.Name, Namespace: o.GetNamespace()} 86 svc := &corev1.Service{} 87 88 // Get the owning object of the secret 89 err := r.Client.Get(context.TODO(), key, svc) 90 if err != nil { 91 log.Error(err, fmt.Sprintf("could not get owner of secret %s", o.GetName())) 92 return result 93 } 94 95 // If there's an object of kind ArgoCD in the owner's list, 96 // this will be our reconciled object. 97 serviceOwnerRefs := svc.GetOwnerReferences() 98 for _, serviceOwner := range serviceOwnerRefs { 99 if serviceOwner.Kind == "ArgoCD" { 100 namespacedArgoCDObject.Name = serviceOwner.Name 101 namespacedArgoCDObject.Namespace = svc.ObjectMeta.Namespace 102 result = []reconcile.Request{ 103 {NamespacedName: namespacedArgoCDObject}, 104 } 105 return result 106 } 107 } 108 } 109 } 110 } else { 111 // For secrets without owner (i.e. manually created), we apply some 112 // heuristics. This may not be as accurate (e.g. if the user made a 113 // typo in the resource's name), but should be good enough for now. 114 secret, ok := o.(*corev1.Secret) 115 if !ok { 116 return result 117 } 118 if owner, ok := secret.Annotations[common.AnnotationName]; ok { 119 namespacedArgoCDObject.Name = owner 120 namespacedArgoCDObject.Namespace = o.GetNamespace() 121 result = []reconcile.Request{ 122 {NamespacedName: namespacedArgoCDObject}, 123 } 124 } 125 } 126 127 return result 128 } 129 130 // namespaceResourceMapper maps a watch event on a namespace, back to the 131 // ArgoCD object that we want to reconcile. 132 func (r *ReconcileArgoCD) namespaceResourceMapper(ctx context.Context, o client.Object) []reconcile.Request { 133 var result = []reconcile.Request{} 134 135 argocds := &argoproj.ArgoCDList{} 136 labels := o.GetLabels() 137 namespaceName := o.GetName() 138 if v, ok := labels[common.ArgoCDManagedByLabel]; ok { 139 if err := r.Client.List(context.TODO(), argocds, &client.ListOptions{Namespace: v}); err != nil { 140 return result 141 } 142 if len(argocds.Items) != 1 { 143 return result 144 } 145 argocd := argocds.Items[0] 146 namespacedName := client.ObjectKey{ 147 Name: argocd.Name, 148 Namespace: argocd.Namespace, 149 } 150 result = []reconcile.Request{ 151 {NamespacedName: namespacedName}, 152 } 153 } else { 154 // If the namespace does not have the expected managed-by label, 155 // iterate through each ArgoCD instance to identify if the observed namespace 156 // matches any configured sourceNamespace pattern. If a match is found, 157 // generate a reconcile request for the instances. 158 if err := r.Client.List(ctx, argocds, &client.ListOptions{}); err != nil { 159 return result 160 } 161 for _, argocd := range argocds.Items { 162 if glob.MatchStringInList(argocd.Spec.SourceNamespaces, namespaceName, false) { 163 namespacedName := client.ObjectKey{ 164 Name: argocd.Name, 165 Namespace: argocd.Namespace, 166 } 167 result = append(result, reconcile.Request{NamespacedName: namespacedName}) 168 } 169 } 170 } 171 172 return result 173 } 174 175 // clusterSecretResourceMapper maps a watch event on a namespace, back to the 176 // ArgoCD object that we want to reconcile. 177 func (r *ReconcileArgoCD) clusterSecretResourceMapper(ctx context.Context, o client.Object) []reconcile.Request { 178 var result = []reconcile.Request{} 179 180 labels := o.GetLabels() 181 if v, ok := labels[common.ArgoCDSecretTypeLabel]; ok && v == "cluster" { 182 argocds := &argoproj.ArgoCDList{} 183 if err := r.Client.List(context.TODO(), argocds, &client.ListOptions{Namespace: o.GetNamespace()}); err != nil { 184 return result 185 } 186 187 if len(argocds.Items) != 1 { 188 return result 189 } 190 191 argocd := argocds.Items[0] 192 namespacedName := client.ObjectKey{ 193 Name: argocd.Name, 194 Namespace: argocd.Namespace, 195 } 196 result = []reconcile.Request{ 197 {NamespacedName: namespacedName}, 198 } 199 } 200 201 return result 202 } 203 204 // applicationSetSCMTLSConfigMapMapper maps a watch event on a configmap with name "argocd-appset-gitlab-scm-tls-certs-cm", 205 // back to the ArgoCD object that we want to reconcile. 206 func (r *ReconcileArgoCD) applicationSetSCMTLSConfigMapMapper(ctx context.Context, o client.Object) []reconcile.Request { 207 var result = []reconcile.Request{} 208 209 if o.GetName() == common.ArgoCDAppSetGitlabSCMTLSCertsConfigMapName { 210 argocds := &argoproj.ArgoCDList{} 211 if err := r.Client.List(context.TODO(), argocds, &client.ListOptions{Namespace: o.GetNamespace()}); err != nil { 212 return result 213 } 214 215 if len(argocds.Items) != 1 { 216 return result 217 } 218 219 argocd := argocds.Items[0] 220 namespacedName := client.ObjectKey{ 221 Name: argocd.Name, 222 Namespace: argocd.Namespace, 223 } 224 result = []reconcile.Request{ 225 {NamespacedName: namespacedName}, 226 } 227 } 228 229 return result 230 }