github.com/argoproj/argo-cd/v3@v3.2.1/util/db/secrets.go (about) 1 package db 2 3 import ( 4 "context" 5 "fmt" 6 "hash/fnv" 7 "net/netip" 8 "net/url" 9 "strconv" 10 "strings" 11 "time" 12 13 log "github.com/sirupsen/logrus" 14 corev1 "k8s.io/api/core/v1" 15 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 16 "k8s.io/apimachinery/pkg/fields" 17 "k8s.io/apimachinery/pkg/labels" 18 "k8s.io/apimachinery/pkg/selection" 19 informersv1 "k8s.io/client-go/informers/core/v1" 20 "k8s.io/client-go/tools/cache" 21 22 "github.com/argoproj/argo-cd/v3/common" 23 "github.com/argoproj/argo-cd/v3/util" 24 ) 25 26 func (db *db) listSecretsByType(types ...string) ([]*corev1.Secret, error) { 27 labelSelector := labels.NewSelector() 28 req, err := labels.NewRequirement(common.LabelKeySecretType, selection.Equals, types) 29 if err != nil { 30 return nil, err 31 } 32 labelSelector = labelSelector.Add(*req) 33 34 secretsLister, err := db.settingsMgr.GetSecretsLister() 35 if err != nil { 36 return nil, err 37 } 38 secrets, err := secretsLister.Secrets(db.ns).List(labelSelector) 39 if err != nil { 40 return nil, err 41 } 42 // SecretNamespaceLister lists all Secrets in the indexer for a given namespace. 43 // Objects returned by the lister must be treated as read-only. 44 // To allow us to modify the secrets, make a copy 45 secrets = util.SliceCopy(secrets) 46 return secrets, nil 47 } 48 49 func boolOrFalse(secret *corev1.Secret, key string) (bool, error) { 50 val, present := secret.Data[key] 51 if !present { 52 return false, nil 53 } 54 55 return strconv.ParseBool(string(val)) 56 } 57 58 func intOrZero(secret *corev1.Secret, key string) (int64, error) { 59 val, present := secret.Data[key] 60 if !present { 61 return 0, nil 62 } 63 64 return strconv.ParseInt(string(val), 10, 64) 65 } 66 67 func updateSecretBool(secret *corev1.Secret, key string, value bool) { 68 if _, present := secret.Data[key]; present || value { 69 secret.Data[key] = []byte(strconv.FormatBool(value)) 70 } 71 } 72 73 func updateSecretInt(secret *corev1.Secret, key string, value int64) { 74 if _, present := secret.Data[key]; present || value != 0 { 75 secret.Data[key] = []byte(strconv.FormatInt(value, 10)) 76 } 77 } 78 79 func updateSecretString(secret *corev1.Secret, key, value string) { 80 if _, present := secret.Data[key]; present || value != "" { 81 secret.Data[key] = []byte(value) 82 } 83 } 84 85 func (db *db) createSecret(ctx context.Context, secret *corev1.Secret) (*corev1.Secret, error) { 86 return db.kubeclientset.CoreV1().Secrets(db.ns).Create(ctx, secret, metav1.CreateOptions{}) 87 } 88 89 func addSecretMetadata(secret *corev1.Secret, secretType string) { 90 if secret.Annotations == nil { 91 secret.Annotations = map[string]string{} 92 } 93 secret.Annotations[common.AnnotationKeyManagedBy] = common.AnnotationValueManagedByArgoCD 94 95 if secret.Labels == nil { 96 secret.Labels = map[string]string{} 97 } 98 secret.Labels[common.LabelKeySecretType] = secretType 99 } 100 101 func (db *db) deleteSecret(ctx context.Context, secret *corev1.Secret) error { 102 var err error 103 104 canDelete := secret.Annotations != nil && secret.Annotations[common.AnnotationKeyManagedBy] == common.AnnotationValueManagedByArgoCD 105 if canDelete { 106 err = db.kubeclientset.CoreV1().Secrets(db.ns).Delete(ctx, secret.Name, metav1.DeleteOptions{}) 107 } else { 108 delete(secret.Labels, common.LabelKeySecretType) 109 _, err = db.kubeclientset.CoreV1().Secrets(db.ns).Update(ctx, secret, metav1.UpdateOptions{}) 110 } 111 112 return err 113 } 114 115 func (db *db) watchSecrets(ctx context.Context, 116 secretType string, 117 handleAddEvent func(secret *corev1.Secret), 118 handleModEvent func(oldSecret *corev1.Secret, newSecret *corev1.Secret), 119 handleDeleteEvent func(secret *corev1.Secret), 120 ) { 121 secretListOptions := func(options *metav1.ListOptions) { 122 labelSelector := fields.ParseSelectorOrDie(common.LabelKeySecretType + "=" + secretType) 123 options.LabelSelector = labelSelector.String() 124 } 125 secretEventHandler := cache.ResourceEventHandlerFuncs{ 126 AddFunc: func(obj any) { 127 if secretObj, ok := obj.(*corev1.Secret); ok { 128 handleAddEvent(secretObj) 129 } 130 }, 131 DeleteFunc: func(obj any) { 132 if secretObj, ok := obj.(*corev1.Secret); ok { 133 handleDeleteEvent(secretObj) 134 } 135 }, 136 UpdateFunc: func(oldObj, newObj any) { 137 if oldSecretObj, ok := oldObj.(*corev1.Secret); ok { 138 if newSecretObj, ok := newObj.(*corev1.Secret); ok { 139 handleModEvent(oldSecretObj, newSecretObj) 140 } 141 } 142 }, 143 } 144 145 indexers := cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc} 146 clusterSecretInformer := informersv1.NewFilteredSecretInformer(db.kubeclientset, db.ns, 3*time.Minute, indexers, secretListOptions) 147 _, err := clusterSecretInformer.AddEventHandler(secretEventHandler) 148 if err != nil { 149 log.Error(err) 150 } 151 152 log.Info("Starting secretInformer for", secretType) 153 go func() { 154 clusterSecretInformer.Run(ctx.Done()) 155 log.Info("secretInformer for", secretType, "cancelled") 156 }() 157 <-ctx.Done() 158 } 159 160 // URIToSecretName hashes an uri address to the secret name using a formula. 161 // Part of the uri address is incorporated for debugging purposes 162 func URIToSecretName(uriType, uri string) (string, error) { 163 parsedURI, err := url.ParseRequestURI(uri) 164 if err != nil { 165 return "", err 166 } 167 host := parsedURI.Host 168 if strings.HasPrefix(host, "[") { 169 last := strings.Index(host, "]") 170 if last >= 0 { 171 addr, err := netip.ParseAddr(host[1:last]) 172 if err != nil { 173 return "", err 174 } 175 host = strings.ReplaceAll(addr.String(), ":", "-") 176 } 177 } else { 178 last := strings.Index(host, ":") 179 if last >= 0 { 180 host = host[0:last] 181 } 182 } 183 h := fnv.New32a() 184 _, _ = h.Write([]byte(uri)) 185 host = strings.ToLower(host) 186 return fmt.Sprintf("%s-%s-%v", uriType, host, h.Sum32()), nil 187 }