diff --git a/common/TOBEREMOVED.go b/common/TOBEREMOVED.go index 410ac60a9..2b6e3e0e2 100644 --- a/common/TOBEREMOVED.go +++ b/common/TOBEREMOVED.go @@ -161,6 +161,10 @@ const ( // to used for the the Redis container in HA mode. ArgoCDRedisHAImageEnvVar = "ARGOCD_REDIS_HA_IMAGE" + // ArgoCDPolicyMatcherMode is the key for matchers function for casbin. + // There are two options for this, 'glob' for glob matcher or 'regex' for regex matcher. + ArgoCDPolicyMatcherMode = "policy.matchMode" + // ArgoCDDefaultRepoMetricsPort is the default listen port for the Argo CD repo server metrics. ArgoCDDefaultRepoMetricsPort = 8084 diff --git a/controllers/argocd/argocd_controller.go b/controllers/argocd/argocd_controller.go index c2f535e39..e2e2da76a 100644 --- a/controllers/argocd/argocd_controller.go +++ b/controllers/argocd/argocd_controller.go @@ -29,7 +29,6 @@ import ( "github.com/argoproj-labs/argocd-operator/common" "github.com/argoproj-labs/argocd-operator/controllers/argocd/appcontroller" "github.com/argoproj-labs/argocd-operator/controllers/argocd/applicationset" - "github.com/argoproj-labs/argocd-operator/controllers/argocd/configmap" "github.com/argoproj-labs/argocd-operator/controllers/argocd/notifications" "github.com/argoproj-labs/argocd-operator/controllers/argocd/redis" "github.com/argoproj-labs/argocd-operator/controllers/argocd/reposerver" @@ -44,7 +43,7 @@ import ( appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" networkingv1 "k8s.io/api/networking/v1" - v1 "k8s.io/api/rbac/v1" + rbacv1 "k8s.io/api/rbac/v1" "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" @@ -90,7 +89,6 @@ type ArgoCDReconciler struct { LabelSelector string SecretController *secret.SecretReconciler - ConfigMapController *configmap.ConfigMapReconciler RedisController *redis.RedisReconciler ReposerverController *reposerver.RepoServerReconciler ServerController *server.ServerReconciler @@ -381,13 +379,13 @@ func (r *ArgoCDReconciler) setAppManagedNamespaces() error { func (r *ArgoCDReconciler) reconcileControllers() error { // core components, return reconciliation errors - if err := r.SecretController.Reconcile(); err != nil { - r.Logger.Error(err, "failed to reconcile secret controller") + if err := r.reconcileConfigMaps(); err != nil { + r.Logger.Error(err, "failed to reconcile required config maps") return err } - if err := r.ConfigMapController.Reconcile(); err != nil { - r.Logger.Error(err, "failed to reconcile configmap controller") + if err := r.SecretController.Reconcile(); err != nil { + r.Logger.Error(err, "failed to reconcile secret controller") return err } @@ -459,12 +457,6 @@ func (r *ArgoCDReconciler) InitializeControllerReconcilers() { ManagedNamespaces: r.ResourceManagedNamespaces, } - configMapController := &configmap.ConfigMapReconciler{ - Client: &r.Client, - Scheme: r.Scheme, - Instance: r.Instance, - } - redisController := &redis.RedisReconciler{ Client: r.Client, Scheme: r.Scheme, @@ -536,8 +528,6 @@ func (r *ArgoCDReconciler) InitializeControllerReconcilers() { r.SSOController = ssoController - r.ConfigMapController = configMapController - r.SecretController = secretController } @@ -573,9 +563,9 @@ func (r *ArgoCDReconciler) setResourceWatches(bldr *builder.Builder) *builder.Bu // Watch for changes to Ingress sub-resources owned by ArgoCD instances. bldr.Owns(&networkingv1.Ingress{}) - bldr.Owns(&v1.Role{}) + bldr.Owns(&rbacv1.Role{}) - bldr.Owns(&v1.RoleBinding{}) + bldr.Owns(&rbacv1.RoleBinding{}) if openshift.IsRouteAPIAvailable() { // Watch OpenShift Route sub-resources owned by ArgoCD instances. diff --git a/controllers/argocd/argocd_controller_test.go b/controllers/argocd/argocd_controller_test.go index 9ddf9fbbf..435de56fd 100644 --- a/controllers/argocd/argocd_controller_test.go +++ b/controllers/argocd/argocd_controller_test.go @@ -38,14 +38,32 @@ import ( "github.com/argoproj-labs/argocd-operator/common" "github.com/argoproj-labs/argocd-operator/pkg/argoutil" "github.com/argoproj-labs/argocd-operator/pkg/cluster" + "github.com/argoproj-labs/argocd-operator/pkg/util" + "github.com/argoproj-labs/argocd-operator/tests/test" ) var _ reconcile.Reconciler = &ArgoCDReconciler{} -func makeTestArgoCDReconciler(client client.Client, sch *runtime.Scheme) *ArgoCDReconciler { +// func makeTestArgoCDReconciler(client client.Client, sch *runtime.Scheme) *ArgoCDReconciler { +// return &ArgoCDReconciler{ +// Client: client, +// Scheme: sch, +// } +// } + +func makeTestArgoCDReconciler(cr *argoproj.ArgoCD, objs ...client.Object) *ArgoCDReconciler { + schemeOpt := func(s *runtime.Scheme) { + argoproj.AddToScheme(s) + } + sch := test.MakeTestReconcilerScheme(schemeOpt) + + client := test.MakeTestReconcilerClient(sch, objs, []client.Object{cr}, []runtime.Object{cr}) + return &ArgoCDReconciler{ - Client: client, - Scheme: sch, + Client: client, + Scheme: sch, + Instance: cr, + Logger: util.NewLogger("argocd-controller"), } } @@ -396,10 +414,7 @@ func TestReconcileArgoCD_CleanUp(t *testing.T) { func TestSetResourceManagedNamespaces(t *testing.T) { - resources := []client.Object{} - subresObjs := []client.Object{} - - runtimeObjs := []runtime.Object{ + objs := []client.Object{ makeTestNs(func(n *corev1.Namespace) { n.Name = "instance-1" }), @@ -432,10 +447,6 @@ func TestSetResourceManagedNamespaces(t *testing.T) { }), } - sch := makeTestReconcilerScheme(argoproj.AddToScheme) - cl := makeTestReconcilerClient(sch, resources, subresObjs, runtimeObjs) - r := makeTestArgoCDReconciler(cl, sch) - instanceOne := makeTestArgoCD(func(ac *argoproj.ArgoCD) { ac.Namespace = "instance-1" }) @@ -448,7 +459,7 @@ func TestSetResourceManagedNamespaces(t *testing.T) { "test-ns-1": "", "test-ns-4": "", } - r.Instance = instanceOne + r := makeTestArgoCDReconciler(instanceOne, objs...) r.setResourceManagedNamespaces() assert.Equal(t, expectedNsMap, r.ResourceManagedNamespaces) @@ -464,10 +475,7 @@ func TestSetResourceManagedNamespaces(t *testing.T) { func TestSetAppManagedNamespaces(t *testing.T) { - resources := []client.Object{} - subresObjs := []client.Object{} - - runtimeObjs := []runtime.Object{ + objs := []client.Object{ makeTestNs(func(n *corev1.Namespace) { n.Name = "instance-1" }), @@ -497,15 +505,13 @@ func TestSetAppManagedNamespaces(t *testing.T) { }), } - sch := makeTestReconcilerScheme(argoproj.AddToScheme) - cl := makeTestReconcilerClient(sch, resources, subresObjs, runtimeObjs) - r := makeTestArgoCDReconciler(cl, sch) - instance := makeTestArgoCD(func(ac *argoproj.ArgoCD) { ac.Namespace = "instance-1" ac.Spec.SourceNamespaces = []string{"test-ns-1", "test-ns-2", "test-ns-3"} }) + r := makeTestArgoCDReconciler(instance, objs...) + // test with namespace scoped instance r.Instance = instance r.ClusterScoped = false diff --git a/controllers/argocd/argocdcommon/helper.go b/controllers/argocd/argocdcommon/helper.go index 9b857ab2e..5c0a69e64 100644 --- a/controllers/argocd/argocdcommon/helper.go +++ b/controllers/argocd/argocdcommon/helper.go @@ -87,7 +87,12 @@ func GetValueOrDefault(value interface{}, defaultValue interface{}) interface{} if reflect.ValueOf(value).IsNil() { return defaultValue } - return reflect.ValueOf(value).String() + ptVal := reflect.Indirect(reflect.ValueOf(value)) + + switch ptVal.Kind() { + case reflect.String: + return reflect.Indirect(reflect.ValueOf(value)).String() + } } switch v := value.(type) { @@ -95,12 +100,12 @@ func GetValueOrDefault(value interface{}, defaultValue interface{}) interface{} if len(v) > 0 { return v } - return defaultValue + return defaultValue.(string) case map[string]string: if len(v) > 0 { return v } - return defaultValue + return defaultValue.(map[string]string) } return defaultValue diff --git a/controllers/argocd/cm_TOBEREMOVED.go b/controllers/argocd/cm_TOBEREMOVED.go index ab81a56a4..2e5b4a6ce 100644 --- a/controllers/argocd/cm_TOBEREMOVED.go +++ b/controllers/argocd/cm_TOBEREMOVED.go @@ -1 +1,520 @@ package argocd + +import ( + "context" + "fmt" + "reflect" + + argoproj "github.com/argoproj-labs/argocd-operator/api/v1beta1" + "github.com/argoproj-labs/argocd-operator/common" + "github.com/argoproj-labs/argocd-operator/pkg/argoutil" + "gopkg.in/yaml.v2" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" +) + +// getRBACPolicy will return the RBAC policy for the given ArgoCD. +func getRBACPolicy(cr *argoproj.ArgoCD) string { + policy := common.ArgoCDDefaultRBACPolicy + if cr.Spec.RBAC.Policy != nil { + policy = *cr.Spec.RBAC.Policy + } + return policy +} + +// getRBACDefaultPolicy will retun the RBAC default policy for the given ArgoCD. +func getRBACDefaultPolicy(cr *argoproj.ArgoCD) string { + dp := common.ArgoCDDefaultRBACDefaultPolicy + if cr.Spec.RBAC.DefaultPolicy != nil { + dp = *cr.Spec.RBAC.DefaultPolicy + } + return dp +} + +// getRBACScopes will return the RBAC scopes for the given ArgoCD. +func getRBACScopes(cr *argoproj.ArgoCD) string { + scopes := common.ArgoCDDefaultRBACScopes + if cr.Spec.RBAC.Scopes != nil { + scopes = *cr.Spec.RBAC.Scopes + } + return scopes +} + +// createRBACConfigMap will create the Argo CD RBAC ConfigMap resource. +func (r *ReconcileArgoCD) createRBACConfigMap(cm *corev1.ConfigMap, cr *argoproj.ArgoCD) error { + data := make(map[string]string) + data[common.ArgoCDKeyRBACPolicyCSV] = getRBACPolicy(cr) + data[common.ArgoCDKeyRBACPolicyDefault] = getRBACDefaultPolicy(cr) + data[common.ArgoCDKeyRBACScopes] = getRBACScopes(cr) + cm.Data = data + + if err := controllerutil.SetControllerReference(cr, cm, r.Scheme); err != nil { + return err + } + return r.Client.Create(context.TODO(), cm) +} + +// reconcileRBAC will ensure that the ArgoCD RBAC ConfigMap is present. +func (r *ReconcileArgoCD) reconcileRBAC(cr *argoproj.ArgoCD) error { + cm := newConfigMapWithName(common.ArgoCDRBACConfigMapName, cr) + if argoutil.IsObjectFound(r.Client, cr.Namespace, cm.Name, cm) { + return r.reconcileRBACConfigMap(cm, cr) + } + return r.createRBACConfigMap(cm, cr) +} + +// reconcileRBACConfigMap will ensure that the RBAC ConfigMap is syncronized with the given ArgoCD. +func (r *ReconcileArgoCD) reconcileRBACConfigMap(cm *corev1.ConfigMap, cr *argoproj.ArgoCD) error { + changed := false + // Policy CSV + if cr.Spec.RBAC.Policy != nil && cm.Data[common.ArgoCDKeyRBACPolicyCSV] != *cr.Spec.RBAC.Policy { + cm.Data[common.ArgoCDKeyRBACPolicyCSV] = *cr.Spec.RBAC.Policy + changed = true + } + + // Default Policy + if cr.Spec.RBAC.DefaultPolicy != nil && cm.Data[common.ArgoCDKeyRBACPolicyDefault] != *cr.Spec.RBAC.DefaultPolicy { + cm.Data[common.ArgoCDKeyRBACPolicyDefault] = *cr.Spec.RBAC.DefaultPolicy + changed = true + } + + // Default Policy Matcher Mode + if cr.Spec.RBAC.PolicyMatcherMode != nil && cm.Data[common.ArgoCDPolicyMatcherMode] != *cr.Spec.RBAC.PolicyMatcherMode { + cm.Data[common.ArgoCDPolicyMatcherMode] = *cr.Spec.RBAC.PolicyMatcherMode + changed = true + } + + // Scopes + if cr.Spec.RBAC.Scopes != nil && cm.Data[common.ArgoCDKeyRBACScopes] != *cr.Spec.RBAC.Scopes { + cm.Data[common.ArgoCDKeyRBACScopes] = *cr.Spec.RBAC.Scopes + changed = true + } + + if changed { + // TODO: Reload server (and dex?) if RBAC settings change? + return r.Client.Update(context.TODO(), cm) + } + return nil // ConfigMap exists and nothing to do, move along... +} + +// getApplicationInstanceLabelKey will return the application instance label key for the given ArgoCD. +func getApplicationInstanceLabelKey(cr *argoproj.ArgoCD) string { + key := common.ArgoCDDefaultApplicationInstanceLabelKey + if len(cr.Spec.ApplicationInstanceLabelKey) > 0 { + key = cr.Spec.ApplicationInstanceLabelKey + } + return key +} + +// getCAConfigMapName will return the CA ConfigMap name for the given ArgoCD. +func getCAConfigMapName(cr *argoproj.ArgoCD) string { + if len(cr.Spec.TLS.CA.ConfigMapName) > 0 { + return cr.Spec.TLS.CA.ConfigMapName + } + return nameWithSuffix(common.ArgoCDCASuffix, cr) +} + +// getSCMRootCAConfigMapName will return the SCMRootCA ConfigMap name for the given ArgoCD ApplicationSet Controller. +func getSCMRootCAConfigMapName(cr *argoproj.ArgoCD) string { + if cr.Spec.ApplicationSet.SCMRootCAConfigMap != "" && len(cr.Spec.ApplicationSet.SCMRootCAConfigMap) > 0 { + return cr.Spec.ApplicationSet.SCMRootCAConfigMap + } + return "" +} + +// getConfigManagementPlugins will return the config management plugins for the given ArgoCD. +func getConfigManagementPlugins(cr *argoproj.ArgoCD) string { + plugins := common.ArgoCDDefaultConfigManagementPlugins + if len(cr.Spec.ConfigManagementPlugins) > 0 { + plugins = cr.Spec.ConfigManagementPlugins + } + return plugins +} + +// getGATrackingID will return the google analytics tracking ID for the given Argo CD. +func getGATrackingID(cr *argoproj.ArgoCD) string { + id := common.ArgoCDDefaultGATrackingID + if len(cr.Spec.GATrackingID) > 0 { + id = cr.Spec.GATrackingID + } + return id +} + +// getHelpChatURL will return the help chat URL for the given Argo CD. +func getHelpChatURL(cr *argoproj.ArgoCD) string { + url := common.ArgoCDDefaultHelpChatURL + if len(cr.Spec.HelpChatURL) > 0 { + url = cr.Spec.HelpChatURL + } + return url +} + +// getHelpChatText will return the help chat text for the given Argo CD. +func getHelpChatText(cr *argoproj.ArgoCD) string { + text := common.ArgoCDDefaultHelpChatText + if len(cr.Spec.HelpChatText) > 0 { + text = cr.Spec.HelpChatText + } + return text +} + +// getKustomizeBuildOptions will return the kuztomize build options for the given ArgoCD. +func getKustomizeBuildOptions(cr *argoproj.ArgoCD) string { + kbo := common.ArgoCDDefaultKustomizeBuildOptions + if len(cr.Spec.KustomizeBuildOptions) > 0 { + kbo = cr.Spec.KustomizeBuildOptions + } + return kbo +} + +// getOIDCConfig will return the OIDC configuration for the given ArgoCD. +func getOIDCConfig(cr *argoproj.ArgoCD) string { + config := common.ArgoCDDefaultOIDCConfig + if len(cr.Spec.OIDCConfig) > 0 { + config = cr.Spec.OIDCConfig + } + return config +} + +// getResourceExclusions will return the resource exclusions for the given ArgoCD. +func getResourceExclusions(cr *argoproj.ArgoCD) string { + re := common.ArgoCDDefaultResourceExclusions + if cr.Spec.ResourceExclusions != "" { + re = cr.Spec.ResourceExclusions + } + return re +} + +// getResourceInclusions will return the resource inclusions for the given ArgoCD. +func getResourceInclusions(cr *argoproj.ArgoCD) string { + re := common.ArgoCDDefaultResourceInclusions + if cr.Spec.ResourceInclusions != "" { + re = cr.Spec.ResourceInclusions + } + return re +} + +// getInitialRepositories will return the initial repositories for the given ArgoCD. +func getInitialRepositories(cr *argoproj.ArgoCD) string { + repos := common.ArgoCDDefaultRepositories + if len(cr.Spec.InitialRepositories) > 0 { + repos = cr.Spec.InitialRepositories + } + return repos +} + +// getRepositoryCredentials will return the repository credentials for the given ArgoCD. +func getRepositoryCredentials(cr *argoproj.ArgoCD) string { + repos := common.ArgoCDDefaultRepositoryCredentials + if len(cr.Spec.RepositoryCredentials) > 0 { + repos = cr.Spec.RepositoryCredentials + } + return repos +} + +// getSSHKnownHosts will return the SSH Known Hosts data for the given ArgoCD. +func getInitialSSHKnownHosts(cr *argoproj.ArgoCD) string { + skh := common.ArgoCDDefaultSSHKnownHosts + if cr.Spec.InitialSSHKnownHosts.ExcludeDefaultHosts { + skh = "" + } + if len(cr.Spec.InitialSSHKnownHosts.Keys) > 0 { + skh += cr.Spec.InitialSSHKnownHosts.Keys + } + return skh +} + +// reconcileSSHKnownHosts will ensure that the ArgoCD SSH Known Hosts ConfigMap is present. +func (r *ReconcileArgoCD) reconcileSSHKnownHosts(cr *argoproj.ArgoCD) error { + cm := newConfigMapWithName(common.ArgoCDKnownHostsConfigMapName, cr) + if argoutil.IsObjectFound(r.Client, cr.Namespace, cm.Name, cm) { + return nil // ConfigMap found, move along... + } + + cm.Data = map[string]string{ + common.ArgoCDKeySSHKnownHosts: getInitialSSHKnownHosts(cr), + } + + if err := controllerutil.SetControllerReference(cr, cm, r.Scheme); err != nil { + return err + } + return r.Client.Create(context.TODO(), cm) +} + +// getTLSCerts will return the TLS certs for the given ArgoCD. +func getInitialTLSCerts(cr *argoproj.ArgoCD) map[string]string { + certs := make(map[string]string) + if len(cr.Spec.TLS.InitialCerts) > 0 { + certs = cr.Spec.TLS.InitialCerts + } + return certs +} + +// reconcileTLSCerts will ensure that the ArgoCD TLS Certs ConfigMap is present. +func (r *ReconcileArgoCD) reconcileTLSCerts(cr *argoproj.ArgoCD) error { + cm := newConfigMapWithName(common.ArgoCDTLSCertsConfigMapName, cr) + if argoutil.IsObjectFound(r.Client, cr.Namespace, cm.Name, cm) { + return nil // ConfigMap found, move along... + } + + cm.Data = getInitialTLSCerts(cr) + + if err := controllerutil.SetControllerReference(cr, cm, r.Scheme); err != nil { + return err + } + return r.Client.Create(context.TODO(), cm) +} + +// reconcileGPGKeysConfigMap creates a gpg-keys config map +func (r *ReconcileArgoCD) reconcileGPGKeysConfigMap(cr *argoproj.ArgoCD) error { + cm := newConfigMapWithName(common.ArgoCDGPGKeysConfigMapName, cr) + if argoutil.IsObjectFound(r.Client, cr.Namespace, cm.Name, cm) { + return nil + } + if err := controllerutil.SetControllerReference(cr, cm, r.Scheme); err != nil { + return err + } + return r.Client.Create(context.TODO(), cm) +} + +// getResourceTrackingMethod will return the resource tracking method for the given ArgoCD. +func getResourceTrackingMethod(cr *argoproj.ArgoCD) string { + rtm := argoproj.ParseResourceTrackingMethod(cr.Spec.ResourceTrackingMethod) + if rtm == argoproj.ResourceTrackingMethodInvalid { + log.Info(fmt.Sprintf("Found '%s' as resource tracking method, which is invalid. Using default 'label' method.", cr.Spec.ResourceTrackingMethod)) + } else if cr.Spec.ResourceTrackingMethod != "" { + log.Info(fmt.Sprintf("Found '%s' as tracking method", cr.Spec.ResourceTrackingMethod)) + } else { + log.Info("Using default resource tracking method 'label'") + } + return rtm.String() +} + +// getResourceHealthChecks loads health customizations to `resource.customizations.health` from argocd-cm ConfigMap +func getResourceHealthChecks(cr *argoproj.ArgoCD) map[string]string { + healthCheck := make(map[string]string) + if cr.Spec.ResourceHealthChecks != nil { + resourceHealthChecks := cr.Spec.ResourceHealthChecks + for _, healthCustomization := range resourceHealthChecks { + if healthCustomization.Group != "" { + healthCustomization.Group += "_" + } + subkey := "resource.customizations.health." + healthCustomization.Group + healthCustomization.Kind + subvalue := healthCustomization.Check + healthCheck[subkey] = subvalue + } + } + return healthCheck +} + +// getResourceIgnoreDifferences loads ignore differences customizations to `resource.customizations.ignoreDifferences` from argocd-cm ConfigMap +func getResourceIgnoreDifferences(cr *argoproj.ArgoCD) (map[string]string, error) { + ignoreDiff := make(map[string]string) + if cr.Spec.ResourceIgnoreDifferences != nil { + resourceIgnoreDiff := cr.Spec.ResourceIgnoreDifferences + if !reflect.DeepEqual(resourceIgnoreDiff.All, &argoproj.IgnoreDifferenceCustomization{}) { + subkey := "resource.customizations.ignoreDifferences.all" + bytes, err := yaml.Marshal(resourceIgnoreDiff.All) + if err != nil { + return ignoreDiff, err + } + subvalue := string(bytes) + ignoreDiff[subkey] = subvalue + } + for _, ignoreDiffCustomization := range resourceIgnoreDiff.ResourceIdentifiers { + if ignoreDiffCustomization.Group != "" { + ignoreDiffCustomization.Group += "_" + } + subkey := "resource.customizations.ignoreDifferences." + ignoreDiffCustomization.Group + ignoreDiffCustomization.Kind + bytes, err := yaml.Marshal(ignoreDiffCustomization.Customization) + if err != nil { + return ignoreDiff, err + } + subvalue := string(bytes) + ignoreDiff[subkey] = subvalue + } + } + return ignoreDiff, nil +} + +// getResourceActions loads custom actions to `resource.customizations.actions` from argocd-cm ConfigMap +func getResourceActions(cr *argoproj.ArgoCD) map[string]string { + action := make(map[string]string) + if cr.Spec.ResourceActions != nil { + resourceAction := cr.Spec.ResourceActions + for _, actionCustomization := range resourceAction { + if actionCustomization.Group != "" { + actionCustomization.Group += "_" + } + subkey := "resource.customizations.actions." + actionCustomization.Group + actionCustomization.Kind + subvalue := actionCustomization.Action + action[subkey] = subvalue + } + } + return action +} + +// newConfigMap returns a new ConfigMap instance for the given ArgoCD. +func newConfigMap(cr *argoproj.ArgoCD) *corev1.ConfigMap { + return &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: cr.Name, + Namespace: cr.Namespace, + Labels: argoutil.LabelsForCluster(cr), + }, + } +} + +// newConfigMapWithName creates a new ConfigMap with the given name for the given ArgCD. +func newConfigMapWithName(name string, cr *argoproj.ArgoCD) *corev1.ConfigMap { + cm := newConfigMap(cr) + cm.ObjectMeta.Name = name + + lbls := cm.ObjectMeta.Labels + lbls[common.ArgoCDKeyName] = name + cm.ObjectMeta.Labels = lbls + + return cm +} + +// newConfigMapWithName creates a new ConfigMap with the given suffix appended to the name. +// The name for the CongifMap is based on the name of the given ArgCD. +func newConfigMapWithSuffix(suffix string, cr *argoproj.ArgoCD) *corev1.ConfigMap { + return newConfigMapWithName(fmt.Sprintf("%s-%s", cr.ObjectMeta.Name, suffix), cr) +} + +// reconcileConfiguration will ensure that the main ConfigMap for ArgoCD is present. +func (r *ReconcileArgoCD) reconcileArgoConfigMap(cr *argoproj.ArgoCD) error { + cm := newConfigMapWithName(common.ArgoCDConfigMapName, cr) + + cm.Data = make(map[string]string) + + cm.Data[common.ArgoCDKeyApplicationInstanceLabelKey] = getApplicationInstanceLabelKey(cr) + cm.Data[common.ArgoCDKeyConfigManagementPlugins] = getConfigManagementPlugins(cr) + cm.Data[common.ArgoCDKeyAdminEnabled] = fmt.Sprintf("%t", !cr.Spec.DisableAdmin) + cm.Data[common.ArgoCDKeyGATrackingID] = getGATrackingID(cr) + cm.Data[common.ArgoCDKeyGAAnonymizeUsers] = fmt.Sprint(cr.Spec.GAAnonymizeUsers) + cm.Data[common.ArgoCDKeyHelpChatURL] = getHelpChatURL(cr) + cm.Data[common.ArgoCDKeyHelpChatText] = getHelpChatText(cr) + cm.Data[common.ArgoCDKeyKustomizeBuildOptions] = getKustomizeBuildOptions(cr) + + if len(cr.Spec.KustomizeVersions) > 0 { + for _, kv := range cr.Spec.KustomizeVersions { + cm.Data["kustomize.version."+kv.Version] = kv.Path + } + } + + cm.Data[common.ArgoCDKeyOIDCConfig] = getOIDCConfig(cr) + + if c := getResourceHealthChecks(cr); c != nil { + for k, v := range c { + cm.Data[k] = v + } + } + + if c, err := getResourceIgnoreDifferences(cr); c != nil && err == nil { + for k, v := range c { + cm.Data[k] = v + } + } else { + return err + } + + if c := getResourceActions(cr); c != nil { + for k, v := range c { + cm.Data[k] = v + } + } + + cm.Data[common.ArgoCDKeyResourceExclusions] = getResourceExclusions(cr) + cm.Data[common.ArgoCDKeyResourceInclusions] = getResourceInclusions(cr) + cm.Data[common.ArgoCDKeyResourceTrackingMethod] = getResourceTrackingMethod(cr) + cm.Data[common.ArgoCDKeyRepositories] = getInitialRepositories(cr) + cm.Data[common.ArgoCDKeyRepositoryCredentials] = getRepositoryCredentials(cr) + cm.Data[common.ArgoCDKeyStatusBadgeEnabled] = fmt.Sprint(cr.Spec.StatusBadgeEnabled) + cm.Data[common.ArgoCDKeyServerURL] = r.getArgoServerURI(cr) + cm.Data[common.ArgoCDKeyUsersAnonymousEnabled] = fmt.Sprint(cr.Spec.UsersAnonymousEnabled) + + // create dex config if dex is enabled through `.spec.sso` + if UseDex(cr) { + dexConfig := getDexConfig(cr) + + // If no dexConfig expressed but openShiftOAuth is requested through `.spec.sso.dex`, use default + // openshift dex config + if dexConfig == "" && (cr.Spec.SSO != nil && cr.Spec.SSO.Dex != nil && cr.Spec.SSO.Dex.OpenShiftOAuth) { + cfg, err := r.getOpenShiftDexConfig(cr) + if err != nil { + return err + } + dexConfig = cfg + } + cm.Data[common.ArgoCDKeyDexConfig] = dexConfig + } + + if cr.Spec.Banner != nil { + if cr.Spec.Banner.Content != "" { + cm.Data[common.ArgoCDKeyBannerContent] = cr.Spec.Banner.Content + if cr.Spec.Banner.URL != "" { + cm.Data[common.ArgoCDKeyBannerURL] = cr.Spec.Banner.URL + } + } + } + + if len(cr.Spec.ExtraConfig) > 0 { + for k, v := range cr.Spec.ExtraConfig { + cm.Data[k] = v + } + } + + if err := controllerutil.SetControllerReference(cr, cm, r.Scheme); err != nil { + return err + } + + existingCM := &corev1.ConfigMap{} + if argoutil.IsObjectFound(r.Client, cr.Namespace, cm.Name, existingCM) { + + // reconcile dex configuration if dex is enabled `.spec.sso.dex.provider` or there is + // existing dex configuration + if UseDex(cr) { + if err := r.reconcileDexConfiguration(existingCM, cr); err != nil { + return err + } + } else if cr.Spec.SSO != nil && cr.Spec.SSO.Provider.ToLower() == argoproj.SSOProviderTypeKeycloak { + // retain oidc.config during reconcilliation when keycloak is configured + cm.Data[common.ArgoCDKeyOIDCConfig] = existingCM.Data[common.ArgoCDKeyOIDCConfig] + } + + if !reflect.DeepEqual(cm.Data, existingCM.Data) { + existingCM.Data = cm.Data + return r.Client.Update(context.TODO(), existingCM) + } + return nil // Do nothing as there is no change in the configmap. + } + return r.Client.Create(context.TODO(), cm) + +} + +// reconcileCAConfigMap will ensure that the Certificate Authority ConfigMap is present. +// This ConfigMap holds the CA Certificate data for client use. +func (r *ReconcileArgoCD) reconcileCAConfigMap(cr *argoproj.ArgoCD) error { + cm := newConfigMapWithName(getCAConfigMapName(cr), cr) + if argoutil.IsObjectFound(r.Client, cr.Namespace, cm.Name, cm) { + return nil // ConfigMap found, do nothing + } + + caSecret := argoutil.NewSecretWithSuffix(cr, common.ArgoCDCASuffix) + if !argoutil.IsObjectFound(r.Client, cr.Namespace, caSecret.Name, caSecret) { + log.Info(fmt.Sprintf("ca secret [%s] not found, waiting to reconcile ca configmap [%s]", caSecret.Name, cm.Name)) + return nil + } + + cm.Data = map[string]string{ + common.ArgoCDKeyTLSCert: string(caSecret.Data[common.ArgoCDKeyTLSCert]), + } + + if err := controllerutil.SetControllerReference(cr, cm, r.Scheme); err != nil { + return err + } + return r.Client.Create(context.TODO(), cm) +} diff --git a/controllers/argocd/configmap.go b/controllers/argocd/configmap.go index 459018f0d..18efffcc9 100644 --- a/controllers/argocd/configmap.go +++ b/controllers/argocd/configmap.go @@ -16,12 +16,7 @@ package argocd import ( "context" - "fmt" - "reflect" - "gopkg.in/yaml.v2" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" argoproj "github.com/argoproj-labs/argocd-operator/api/v1beta1" @@ -29,283 +24,6 @@ import ( "github.com/argoproj-labs/argocd-operator/pkg/argoutil" ) -// createRBACConfigMap will create the Argo CD RBAC ConfigMap resource. -func (r *ReconcileArgoCD) createRBACConfigMap(cm *corev1.ConfigMap, cr *argoproj.ArgoCD) error { - data := make(map[string]string) - data[common.ArgoCDKeyRBACPolicyCSV] = getRBACPolicy(cr) - data[common.ArgoCDKeyRBACPolicyDefault] = getRBACDefaultPolicy(cr) - data[common.ArgoCDKeyRBACScopes] = getRBACScopes(cr) - cm.Data = data - - if err := controllerutil.SetControllerReference(cr, cm, r.Scheme); err != nil { - return err - } - return r.Client.Create(context.TODO(), cm) -} - -// getApplicationInstanceLabelKey will return the application instance label key for the given ArgoCD. -func getApplicationInstanceLabelKey(cr *argoproj.ArgoCD) string { - key := common.ArgoCDDefaultApplicationInstanceLabelKey - if len(cr.Spec.ApplicationInstanceLabelKey) > 0 { - key = cr.Spec.ApplicationInstanceLabelKey - } - return key -} - -// getCAConfigMapName will return the CA ConfigMap name for the given ArgoCD. -func getCAConfigMapName(cr *argoproj.ArgoCD) string { - if len(cr.Spec.TLS.CA.ConfigMapName) > 0 { - return cr.Spec.TLS.CA.ConfigMapName - } - return nameWithSuffix(common.ArgoCDCASuffix, cr) -} - -// getSCMRootCAConfigMapName will return the SCMRootCA ConfigMap name for the given ArgoCD ApplicationSet Controller. -func getSCMRootCAConfigMapName(cr *argoproj.ArgoCD) string { - if cr.Spec.ApplicationSet.SCMRootCAConfigMap != "" && len(cr.Spec.ApplicationSet.SCMRootCAConfigMap) > 0 { - return cr.Spec.ApplicationSet.SCMRootCAConfigMap - } - return "" -} - -// getConfigManagementPlugins will return the config management plugins for the given ArgoCD. -func getConfigManagementPlugins(cr *argoproj.ArgoCD) string { - plugins := common.ArgoCDDefaultConfigManagementPlugins - if len(cr.Spec.ConfigManagementPlugins) > 0 { - plugins = cr.Spec.ConfigManagementPlugins - } - return plugins -} - -// getGATrackingID will return the google analytics tracking ID for the given Argo CD. -func getGATrackingID(cr *argoproj.ArgoCD) string { - id := common.ArgoCDDefaultGATrackingID - if len(cr.Spec.GATrackingID) > 0 { - id = cr.Spec.GATrackingID - } - return id -} - -// getHelpChatURL will return the help chat URL for the given Argo CD. -func getHelpChatURL(cr *argoproj.ArgoCD) string { - url := common.ArgoCDDefaultHelpChatURL - if len(cr.Spec.HelpChatURL) > 0 { - url = cr.Spec.HelpChatURL - } - return url -} - -// getHelpChatText will return the help chat text for the given Argo CD. -func getHelpChatText(cr *argoproj.ArgoCD) string { - text := common.ArgoCDDefaultHelpChatText - if len(cr.Spec.HelpChatText) > 0 { - text = cr.Spec.HelpChatText - } - return text -} - -// getKustomizeBuildOptions will return the kuztomize build options for the given ArgoCD. -func getKustomizeBuildOptions(cr *argoproj.ArgoCD) string { - kbo := common.ArgoCDDefaultKustomizeBuildOptions - if len(cr.Spec.KustomizeBuildOptions) > 0 { - kbo = cr.Spec.KustomizeBuildOptions - } - return kbo -} - -// getOIDCConfig will return the OIDC configuration for the given ArgoCD. -func getOIDCConfig(cr *argoproj.ArgoCD) string { - config := common.ArgoCDDefaultOIDCConfig - if len(cr.Spec.OIDCConfig) > 0 { - config = cr.Spec.OIDCConfig - } - return config -} - -// getRBACPolicy will return the RBAC policy for the given ArgoCD. -func getRBACPolicy(cr *argoproj.ArgoCD) string { - policy := common.ArgoCDDefaultRBACPolicy - if cr.Spec.RBAC.Policy != nil { - policy = *cr.Spec.RBAC.Policy - } - return policy -} - -// getRBACDefaultPolicy will retun the RBAC default policy for the given ArgoCD. -func getRBACDefaultPolicy(cr *argoproj.ArgoCD) string { - dp := common.ArgoCDDefaultRBACDefaultPolicy - if cr.Spec.RBAC.DefaultPolicy != nil { - dp = *cr.Spec.RBAC.DefaultPolicy - } - return dp -} - -// getRBACScopes will return the RBAC scopes for the given ArgoCD. -func getRBACScopes(cr *argoproj.ArgoCD) string { - scopes := common.ArgoCDDefaultRBACScopes - if cr.Spec.RBAC.Scopes != nil { - scopes = *cr.Spec.RBAC.Scopes - } - return scopes -} - -// getResourceHealthChecks loads health customizations to `resource.customizations.health` from argocd-cm ConfigMap -func getResourceHealthChecks(cr *argoproj.ArgoCD) map[string]string { - healthCheck := make(map[string]string) - if cr.Spec.ResourceHealthChecks != nil { - resourceHealthChecks := cr.Spec.ResourceHealthChecks - for _, healthCustomization := range resourceHealthChecks { - if healthCustomization.Group != "" { - healthCustomization.Group += "_" - } - subkey := "resource.customizations.health." + healthCustomization.Group + healthCustomization.Kind - subvalue := healthCustomization.Check - healthCheck[subkey] = subvalue - } - } - return healthCheck -} - -// getResourceIgnoreDifferences loads ignore differences customizations to `resource.customizations.ignoreDifferences` from argocd-cm ConfigMap -func getResourceIgnoreDifferences(cr *argoproj.ArgoCD) (map[string]string, error) { - ignoreDiff := make(map[string]string) - if cr.Spec.ResourceIgnoreDifferences != nil { - resourceIgnoreDiff := cr.Spec.ResourceIgnoreDifferences - if !reflect.DeepEqual(resourceIgnoreDiff.All, &argoproj.IgnoreDifferenceCustomization{}) { - subkey := "resource.customizations.ignoreDifferences.all" - bytes, err := yaml.Marshal(resourceIgnoreDiff.All) - if err != nil { - return ignoreDiff, err - } - subvalue := string(bytes) - ignoreDiff[subkey] = subvalue - } - for _, ignoreDiffCustomization := range resourceIgnoreDiff.ResourceIdentifiers { - if ignoreDiffCustomization.Group != "" { - ignoreDiffCustomization.Group += "_" - } - subkey := "resource.customizations.ignoreDifferences." + ignoreDiffCustomization.Group + ignoreDiffCustomization.Kind - bytes, err := yaml.Marshal(ignoreDiffCustomization.Customization) - if err != nil { - return ignoreDiff, err - } - subvalue := string(bytes) - ignoreDiff[subkey] = subvalue - } - } - return ignoreDiff, nil -} - -// getResourceActions loads custom actions to `resource.customizations.actions` from argocd-cm ConfigMap -func getResourceActions(cr *argoproj.ArgoCD) map[string]string { - action := make(map[string]string) - if cr.Spec.ResourceActions != nil { - resourceAction := cr.Spec.ResourceActions - for _, actionCustomization := range resourceAction { - if actionCustomization.Group != "" { - actionCustomization.Group += "_" - } - subkey := "resource.customizations.actions." + actionCustomization.Group + actionCustomization.Kind - subvalue := actionCustomization.Action - action[subkey] = subvalue - } - } - return action -} - -// getResourceExclusions will return the resource exclusions for the given ArgoCD. -func getResourceExclusions(cr *argoproj.ArgoCD) string { - re := common.ArgoCDDefaultResourceExclusions - if cr.Spec.ResourceExclusions != "" { - re = cr.Spec.ResourceExclusions - } - return re -} - -// getResourceInclusions will return the resource inclusions for the given ArgoCD. -func getResourceInclusions(cr *argoproj.ArgoCD) string { - re := common.ArgoCDDefaultResourceInclusions - if cr.Spec.ResourceInclusions != "" { - re = cr.Spec.ResourceInclusions - } - return re -} - -// getResourceTrackingMethod will return the resource tracking method for the given ArgoCD. -func getResourceTrackingMethod(cr *argoproj.ArgoCD) string { - rtm := argoproj.ParseResourceTrackingMethod(cr.Spec.ResourceTrackingMethod) - if rtm == argoproj.ResourceTrackingMethodInvalid { - log.Info(fmt.Sprintf("Found '%s' as resource tracking method, which is invalid. Using default 'label' method.", cr.Spec.ResourceTrackingMethod)) - } else if cr.Spec.ResourceTrackingMethod != "" { - log.Info(fmt.Sprintf("Found '%s' as tracking method", cr.Spec.ResourceTrackingMethod)) - } else { - log.Info("Using default resource tracking method 'label'") - } - return rtm.String() -} - -// getInitialRepositories will return the initial repositories for the given ArgoCD. -func getInitialRepositories(cr *argoproj.ArgoCD) string { - repos := common.ArgoCDDefaultRepositories - if len(cr.Spec.InitialRepositories) > 0 { - repos = cr.Spec.InitialRepositories - } - return repos -} - -// getRepositoryCredentials will return the repository credentials for the given ArgoCD. -func getRepositoryCredentials(cr *argoproj.ArgoCD) string { - repos := common.ArgoCDDefaultRepositoryCredentials - if len(cr.Spec.RepositoryCredentials) > 0 { - repos = cr.Spec.RepositoryCredentials - } - return repos -} - -// getSSHKnownHosts will return the SSH Known Hosts data for the given ArgoCD. -func getInitialSSHKnownHosts(cr *argoproj.ArgoCD) string { - skh := common.ArgoCDDefaultSSHKnownHosts - if cr.Spec.InitialSSHKnownHosts.ExcludeDefaultHosts { - skh = "" - } - if len(cr.Spec.InitialSSHKnownHosts.Keys) > 0 { - skh += cr.Spec.InitialSSHKnownHosts.Keys - } - return skh -} - -// getTLSCerts will return the TLS certs for the given ArgoCD. -func getInitialTLSCerts(cr *argoproj.ArgoCD) map[string]string { - certs := make(map[string]string) - if len(cr.Spec.TLS.InitialCerts) > 0 { - certs = cr.Spec.TLS.InitialCerts - } - return certs -} - -// newConfigMap returns a new ConfigMap instance for the given ArgoCD. -func newConfigMap(cr *argoproj.ArgoCD) *corev1.ConfigMap { - return &corev1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: cr.Name, - Namespace: cr.Namespace, - Labels: argoutil.LabelsForCluster(cr), - }, - } -} - -// newConfigMapWithName creates a new ConfigMap with the given name for the given ArgCD. -func newConfigMapWithName(name string, cr *argoproj.ArgoCD) *corev1.ConfigMap { - cm := newConfigMap(cr) - cm.ObjectMeta.Name = name - - lbls := cm.ObjectMeta.Labels - lbls[common.ArgoCDKeyName] = name - cm.ObjectMeta.Labels = lbls - - return cm -} - // reconcileConfigMaps will ensure that all ArgoCD ConfigMaps are present. func (r *ReconcileArgoCD) reconcileConfigMaps(cr *argoproj.ArgoCD, useTLSForRedis bool) error { if err := r.reconcileArgoConfigMap(cr); err != nil { @@ -328,216 +46,9 @@ func (r *ReconcileArgoCD) reconcileConfigMaps(cr *argoproj.ArgoCD, useTLSForRedi return err } - if err := r.reconcileGrafanaConfiguration(cr); err != nil { - return err - } - - if err := r.reconcileGrafanaDashboards(cr); err != nil { - return err - } - return r.reconcileGPGKeysConfigMap(cr) } -// reconcileCAConfigMap will ensure that the Certificate Authority ConfigMap is present. -// This ConfigMap holds the CA Certificate data for client use. -func (r *ReconcileArgoCD) reconcileCAConfigMap(cr *argoproj.ArgoCD) error { - cm := newConfigMapWithName(getCAConfigMapName(cr), cr) - if argoutil.IsObjectFound(r.Client, cr.Namespace, cm.Name, cm) { - return nil // ConfigMap found, do nothing - } - - caSecret := argoutil.NewSecretWithSuffix(cr, common.ArgoCDCASuffix) - if !argoutil.IsObjectFound(r.Client, cr.Namespace, caSecret.Name, caSecret) { - log.Info(fmt.Sprintf("ca secret [%s] not found, waiting to reconcile ca configmap [%s]", caSecret.Name, cm.Name)) - return nil - } - - cm.Data = map[string]string{ - common.ArgoCDKeyTLSCert: string(caSecret.Data[common.ArgoCDKeyTLSCert]), - } - - if err := controllerutil.SetControllerReference(cr, cm, r.Scheme); err != nil { - return err - } - return r.Client.Create(context.TODO(), cm) -} - -// reconcileConfiguration will ensure that the main ConfigMap for ArgoCD is present. -func (r *ReconcileArgoCD) reconcileArgoConfigMap(cr *argoproj.ArgoCD) error { - cm := newConfigMapWithName(common.ArgoCDConfigMapName, cr) - - cm.Data = make(map[string]string) - - cm.Data[common.ArgoCDKeyApplicationInstanceLabelKey] = getApplicationInstanceLabelKey(cr) - cm.Data[common.ArgoCDKeyConfigManagementPlugins] = getConfigManagementPlugins(cr) - cm.Data[common.ArgoCDKeyAdminEnabled] = fmt.Sprintf("%t", !cr.Spec.DisableAdmin) - cm.Data[common.ArgoCDKeyGATrackingID] = getGATrackingID(cr) - cm.Data[common.ArgoCDKeyGAAnonymizeUsers] = fmt.Sprint(cr.Spec.GAAnonymizeUsers) - cm.Data[common.ArgoCDKeyHelpChatURL] = getHelpChatURL(cr) - cm.Data[common.ArgoCDKeyHelpChatText] = getHelpChatText(cr) - cm.Data[common.ArgoCDKeyKustomizeBuildOptions] = getKustomizeBuildOptions(cr) - - if len(cr.Spec.KustomizeVersions) > 0 { - for _, kv := range cr.Spec.KustomizeVersions { - cm.Data["kustomize.version."+kv.Version] = kv.Path - } - } - - cm.Data[common.ArgoCDKeyOIDCConfig] = getOIDCConfig(cr) - - if c := getResourceHealthChecks(cr); c != nil { - for k, v := range c { - cm.Data[k] = v - } - } - - if c, err := getResourceIgnoreDifferences(cr); c != nil && err == nil { - for k, v := range c { - cm.Data[k] = v - } - } else { - return err - } - - if c := getResourceActions(cr); c != nil { - for k, v := range c { - cm.Data[k] = v - } - } - - cm.Data[common.ArgoCDKeyResourceExclusions] = getResourceExclusions(cr) - cm.Data[common.ArgoCDKeyResourceInclusions] = getResourceInclusions(cr) - cm.Data[common.ArgoCDKeyResourceTrackingMethod] = getResourceTrackingMethod(cr) - cm.Data[common.ArgoCDKeyRepositories] = getInitialRepositories(cr) - cm.Data[common.ArgoCDKeyRepositoryCredentials] = getRepositoryCredentials(cr) - cm.Data[common.ArgoCDKeyStatusBadgeEnabled] = fmt.Sprint(cr.Spec.StatusBadgeEnabled) - cm.Data[common.ArgoCDKeyServerURL] = r.getArgoServerURI(cr) - cm.Data[common.ArgoCDKeyUsersAnonymousEnabled] = fmt.Sprint(cr.Spec.UsersAnonymousEnabled) - - // create dex config if dex is enabled through `.spec.sso` - if UseDex(cr) { - dexConfig := getDexConfig(cr) - - // Append the default OpenShift dex config if the openShiftOAuth is requested through `.spec.sso.dex`. - if cr.Spec.SSO != nil && cr.Spec.SSO.Dex != nil && cr.Spec.SSO.Dex.OpenShiftOAuth { - cfg, err := r.getOpenShiftDexConfig(cr) - if err != nil { - return err - } - dexConfig = cfg - } - cm.Data[common.ArgoCDKeyDexConfig] = dexConfig - } - - if cr.Spec.Banner != nil { - if cr.Spec.Banner.Content != "" { - cm.Data[common.ArgoCDKeyBannerContent] = cr.Spec.Banner.Content - if cr.Spec.Banner.URL != "" { - cm.Data[common.ArgoCDKeyBannerURL] = cr.Spec.Banner.URL - } - } - } - - if len(cr.Spec.ExtraConfig) > 0 { - for k, v := range cr.Spec.ExtraConfig { - cm.Data[k] = v - } - } - - if err := controllerutil.SetControllerReference(cr, cm, r.Scheme); err != nil { - return err - } - - existingCM := &corev1.ConfigMap{} - if argoutil.IsObjectFound(r.Client, cr.Namespace, cm.Name, existingCM) { - - // reconcile dex configuration if dex is enabled `.spec.sso.dex.provider` or there is - // existing dex configuration - if UseDex(cr) { - if err := r.reconcileDexConfiguration(existingCM, cr); err != nil { - return err - } - } else if cr.Spec.SSO != nil && cr.Spec.SSO.Provider.ToLower() == argoproj.SSOProviderTypeKeycloak { - // retain oidc.config during reconcilliation when keycloak is configured - cm.Data[common.ArgoCDKeyOIDCConfig] = existingCM.Data[common.ArgoCDKeyOIDCConfig] - } - - if !reflect.DeepEqual(cm.Data, existingCM.Data) { - existingCM.Data = cm.Data - return r.Client.Update(context.TODO(), existingCM) - } - return nil // Do nothing as there is no change in the configmap. - } - return r.Client.Create(context.TODO(), cm) - -} - -// reconcileGrafanaConfiguration will ensure that the Grafana configuration ConfigMap is present. -func (r *ReconcileArgoCD) reconcileGrafanaConfiguration(cr *argoproj.ArgoCD) error { - if !cr.Spec.Grafana.Enabled { - return nil // Grafana not enabled, do nothing. - } - - log.Info(grafanaDeprecatedWarning) - - return nil -} - -// reconcileGrafanaDashboards will ensure that the Grafana dashboards ConfigMap is present. -func (r *ReconcileArgoCD) reconcileGrafanaDashboards(cr *argoproj.ArgoCD) error { - if !cr.Spec.Grafana.Enabled { - return nil // Grafana not enabled, do nothing. - } - - log.Info(grafanaDeprecatedWarning) - - return nil -} - -// reconcileRBAC will ensure that the ArgoCD RBAC ConfigMap is present. -func (r *ReconcileArgoCD) reconcileRBAC(cr *argoproj.ArgoCD) error { - cm := newConfigMapWithName(common.ArgoCDRBACConfigMapName, cr) - if argoutil.IsObjectFound(r.Client, cr.Namespace, cm.Name, cm) { - return r.reconcileRBACConfigMap(cm, cr) - } - return r.createRBACConfigMap(cm, cr) -} - -// reconcileRBACConfigMap will ensure that the RBAC ConfigMap is syncronized with the given ArgoCD. -func (r *ReconcileArgoCD) reconcileRBACConfigMap(cm *corev1.ConfigMap, cr *argoproj.ArgoCD) error { - changed := false - // Policy CSV - if cr.Spec.RBAC.Policy != nil && cm.Data[common.ArgoCDKeyRBACPolicyCSV] != *cr.Spec.RBAC.Policy { - cm.Data[common.ArgoCDKeyRBACPolicyCSV] = *cr.Spec.RBAC.Policy - changed = true - } - - // Default Policy - if cr.Spec.RBAC.DefaultPolicy != nil && cm.Data[common.ArgoCDKeyRBACPolicyDefault] != *cr.Spec.RBAC.DefaultPolicy { - cm.Data[common.ArgoCDKeyRBACPolicyDefault] = *cr.Spec.RBAC.DefaultPolicy - changed = true - } - - // Default Policy Matcher Mode - if cr.Spec.RBAC.PolicyMatcherMode != nil && cm.Data[common.ArgoCDKeyPolicyMatcherMode] != *cr.Spec.RBAC.PolicyMatcherMode { - cm.Data[common.ArgoCDKeyPolicyMatcherMode] = *cr.Spec.RBAC.PolicyMatcherMode - changed = true - } - - // Scopes - if cr.Spec.RBAC.Scopes != nil && cm.Data[common.ArgoCDKeyRBACScopes] != *cr.Spec.RBAC.Scopes { - cm.Data[common.ArgoCDKeyRBACScopes] = *cr.Spec.RBAC.Scopes - changed = true - } - - if changed { - // TODO: Reload server (and dex?) if RBAC settings change? - return r.Client.Update(context.TODO(), cm) - } - return nil // ConfigMap exists and nothing to do, move along... -} - // reconcileRedisConfiguration will ensure that all of the Redis ConfigMaps are present for the given ArgoCD. func (r *ReconcileArgoCD) reconcileRedisConfiguration(cr *argoproj.ArgoCD, useTLSForRedis bool) error { if err := r.reconcileRedisHAConfigMap(cr, useTLSForRedis); err != nil { @@ -624,47 +135,3 @@ func (r *ReconcileArgoCD) recreateRedisHAHealthConfigMap(cr *argoproj.ArgoCD, us } return r.reconcileRedisHAHealthConfigMap(cr, useTLSForRedis) } - -// reconcileSSHKnownHosts will ensure that the ArgoCD SSH Known Hosts ConfigMap is present. -func (r *ReconcileArgoCD) reconcileSSHKnownHosts(cr *argoproj.ArgoCD) error { - cm := newConfigMapWithName(common.ArgoCDKnownHostsConfigMapName, cr) - if argoutil.IsObjectFound(r.Client, cr.Namespace, cm.Name, cm) { - return nil // ConfigMap found, move along... - } - - cm.Data = map[string]string{ - common.ArgoCDKeySSHKnownHosts: getInitialSSHKnownHosts(cr), - } - - if err := controllerutil.SetControllerReference(cr, cm, r.Scheme); err != nil { - return err - } - return r.Client.Create(context.TODO(), cm) -} - -// reconcileTLSCerts will ensure that the ArgoCD TLS Certs ConfigMap is present. -func (r *ReconcileArgoCD) reconcileTLSCerts(cr *argoproj.ArgoCD) error { - cm := newConfigMapWithName(common.ArgoCDTLSCertsConfigMapName, cr) - if argoutil.IsObjectFound(r.Client, cr.Namespace, cm.Name, cm) { - return nil // ConfigMap found, move along... - } - - cm.Data = getInitialTLSCerts(cr) - - if err := controllerutil.SetControllerReference(cr, cm, r.Scheme); err != nil { - return err - } - return r.Client.Create(context.TODO(), cm) -} - -// reconcileGPGKeysConfigMap creates a gpg-keys config map -func (r *ReconcileArgoCD) reconcileGPGKeysConfigMap(cr *argoproj.ArgoCD) error { - cm := newConfigMapWithName(common.ArgoCDGPGKeysConfigMapName, cr) - if argoutil.IsObjectFound(r.Client, cr.Namespace, cm.Name, cm) { - return nil - } - if err := controllerutil.SetControllerReference(cr, cm, r.Scheme); err != nil { - return err - } - return r.Client.Create(context.TODO(), cm) -} diff --git a/controllers/argocd/configmap/configmap.go b/controllers/argocd/configmap/configmap.go deleted file mode 100644 index 6d3501551..000000000 --- a/controllers/argocd/configmap/configmap.go +++ /dev/null @@ -1,22 +0,0 @@ -package configmap - -import ( - "github.com/go-logr/logr" - "k8s.io/apimachinery/pkg/runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - - argoproj "github.com/argoproj-labs/argocd-operator/api/v1beta1" -) - -type ConfigMapReconciler struct { - Client *client.Client - Scheme *runtime.Scheme - Instance *argoproj.ArgoCD - Logger logr.Logger -} - -func (cmr *ConfigMapReconciler) Reconcile() error { - - // controller logic goes here - return nil -} diff --git a/controllers/argocd/configmaps.go b/controllers/argocd/configmaps.go new file mode 100644 index 000000000..71a3e4546 --- /dev/null +++ b/controllers/argocd/configmaps.go @@ -0,0 +1,282 @@ +package argocd + +import ( + "github.com/argoproj-labs/argocd-operator/common" + "github.com/argoproj-labs/argocd-operator/controllers/argocd/argocdcommon" + "github.com/argoproj-labs/argocd-operator/pkg/argoutil" + "github.com/argoproj-labs/argocd-operator/pkg/mutation" + "github.com/argoproj-labs/argocd-operator/pkg/util" + "github.com/argoproj-labs/argocd-operator/pkg/workloads" + "github.com/pkg/errors" + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" +) + +var ( + caResourceName string +) + +func (r *ArgoCDReconciler) reconcileConfigMaps() error { + var reconErrs util.MultiError + r.cmVarSetter() + + err := r.reconcileRBACCm() + reconErrs.Append(err) + + err = r.reconcileSSHKnownHostsCm() + reconErrs.Append(err) + + err = r.reconcileTLSCertsCm() + reconErrs.Append(err) + + err = r.reconcileGPGKeysCm() + reconErrs.Append(err) + + err = r.reconcileCACm() + reconErrs.Append(err) + + err = r.reeconcileArgoCDCm() + reconErrs.Append(err) + + return reconErrs.ErrOrNil() +} + +func (r *ArgoCDReconciler) deleteConfigMaps() error { + var delErrs util.MultiError + + err := r.deleteConfigMap(common.ArgoCDConfigMapName, r.Instance.Namespace) + delErrs.Append(err) + + err = r.deleteConfigMap(caResourceName, r.Instance.Namespace) + delErrs.Append(err) + + err = r.deleteConfigMap(common.ArgoCDGPGKeysConfigMapName, r.Instance.Namespace) + delErrs.Append(err) + + err = r.deleteConfigMap(common.ArgoCDTLSCertsConfigMapName, r.Instance.Namespace) + delErrs.Append(err) + + err = r.deleteConfigMap(common.ArgoCDKnownHostsConfigMapName, r.Instance.Namespace) + delErrs.Append(err) + + err = r.deleteConfigMap(common.ArgoCDRBACConfigMapName, r.Instance.Namespace) + delErrs.Append(err) + + return delErrs.ErrOrNil() +} + +// reconcileConfiguration will ensure that the main ConfigMap for ArgoCD is present. +func (r *ArgoCDReconciler) reeconcileArgoCDCm() error { + req := workloads.ConfigMapRequest{ + ObjectMeta: argoutil.GetObjMeta(common.ArgoCDConfigMapName, r.Instance.Namespace, r.Instance.Name, r.Instance.Namespace, ""), + Data: map[string]string{ + common.ArgoCDKeyApplicationInstanceLabelKey: r.getApplicationInstanceLabelKey(), + common.ArgoCDKeyConfigManagementPlugins: r.getConfigManagementPlugins(), + common.ArgoCDKeyAdminEnabled: r.getDisableAdmin(), + common.ArgoCDKeyGATrackingID: r.getGATrackingID(), + common.ArgoCDKeyGAAnonymizeUsers: r.getGAAnonymizeUsers(), + common.ArgoCDKeyHelpChatURL: r.getHelpChatURL(), + common.ArgoCDKeyHelpChatText: r.getHelpChatText(), + common.ArgoCDKeyKustomizeBuildOptions: r.getKustomizeBuildOptions(), + common.ArgoCDKeyOIDCConfig: r.getOIDCConfig(), + common.ArgoCDKeyResourceExclusions: r.getResourceExclusions(), + common.ArgoCDKeyResourceInclusions: r.getResourceInclusions(), + common.ArgoCDKeyResourceTrackingMethod: r.getResourceTrackingMethod(), + common.ArgoCDKeyRepositories: r.getInitialRepositories(), + common.ArgoCDKeyRepositoryCredentials: r.getRepositoryCredentials(), + common.ArgoCDKeyStatusBadgeEnabled: r.getStatusBadgeEnabled(), + common.ArgoCDKeyUsersAnonymousEnabled: r.getUsersAnonymousEnabled(), + // TO DO: skipping server URI since that should be handled by server component + }, + Mutations: []mutation.MutateFunc{mutation.ApplyReconcilerMutation}, + Client: r.Client, + } + + // TO DO: skipping dex config since that should be handled by SSO component + + req.Data = util.MergeMaps(req.Data, r.getKustomizeVersions()) + req.Data = util.MergeMaps(req.Data, r.getResourceHealthChecks()) + req.Data = util.MergeMaps(req.Data, r.getResourceActions()) + req.Data = util.MergeMaps(req.Data, r.getResourceIgnoreDifferences()) + req.Data = util.MergeMaps(req.Data, r.getBanner()) + req.Data = util.MergeMaps(req.Data, r.getExtraConfig()) + + fieldsToCompare := func(existing, desired *corev1.ConfigMap) []argocdcommon.FieldToCompare { + return []argocdcommon.FieldToCompare{ + {Existing: &existing.Labels, Desired: &desired.Labels, ExtraAction: nil}, + {Existing: &existing.Annotations, Desired: &desired.Annotations, ExtraAction: nil}, + {Existing: &existing.Data, Desired: &desired.Data, ExtraAction: nil}, + } + } + + return r.reconcileCM(req, fieldsToCompare) +} + +// reconcileCAConfigMap will ensure that the Certificate Authority ConfigMap is present. +// This ConfigMap holds the CA Certificate data for client use. +func (r *ArgoCDReconciler) reconcileCACm() error { + caSecret, err := workloads.GetSecret(caResourceName, r.Instance.Namespace, r.Client) + if err != nil { + return errors.Wrapf(err, "reconcileCACm: failed to retrieve ca secret %s in namespace %s", caResourceName, r.Instance.Namespace) + } + + req := workloads.ConfigMapRequest{ + ObjectMeta: argoutil.GetObjMeta(r.getCAConfigMapName(), r.Instance.Namespace, r.Instance.Name, r.Instance.Namespace, ""), + Data: map[string]string{ + common.ArgoCDKeyTLSCert: string(caSecret.Data[common.ArgoCDKeyTLSCert]), + }, + Mutations: []mutation.MutateFunc{mutation.ApplyReconcilerMutation}, + Client: r.Client, + } + + fieldsToCompare := func(existing, desired *corev1.ConfigMap) []argocdcommon.FieldToCompare { + return []argocdcommon.FieldToCompare{ + {Existing: &existing.Labels, Desired: &desired.Labels, ExtraAction: nil}, + {Existing: &existing.Annotations, Desired: &desired.Annotations, ExtraAction: nil}, + {Existing: &existing.Data, Desired: &desired.Data, ExtraAction: nil}, + } + } + + return r.reconcileCM(req, fieldsToCompare) +} + +// reconcileGPGKeysConfigMap creates a gpg-keys config map +func (r *ArgoCDReconciler) reconcileGPGKeysCm() error { + req := workloads.ConfigMapRequest{ + ObjectMeta: argoutil.GetObjMeta(common.ArgoCDGPGKeysConfigMapName, r.Instance.Namespace, r.Instance.Name, r.Instance.Namespace, ""), + Mutations: []mutation.MutateFunc{mutation.ApplyReconcilerMutation}, + Client: r.Client, + } + + fieldsToCompare := func(existing, desired *corev1.ConfigMap) []argocdcommon.FieldToCompare { + return []argocdcommon.FieldToCompare{ + {Existing: &existing.Labels, Desired: &desired.Labels, ExtraAction: nil}, + {Existing: &existing.Annotations, Desired: &desired.Annotations, ExtraAction: nil}, + {Existing: &existing.Data, Desired: &desired.Data, ExtraAction: nil}, + } + } + + return r.reconcileCM(req, fieldsToCompare) +} + +// reconcileTLSCerts will ensure that the ArgoCD TLS Certs ConfigMap is present. +func (r *ArgoCDReconciler) reconcileTLSCertsCm() error { + req := workloads.ConfigMapRequest{ + ObjectMeta: argoutil.GetObjMeta(common.ArgoCDTLSCertsConfigMapName, r.Instance.Namespace, r.Instance.Name, r.Instance.Namespace, ""), + Data: r.getInitialTLSCerts(), + Mutations: []mutation.MutateFunc{mutation.ApplyReconcilerMutation}, + Client: r.Client, + } + + fieldsToCompare := func(existing, desired *corev1.ConfigMap) []argocdcommon.FieldToCompare { + return []argocdcommon.FieldToCompare{ + {Existing: &existing.Labels, Desired: &desired.Labels, ExtraAction: nil}, + {Existing: &existing.Annotations, Desired: &desired.Annotations, ExtraAction: nil}, + {Existing: &existing.Data, Desired: &desired.Data, ExtraAction: nil}, + } + } + + return r.reconcileCM(req, fieldsToCompare) +} + +// reconcileSSHKnownHosts will ensure that the ArgoCD SSH Known Hosts ConfigMap is present. +func (r *ArgoCDReconciler) reconcileSSHKnownHostsCm() error { + req := workloads.ConfigMapRequest{ + ObjectMeta: argoutil.GetObjMeta(common.ArgoCDKnownHostsConfigMapName, r.Instance.Namespace, r.Instance.Name, r.Instance.Namespace, ""), + Data: map[string]string{ + common.ArgoCDKeySSHKnownHosts: r.getInitialSSHKnownHosts(), + }, + Mutations: []mutation.MutateFunc{mutation.ApplyReconcilerMutation}, + Client: r.Client, + } + + fieldsToCompare := func(existing, desired *corev1.ConfigMap) []argocdcommon.FieldToCompare { + return []argocdcommon.FieldToCompare{ + {Existing: &existing.Labels, Desired: &desired.Labels, ExtraAction: nil}, + {Existing: &existing.Annotations, Desired: &desired.Annotations, ExtraAction: nil}, + {Existing: &existing.Data, Desired: &desired.Data, ExtraAction: nil}, + } + } + + return r.reconcileCM(req, fieldsToCompare) +} + +// reconcileRBACCm will ensure that the Redis HA ConfigMap is present for the given ArgoCD instance +func (r *ArgoCDReconciler) reconcileRBACCm() error { + req := workloads.ConfigMapRequest{ + ObjectMeta: argoutil.GetObjMeta(common.ArgoCDRBACConfigMapName, r.Instance.Namespace, r.Instance.Name, r.Instance.Namespace, ""), + Data: map[string]string{ + common.ArgoCDKeyRBACPolicyCSV: r.getRBACPolicy(), + common.ArgoCDKeyRBACPolicyDefault: r.getRBACDefaultPolicy(), + common.ArgoCDKeyRBACScopes: r.getRBACScopes(), + common.ArgoCDKeyPolicyMatcherMode: r.getRBACPolicyMatcherMode(), + }, + Mutations: []mutation.MutateFunc{mutation.ApplyReconcilerMutation}, + Client: r.Client, + } + + fieldsToCompare := func(existing, desired *corev1.ConfigMap) []argocdcommon.FieldToCompare { + return []argocdcommon.FieldToCompare{ + {Existing: &existing.Labels, Desired: &desired.Labels, ExtraAction: nil}, + {Existing: &existing.Annotations, Desired: &desired.Annotations, ExtraAction: nil}, + {Existing: &existing.Data, Desired: &desired.Data, ExtraAction: nil}, + } + } + + return r.reconcileCM(req, fieldsToCompare) +} + +func (r *ArgoCDReconciler) reconcileCM(req workloads.ConfigMapRequest, compare argocdcommon.FieldCompFnCm) error { + desired, err := workloads.RequestConfigMap(req) + if err != nil { + r.Logger.Debug("reconcileCM: one or more mutations could not be applied") + return errors.Wrapf(err, "reconcileCM: failed to request configMap %s in namespace %s", desired.Name, desired.Namespace) + } + + if err = controllerutil.SetControllerReference(r.Instance, desired, r.Scheme); err != nil { + r.Logger.Error(err, "reconcileCM: failed to set owner reference for configMap", "name", desired.Name, "namespace", desired.Namespace) + } + + existing, err := workloads.GetConfigMap(desired.Name, desired.Namespace, r.Client) + if err != nil { + if !apierrors.IsNotFound(err) { + return errors.Wrapf(err, "reconcileCM: failed to retrieve configMap %s in namespace %s", desired.Name, desired.Namespace) + } + + if err = workloads.CreateConfigMap(desired, r.Client); err != nil { + return errors.Wrapf(err, "reconcileCM: failed to create configMap %s in namespace %s", desired.Name, desired.Namespace) + } + r.Logger.Info("config map created", "name", desired.Name, "namespace", desired.Namespace) + return nil + } + changed := false + + argocdcommon.UpdateIfChanged(compare(existing, desired), &changed) + + if !changed { + return nil + } + + if err = workloads.UpdateConfigMap(existing, r.Client); err != nil { + return errors.Wrapf(err, "reconcileCM: failed to update configmap %s", existing.Name) + } + + r.Logger.Info("configmap updated", "name", existing.Name, "namespace", existing.Namespace) + return nil +} + +func (r *ArgoCDReconciler) deleteConfigMap(name, namespace string) error { + if err := workloads.DeleteConfigMap(name, namespace, r.Client); err != nil { + if apierrors.IsNotFound(err) { + return nil + } + return errors.Wrapf(err, "deleteConfigMap: failed to delete config map %s", name) + } + r.Logger.Info("config map deleted", "name", name, "namespace", namespace) + return nil +} + +func (r *ArgoCDReconciler) cmVarSetter() { + caResourceName = argoutil.GenerateResourceName(r.Instance.Name, common.ArgoCDCASuffix) +} diff --git a/controllers/argocd/configmaps_test.go b/controllers/argocd/configmaps_test.go new file mode 100644 index 000000000..915ec6544 --- /dev/null +++ b/controllers/argocd/configmaps_test.go @@ -0,0 +1,925 @@ +package argocd + +import ( + "testing" + + argoproj "github.com/argoproj-labs/argocd-operator/api/v1beta1" + "github.com/argoproj-labs/argocd-operator/controllers/argocd/argocdcommon" + "github.com/argoproj-labs/argocd-operator/pkg/resource" + "github.com/argoproj-labs/argocd-operator/pkg/util" + "github.com/argoproj-labs/argocd-operator/pkg/workloads" + "github.com/argoproj-labs/argocd-operator/tests/test" + "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +func Test_reconcileConfigMaps(t *testing.T) { + testArgoCD := test.MakeTestArgoCD(nil) + reconciler := makeTestArgoCDReconciler( + testArgoCD, + test.MakeTestSecret( + nil, + func(s *corev1.Secret) { + s.Name = "test-argocd-ca" + s.Data = map[string][]byte{ + "tls.crt": []byte(test.TestVal), + } + }, + ), + ) + + expectedResources := []client.Object{ + test.MakeTestConfigMap( + nil, + func(cm *corev1.ConfigMap) { + cm.Name = "argocd-cm" + }, + ), + test.MakeTestConfigMap( + nil, + func(cm *corev1.ConfigMap) { + cm.Name = "test-argocd-ca" + }, + ), + test.MakeTestConfigMap( + nil, + func(cm *corev1.ConfigMap) { + cm.Name = "argocd-gpg-keys-cm" + }, + ), + test.MakeTestConfigMap( + nil, + func(cm *corev1.ConfigMap) { + cm.Name = "argocd-tls-certs-cm" + }, + ), + test.MakeTestConfigMap( + nil, + func(cm *corev1.ConfigMap) { + cm.Name = "argocd-ssh-known-hosts-cm" + }, + ), + test.MakeTestConfigMap( + nil, + func(cm *corev1.ConfigMap) { + cm.Name = "argocd-rbac-cm" + }, + ), + } + + err := reconciler.reconcileConfigMaps() + assert.NoError(t, err) + + for _, obj := range expectedResources { + _, err := resource.GetObject(obj.GetName(), test.TestNamespace, obj, reconciler.Client) + assert.NoError(t, err) + } +} + +func Test_deleteConfigMaps(t *testing.T) { + testArgoCD := test.MakeTestArgoCD(nil) + + resources := []client.Object{ + test.MakeTestConfigMap( + nil, + func(cm *corev1.ConfigMap) { + cm.Name = "argocd-cm" + }, + ), + test.MakeTestConfigMap( + nil, + func(cm *corev1.ConfigMap) { + cm.Name = "test-argocd-ca" + }, + ), + test.MakeTestConfigMap( + nil, + func(cm *corev1.ConfigMap) { + cm.Name = "argocd-gpg-keys-cm" + }, + ), + test.MakeTestConfigMap( + nil, + func(cm *corev1.ConfigMap) { + cm.Name = "argocd-tls-certs-cm" + }, + ), + test.MakeTestConfigMap( + nil, + func(cm *corev1.ConfigMap) { + cm.Name = "argocd-ssh-known-hosts-cm" + }, + ), + test.MakeTestConfigMap( + nil, + func(cm *corev1.ConfigMap) { + cm.Name = "argocd-rbac-cm" + }, + ), + } + + reconciler := makeTestArgoCDReconciler( + testArgoCD, + resources..., + ) + + reconciler.cmVarSetter() + + err := reconciler.deleteConfigMaps() + assert.NoError(t, err) + + for _, obj := range resources { + _, err := resource.GetObject(obj.GetName(), test.TestNamespace, obj, reconciler.Client) + assert.True(t, apierrors.IsNotFound(err)) + } + +} + +func Test_reconcileArgoCDCm(t *testing.T) { + tests := []struct { + name string + reconciler *ArgoCDReconciler + expectedCm *corev1.ConfigMap + }{ + { + name: "default argocd-cm", + reconciler: makeTestArgoCDReconciler( + test.MakeTestArgoCD(nil), + ), + expectedCm: getTestArgoCDCm(), + }, + { + name: "modified argocd-cm", + reconciler: makeTestArgoCDReconciler( + test.MakeTestArgoCD(nil, + func(cr *argoproj.ArgoCD) { + cr.Spec.ResourceInclusions = "test-resource-inclusions" + cr.Spec.ResourceExclusions = "test-resource-exclusions" + cr.Spec.ResourceTrackingMethod = "annotation" + }, + ), + ), + expectedCm: test.MakeTestConfigMap( + getTestArgoCDCm(), + func(cm *corev1.ConfigMap) { + cm.Data["resource.inclusions"] = "test-resource-inclusions" + cm.Data["resource.exclusions"] = "test-resource-exclusions" + cm.Data["application.resourceTrackingMethod"] = "annotation" + }, + ), + }, + { + name: "drifted argocd-cm", + reconciler: makeTestArgoCDReconciler( + test.MakeTestArgoCD(nil, + func(cr *argoproj.ArgoCD) { + cr.Spec.ResourceInclusions = "test-resource-inclusions" + cr.Spec.ResourceExclusions = "test-resource-exclusions" + cr.Spec.ResourceTrackingMethod = "annotation" + }, + ), + test.MakeTestConfigMap( + getTestArgoCDCm(), + func(cm *corev1.ConfigMap) { + cm.Data["resource.inclusions"] = "random-info" + cm.Data["resource.exclusions"] = "random-info" + cm.Data["application.resourceTrackingMethod"] = "random" + }, + ), + ), + expectedCm: test.MakeTestConfigMap( + getTestArgoCDCm(), + func(cm *corev1.ConfigMap) { + cm.Data["resource.inclusions"] = "test-resource-inclusions" + cm.Data["resource.exclusions"] = "test-resource-exclusions" + cm.Data["application.resourceTrackingMethod"] = "annotation" + }, + ), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + + err := tt.reconciler.reeconcileArgoCDCm() + assert.NoError(t, err) + + existing, err := workloads.GetConfigMap("argocd-cm", test.TestNamespace, tt.reconciler.Client) + assert.NoError(t, err) + + if tt.expectedCm != nil { + match := true + + // Check for partial match on relevant fields + ftc := []argocdcommon.FieldToCompare{ + { + Existing: existing.Labels, + Desired: tt.expectedCm.Labels, + }, + { + Existing: existing.Annotations, + Desired: tt.expectedCm.Annotations, + }, + { + Existing: existing.Data, + Desired: tt.expectedCm.Data, + }, + } + argocdcommon.PartialMatch(ftc, &match) + assert.True(t, match) + } + + }) + } +} + +func Test_reconcileCaCm(t *testing.T) { + tests := []struct { + name string + reconciler *ArgoCDReconciler + expectedCm *corev1.ConfigMap + expectedError bool + }{ + { + name: "no ca secret found", + reconciler: makeTestArgoCDReconciler( + test.MakeTestArgoCD(nil), + ), + expectedCm: nil, + expectedError: true, + }, + { + name: "ca secret found", + reconciler: makeTestArgoCDReconciler( + test.MakeTestArgoCD(nil), + test.MakeTestSecret( + nil, + func(s *corev1.Secret) { + s.Name = "test-argocd-ca" + s.Data = map[string][]byte{ + "tls.crt": []byte(test.TestVal), + } + }, + ), + ), + expectedCm: test.MakeTestConfigMap( + getTestCaCm(), + func(cm *corev1.ConfigMap) { + cm.Data["tls.crt"] = "test-val" + }, + ), + expectedError: false, + }, + { + name: "ca config map drift", + reconciler: makeTestArgoCDReconciler( + test.MakeTestArgoCD(nil), + test.MakeTestSecret( + nil, + func(s *corev1.Secret) { + s.Name = "test-argocd-ca" + s.Data = map[string][]byte{ + "tls.crt": []byte(test.TestVal), + } + }, + ), + test.MakeTestConfigMap( + nil, + func(cm *corev1.ConfigMap) { + cm.Name = "test-argocd-ca" + cm.Data = map[string]string{ + "tls.crt": "random-val", + } + }, + ), + ), + expectedCm: test.MakeTestConfigMap( + getTestCaCm(), + func(cm *corev1.ConfigMap) { + cm.Data["tls.crt"] = "test-val" + }, + ), + expectedError: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt.reconciler.cmVarSetter() + + err := tt.reconciler.reconcileCACm() + if tt.expectedError { + assert.Error(t, err, "Expected an error but got none.") + } else { + assert.NoError(t, err, "Expected no error but got one.") + } + + existing, err := workloads.GetConfigMap("test-argocd-ca", test.TestNamespace, tt.reconciler.Client) + + if tt.expectedError { + assert.Error(t, err, "Expected an error but got none.") + } else { + assert.NoError(t, err, "Expected no error but got one.") + } + + if tt.expectedCm != nil { + match := true + + // Check for partial match on relevant fields + ftc := []argocdcommon.FieldToCompare{ + { + Existing: existing.Labels, + Desired: tt.expectedCm.Labels, + }, + { + Existing: existing.Annotations, + Desired: tt.expectedCm.Annotations, + }, + { + Existing: existing.Data, + Desired: tt.expectedCm.Data, + }, + } + argocdcommon.PartialMatch(ftc, &match) + assert.True(t, match) + } + + }) + } +} + +func Test_reconcileGPGKeysCm(t *testing.T) { + tests := []struct { + name string + reconciler *ArgoCDReconciler + expectedCm *corev1.ConfigMap + }{ + { + name: "default argocd-gpg-keys cm", + reconciler: makeTestArgoCDReconciler( + test.MakeTestArgoCD(nil), + ), + expectedCm: getTestGPGKeysCm(), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + + err := tt.reconciler.reconcileGPGKeysCm() + assert.NoError(t, err) + + existing, err := workloads.GetConfigMap("argocd-gpg-keys-cm", test.TestNamespace, tt.reconciler.Client) + assert.NoError(t, err) + + if tt.expectedCm != nil { + match := true + + // Check for partial match on relevant fields + ftc := []argocdcommon.FieldToCompare{ + { + Existing: existing.Labels, + Desired: tt.expectedCm.Labels, + }, + { + Existing: existing.Annotations, + Desired: tt.expectedCm.Annotations, + }, + { + Existing: existing.Data, + Desired: tt.expectedCm.Data, + }, + } + argocdcommon.PartialMatch(ftc, &match) + assert.True(t, match) + } + + }) + } +} + +func Test_reconcileTLSCertsCm(t *testing.T) { + tests := []struct { + name string + reconciler *ArgoCDReconciler + expectedCm *corev1.ConfigMap + }{ + { + name: "default argocd-tls-certs cm", + reconciler: makeTestArgoCDReconciler( + test.MakeTestArgoCD(nil), + ), + expectedCm: test.MakeTestConfigMap( + getTestTLSCertsCm(), + func(cm *corev1.ConfigMap) { + cm.Data = nil + }, + ), + }, + { + name: "modified argocd-tls-certs cm", + reconciler: makeTestArgoCDReconciler( + test.MakeTestArgoCD(nil, + func(cr *argoproj.ArgoCD) { + cr.Spec.TLS.InitialCerts = test.TestKVP + }, + ), + ), + expectedCm: test.MakeTestConfigMap(getTestTLSCertsCm(), + func(cm *corev1.ConfigMap) { + cm.Data = test.TestKVP + }, + ), + }, + { + name: "drifted argocd-tls-certs cm", + reconciler: makeTestArgoCDReconciler( + test.MakeTestArgoCD(nil, + func(cr *argoproj.ArgoCD) { + cr.Spec.TLS.InitialCerts = test.TestKVP + }, + ), + test.MakeTestConfigMap(getTestTLSCertsCm(), + func(cm *corev1.ConfigMap) { + cm.Data = map[string]string{ + "test-key": "random-info", + } + }, + ), + ), + expectedCm: test.MakeTestConfigMap(getTestTLSCertsCm(), + func(cm *corev1.ConfigMap) { + cm.Data = test.TestKVP + }, + ), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + + err := tt.reconciler.reconcileTLSCertsCm() + assert.NoError(t, err) + + existing, err := workloads.GetConfigMap("argocd-tls-certs-cm", test.TestNamespace, tt.reconciler.Client) + assert.NoError(t, err) + + if tt.expectedCm != nil { + match := true + + // Check for partial match on relevant fields + ftc := []argocdcommon.FieldToCompare{ + { + Existing: existing.Labels, + Desired: tt.expectedCm.Labels, + }, + { + Existing: existing.Annotations, + Desired: tt.expectedCm.Annotations, + }, + { + Existing: existing.Data, + Desired: tt.expectedCm.Data, + }, + } + argocdcommon.PartialMatch(ftc, &match) + assert.True(t, match) + } + + }) + } +} + +func Test_reconcileSSHKnownHostsCm(t *testing.T) { + tests := []struct { + name string + reconciler *ArgoCDReconciler + expectedCm *corev1.ConfigMap + }{ + { + name: "default ssh-known-hosts cm", + reconciler: makeTestArgoCDReconciler( + test.MakeTestArgoCD(nil), + ), + expectedCm: getTestSSHKnownHostsCm(), + }, + { + name: "modified ssh-known-hosts cm", + reconciler: makeTestArgoCDReconciler( + test.MakeTestArgoCD(nil, + func(cr *argoproj.ArgoCD) { + cr.Spec.InitialSSHKnownHosts.Keys = test.TestKey + }, + ), + ), + expectedCm: test.MakeTestConfigMap(getTestSSHKnownHostsCm(), + func(cm *corev1.ConfigMap) { + cm.Data["ssh_known_hosts"] = `[ssh.github.com]:443 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg= +[ssh.github.com]:443 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl +[ssh.github.com]:443 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk= +bitbucket.org ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPIQmuzMBuKdWeF4+a2sjSSpBK0iqitSQ+5BM9KhpexuGt20JpTVM7u5BDZngncgrqDMbWdxMWWOGtZ9UgbqgZE= +bitbucket.org ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIazEu89wgQZ4bqs3d63QSMzYVa0MuJ2e2gKTKqu+UUO +bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw== +github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg= +github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl +github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk= +gitlab.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY= +gitlab.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf +gitlab.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsj2bNKTBSpIYDEGk9KxsGh3mySTRgMtXL583qmBpzeQ+jqCMRgBqB98u3z++J1sKlXHWfM9dyhSevkMwSbhoR8XIq/U0tCNyokEi/ueaBMCvbcTHhO7FcwzY92WK4Yt0aGROY5qX2UKSeOvuP4D6TPqKF1onrSzH9bx9XUf2lEdWT/ia1NEKjunUqu1xOB/StKDHMoX4/OKyIzuS0q/T1zOATthvasJFoPrAjkohTyaDUz2LN5JoH839hViyEG82yB+MjcFV5MU3N1l1QL3cVUCh93xSaua1N85qivl+siMkPGbO5xR/En4iEY6K2XPASUEMaieWVNTRCtJ4S8H+9 +ssh.dev.azure.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H +vs-ssh.visualstudio.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H +test-key` + }, + ), + }, + { + name: "drifted ssh-known-hosts cm", + reconciler: makeTestArgoCDReconciler( + test.MakeTestArgoCD(nil, + func(cr *argoproj.ArgoCD) { + cr.Spec.InitialSSHKnownHosts.Keys = test.TestKey + }, + ), + test.MakeTestConfigMap( + getTestSSHKnownHostsCm(), + func(cm *corev1.ConfigMap) { + cm.Data["ssh_known_hosts"] = `[ssh.github.com]:443 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg= +[ssh.github.com]:443 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl +[ssh.github.com]:443 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk= +bitbucket.org ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPIQmuzMBuKdWeF4+a2sjSSpBK0iqitSQ+5BM9KhpexuGt20JpTVM7u5BDZngncgrqDMbWdxMWWOGtZ9UgbqgZE= +bitbucket.org ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIazEu89wgQZ4bqs3d63QSMzYVa0MuJ2e2gKTKqu+UUO +bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw== +github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg= +github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl +github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk= +gitlab.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY= +gitlab.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf +gitlab.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsj2bNKTBSpIYDEGk9KxsGh3mySTRgMtXL583qmBpzeQ+jqCMRgBqB98u3z++J1sKlXHWfM9dyhSevkMwSbhoR8XIq/U0tCNyokEi/ueaBMCvbcTHhO7FcwzY92WK4Yt0aGROY5qX2UKSeOvuP4D6TPqKF1onrSzH9bx9XUf2lEdWT/ia1NEKjunUqu1xOB/StKDHMoX4/OKyIzuS0q/T1zOATthvasJFoPrAjkohTyaDUz2LN5JoH839hViyEG82yB+MjcFV5MU3N1l1QL3cVUCh93xSaua1N85qivl+siMkPGbO5xR/En4iEY6K2XPASUEMaieWVNTRCtJ4S8H+9 +ssh.dev.azure.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H +vs-ssh.visualstudio.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H +test-keyssss` + }, + ), + ), + expectedCm: test.MakeTestConfigMap(getTestSSHKnownHostsCm(), + func(cm *corev1.ConfigMap) { + cm.Data["ssh_known_hosts"] = `[ssh.github.com]:443 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg= +[ssh.github.com]:443 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl +[ssh.github.com]:443 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk= +bitbucket.org ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPIQmuzMBuKdWeF4+a2sjSSpBK0iqitSQ+5BM9KhpexuGt20JpTVM7u5BDZngncgrqDMbWdxMWWOGtZ9UgbqgZE= +bitbucket.org ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIazEu89wgQZ4bqs3d63QSMzYVa0MuJ2e2gKTKqu+UUO +bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw== +github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg= +github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl +github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk= +gitlab.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY= +gitlab.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf +gitlab.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsj2bNKTBSpIYDEGk9KxsGh3mySTRgMtXL583qmBpzeQ+jqCMRgBqB98u3z++J1sKlXHWfM9dyhSevkMwSbhoR8XIq/U0tCNyokEi/ueaBMCvbcTHhO7FcwzY92WK4Yt0aGROY5qX2UKSeOvuP4D6TPqKF1onrSzH9bx9XUf2lEdWT/ia1NEKjunUqu1xOB/StKDHMoX4/OKyIzuS0q/T1zOATthvasJFoPrAjkohTyaDUz2LN5JoH839hViyEG82yB+MjcFV5MU3N1l1QL3cVUCh93xSaua1N85qivl+siMkPGbO5xR/En4iEY6K2XPASUEMaieWVNTRCtJ4S8H+9 +ssh.dev.azure.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H +vs-ssh.visualstudio.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H +test-key` + }, + ), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + + err := tt.reconciler.reconcileSSHKnownHostsCm() + assert.NoError(t, err) + + existing, err := workloads.GetConfigMap("argocd-ssh-known-hosts-cm", test.TestNamespace, tt.reconciler.Client) + assert.NoError(t, err) + + if tt.expectedCm != nil { + match := true + + // Check for partial match on relevant fields + ftc := []argocdcommon.FieldToCompare{ + { + Existing: existing.Labels, + Desired: tt.expectedCm.Labels, + }, + { + Existing: existing.Annotations, + Desired: tt.expectedCm.Annotations, + }, + { + Existing: existing.Data, + Desired: tt.expectedCm.Data, + }, + } + argocdcommon.PartialMatch(ftc, &match) + assert.True(t, match) + } + + }) + } +} + +func Test_reconcileRBACCm(t *testing.T) { + tests := []struct { + name string + reconciler *ArgoCDReconciler + expectedCm *corev1.ConfigMap + }{ + { + name: "default rbac cm", + reconciler: makeTestArgoCDReconciler( + test.MakeTestArgoCD(nil), + ), + expectedCm: getTestRbacCm(), + }, + { + name: "modified rbac cm", + reconciler: makeTestArgoCDReconciler( + test.MakeTestArgoCD(nil, + func(cr *argoproj.ArgoCD) { + cr.Spec.RBAC.Policy = util.StringPtr("p, subj, resource, action") + }, + ), + ), + expectedCm: test.MakeTestConfigMap(getTestRbacCm(), + func(cm *corev1.ConfigMap) { + cm.Data = map[string]string{ + "policy.csv": "p, subj, resource, action", + "policy.default": "", + "scopes": "[groups]", + "policy.matchMode": "", + } + }, + ), + }, + { + name: "drifted rbac cm", + reconciler: makeTestArgoCDReconciler( + test.MakeTestArgoCD(nil, + func(cr *argoproj.ArgoCD) { + cr.Spec.RBAC.Policy = util.StringPtr("p, subj, resource, action") + }, + ), + test.MakeTestConfigMap( + getTestRbacCm(), + func(cm *corev1.ConfigMap) { + cm.Data = map[string]string{ + "policy.csv": "p, subj, resource 1, resource 2, action", + "policy.default": "", + "scopes": "[groups]", + "policy.matchMode": "", + } + }, + ), + ), + expectedCm: test.MakeTestConfigMap(getTestRbacCm(), + func(cm *corev1.ConfigMap) { + cm.Data = map[string]string{ + "policy.csv": "p, subj, resource, action", + "policy.default": "", + "scopes": "[groups]", + "policy.matchMode": "", + } + }, + ), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + + err := tt.reconciler.reconcileRBACCm() + assert.NoError(t, err) + + existing, err := workloads.GetConfigMap("argocd-rbac-cm", test.TestNamespace, tt.reconciler.Client) + assert.NoError(t, err) + + if tt.expectedCm != nil { + match := true + + // Check for partial match on relevant fields + ftc := []argocdcommon.FieldToCompare{ + { + Existing: existing.Labels, + Desired: tt.expectedCm.Labels, + }, + { + Existing: existing.Annotations, + Desired: tt.expectedCm.Annotations, + }, + { + Existing: existing.Data, + Desired: tt.expectedCm.Data, + }, + } + argocdcommon.PartialMatch(ftc, &match) + assert.True(t, match) + } + + }) + } +} + +func TestDeleteConfigMap(t *testing.T) { + tests := []struct { + name string + reconciler *ArgoCDReconciler + configMapExist bool + expectedError bool + }{ + { + name: "ConfigMap exists", + reconciler: makeTestArgoCDReconciler( + test.MakeTestArgoCD(nil), + test.MakeTestConfigMap(nil), + ), + configMapExist: true, + expectedError: false, + }, + { + name: "ConfigMap does not exist", + reconciler: makeTestArgoCDReconciler( + test.MakeTestArgoCD(nil), + ), + configMapExist: false, + expectedError: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + + err := tt.reconciler.deleteConfigMap(test.TestName, test.TestNamespace) + + if tt.configMapExist { + _, err := workloads.GetConfigMap(test.TestName, test.TestNamespace, tt.reconciler.Client) + assert.True(t, apierrors.IsNotFound(err)) + } + + if tt.expectedError { + assert.Error(t, err, "Expected an error but got none.") + } else { + assert.NoError(t, err, "Expected no error but got one.") + } + }) + } +} + +func getTestArgoCDCm() *corev1.ConfigMap { + return &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "argocd-cm", + Namespace: "test-ns", + Labels: map[string]string{ + "app.kubernetes.io/name": "argocd-cm", + "app.kubernetes.io/part-of": "argocd", + "app.kubernetes.io/instance": "test-argocd", + "app.kubernetes.io/managed-by": "argocd-operator", + }, + Annotations: map[string]string{ + "argocds.argoproj.io/name": "test-argocd", + "argocds.argoproj.io/namespace": "test-ns", + }, + }, + Data: map[string]string{ + "application.instanceLabelKey": "app.kubernetes.io/instance", + "admin.enabled": "true", + "ga.trackingid": "", + "ga.anonymizeusers": "false", + "configManagementPlugins": "", + "help.chatUrl": "", + "help.chatText": "", + "kustomize.buildOptions": "", + "oidc.config": "", + "resource.exclusions": "", + "resource.inclusions": "", + "application.resourceTrackingMethod": "label", + "repositories": "", + "repository.credentials": "", + "statusbadge.enabled": "false", + "users.anonymous.enabled": "false", + }, + } +} + +func getTestCaCm() *corev1.ConfigMap { + return &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-argocd-ca", + Namespace: "test-ns", + Labels: map[string]string{ + "app.kubernetes.io/name": "test-argocd-ca", + "app.kubernetes.io/part-of": "argocd", + "app.kubernetes.io/instance": "test-argocd", + "app.kubernetes.io/managed-by": "argocd-operator", + }, + Annotations: map[string]string{ + "argocds.argoproj.io/name": "test-argocd", + "argocds.argoproj.io/namespace": "test-ns", + }, + }, + Data: make(map[string]string), + } +} + +func getTestGPGKeysCm() *corev1.ConfigMap { + return &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "argocd-gpg-keys-cm", + Namespace: "test-ns", + Labels: map[string]string{ + "app.kubernetes.io/name": "argocd-gpg-keys-cm", + "app.kubernetes.io/part-of": "argocd", + "app.kubernetes.io/instance": "test-argocd", + "app.kubernetes.io/managed-by": "argocd-operator", + }, + Annotations: map[string]string{ + "argocds.argoproj.io/name": "test-argocd", + "argocds.argoproj.io/namespace": "test-ns", + }, + }, + } +} + +func getTestTLSCertsCm() *corev1.ConfigMap { + return &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "argocd-tls-certs-cm", + Namespace: "test-ns", + Labels: map[string]string{ + "app.kubernetes.io/name": "argocd-tls-certs-cm", + "app.kubernetes.io/part-of": "argocd", + "app.kubernetes.io/instance": "test-argocd", + "app.kubernetes.io/managed-by": "argocd-operator", + }, + Annotations: map[string]string{ + "argocds.argoproj.io/name": "test-argocd", + "argocds.argoproj.io/namespace": "test-ns", + }, + }, + Data: make(map[string]string), + } +} + +func getTestSSHKnownHostsCm() *corev1.ConfigMap { + return &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "argocd-ssh-known-hosts-cm", + Namespace: "test-ns", + Labels: map[string]string{ + "app.kubernetes.io/name": "argocd-ssh-known-hosts-cm", + "app.kubernetes.io/part-of": "argocd", + "app.kubernetes.io/instance": "test-argocd", + "app.kubernetes.io/managed-by": "argocd-operator", + }, + Annotations: map[string]string{ + "argocds.argoproj.io/name": "test-argocd", + "argocds.argoproj.io/namespace": "test-ns", + }, + }, + Data: map[string]string{ + "ssh_known_hosts": `[ssh.github.com]:443 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg= +[ssh.github.com]:443 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl +[ssh.github.com]:443 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk= +bitbucket.org ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPIQmuzMBuKdWeF4+a2sjSSpBK0iqitSQ+5BM9KhpexuGt20JpTVM7u5BDZngncgrqDMbWdxMWWOGtZ9UgbqgZE= +bitbucket.org ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIazEu89wgQZ4bqs3d63QSMzYVa0MuJ2e2gKTKqu+UUO +bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw== +github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg= +github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl +github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk= +gitlab.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY= +gitlab.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf +gitlab.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsj2bNKTBSpIYDEGk9KxsGh3mySTRgMtXL583qmBpzeQ+jqCMRgBqB98u3z++J1sKlXHWfM9dyhSevkMwSbhoR8XIq/U0tCNyokEi/ueaBMCvbcTHhO7FcwzY92WK4Yt0aGROY5qX2UKSeOvuP4D6TPqKF1onrSzH9bx9XUf2lEdWT/ia1NEKjunUqu1xOB/StKDHMoX4/OKyIzuS0q/T1zOATthvasJFoPrAjkohTyaDUz2LN5JoH839hViyEG82yB+MjcFV5MU3N1l1QL3cVUCh93xSaua1N85qivl+siMkPGbO5xR/En4iEY6K2XPASUEMaieWVNTRCtJ4S8H+9 +ssh.dev.azure.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H +vs-ssh.visualstudio.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H +`, + }, + } +} + +func getTestRbacCm() *corev1.ConfigMap { + return &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "argocd-rbac-cm", + Namespace: "test-ns", + Labels: map[string]string{ + "app.kubernetes.io/name": "argocd-rbac-cm", + "app.kubernetes.io/part-of": "argocd", + "app.kubernetes.io/instance": "test-argocd", + "app.kubernetes.io/managed-by": "argocd-operator", + }, + Annotations: map[string]string{ + "argocds.argoproj.io/name": "test-argocd", + "argocds.argoproj.io/namespace": "test-ns", + }, + }, + Data: map[string]string{ + "policy.csv": "", + "policy.default": "", + "scopes": "[groups]", + "policy.matchMode": "", + }, + } +} diff --git a/controllers/argocd/instance.go b/controllers/argocd/instance.go index 07a98155f..94315bdbb 100644 --- a/controllers/argocd/instance.go +++ b/controllers/argocd/instance.go @@ -29,6 +29,7 @@ func (r *ArgoCDReconciler) getCAConfigMapName() string { return argocdcommon.GetValueOrDefault(r.Instance.Spec.TLS.CA.ConfigMapName, argoutil.GenerateResourceName(r.Instance.Name, common.ArgoCDCASuffix)).(string) } +// TO DO: move to appset component // getSCMRootCAConfigMapName returns the SCMRootCA ConfigMap name for the given ArgoCD ApplicationSet Controller. func (r *ArgoCDReconciler) getSCMRootCAConfigMapName() string { return argocdcommon.GetValueOrDefault(r.Instance.Spec.ApplicationSet.SCMRootCAConfigMap, "").(string) @@ -71,7 +72,7 @@ func (r *ArgoCDReconciler) getRBACPolicy() string { // getRBACPolicyMatcherMode will return the RBAC policy matcher mode for the given ArgoCD instance. func (r *ArgoCDReconciler) getRBACPolicyMatcherMode() string { - return argocdcommon.GetValueOrDefault(r.Instance.Spec.RBAC.PolicyMatcherMode, nil).(string) + return argocdcommon.GetValueOrDefault(r.Instance.Spec.RBAC.PolicyMatcherMode, "").(string) } // getRBACDefaultPolicy will return the RBAC default policy for the given ArgoCD instance.