github.com/argoproj-labs/argocd-operator@v0.10.0/controllers/argocd/configmap.go (about)

     1  // Copyright 2019 ArgoCD Operator Developers
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  // 	http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package argocd
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"reflect"
    21  
    22  	"gopkg.in/yaml.v2"
    23  	corev1 "k8s.io/api/core/v1"
    24  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    25  	"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
    26  
    27  	argoproj "github.com/argoproj-labs/argocd-operator/api/v1beta1"
    28  	"github.com/argoproj-labs/argocd-operator/common"
    29  	"github.com/argoproj-labs/argocd-operator/controllers/argoutil"
    30  )
    31  
    32  // createRBACConfigMap will create the Argo CD RBAC ConfigMap resource.
    33  func (r *ReconcileArgoCD) createRBACConfigMap(cm *corev1.ConfigMap, cr *argoproj.ArgoCD) error {
    34  	data := make(map[string]string)
    35  	data[common.ArgoCDKeyRBACPolicyCSV] = getRBACPolicy(cr)
    36  	data[common.ArgoCDKeyRBACPolicyDefault] = getRBACDefaultPolicy(cr)
    37  	data[common.ArgoCDKeyRBACScopes] = getRBACScopes(cr)
    38  	cm.Data = data
    39  
    40  	if err := controllerutil.SetControllerReference(cr, cm, r.Scheme); err != nil {
    41  		return err
    42  	}
    43  	return r.Client.Create(context.TODO(), cm)
    44  }
    45  
    46  // getApplicationInstanceLabelKey will return the application instance label key  for the given ArgoCD.
    47  func getApplicationInstanceLabelKey(cr *argoproj.ArgoCD) string {
    48  	key := common.ArgoCDDefaultApplicationInstanceLabelKey
    49  	if len(cr.Spec.ApplicationInstanceLabelKey) > 0 {
    50  		key = cr.Spec.ApplicationInstanceLabelKey
    51  	}
    52  	return key
    53  }
    54  
    55  // getCAConfigMapName will return the CA ConfigMap name for the given ArgoCD.
    56  func getCAConfigMapName(cr *argoproj.ArgoCD) string {
    57  	if len(cr.Spec.TLS.CA.ConfigMapName) > 0 {
    58  		return cr.Spec.TLS.CA.ConfigMapName
    59  	}
    60  	return nameWithSuffix(common.ArgoCDCASuffix, cr)
    61  }
    62  
    63  // getSCMRootCAConfigMapName will return the SCMRootCA ConfigMap name for the given ArgoCD ApplicationSet Controller.
    64  func getSCMRootCAConfigMapName(cr *argoproj.ArgoCD) string {
    65  	if cr.Spec.ApplicationSet.SCMRootCAConfigMap != "" && len(cr.Spec.ApplicationSet.SCMRootCAConfigMap) > 0 {
    66  		return cr.Spec.ApplicationSet.SCMRootCAConfigMap
    67  	}
    68  	return ""
    69  }
    70  
    71  // getConfigManagementPlugins will return the config management plugins for the given ArgoCD.
    72  func getConfigManagementPlugins(cr *argoproj.ArgoCD) string {
    73  	plugins := common.ArgoCDDefaultConfigManagementPlugins
    74  	if len(cr.Spec.ConfigManagementPlugins) > 0 {
    75  		plugins = cr.Spec.ConfigManagementPlugins
    76  	}
    77  	return plugins
    78  }
    79  
    80  // getGATrackingID will return the google analytics tracking ID for the given Argo CD.
    81  func getGATrackingID(cr *argoproj.ArgoCD) string {
    82  	id := common.ArgoCDDefaultGATrackingID
    83  	if len(cr.Spec.GATrackingID) > 0 {
    84  		id = cr.Spec.GATrackingID
    85  	}
    86  	return id
    87  }
    88  
    89  // getHelpChatURL will return the help chat URL for the given Argo CD.
    90  func getHelpChatURL(cr *argoproj.ArgoCD) string {
    91  	url := common.ArgoCDDefaultHelpChatURL
    92  	if len(cr.Spec.HelpChatURL) > 0 {
    93  		url = cr.Spec.HelpChatURL
    94  	}
    95  	return url
    96  }
    97  
    98  // getHelpChatText will return the help chat text for the given Argo CD.
    99  func getHelpChatText(cr *argoproj.ArgoCD) string {
   100  	text := common.ArgoCDDefaultHelpChatText
   101  	if len(cr.Spec.HelpChatText) > 0 {
   102  		text = cr.Spec.HelpChatText
   103  	}
   104  	return text
   105  }
   106  
   107  // getKustomizeBuildOptions will return the kuztomize build options for the given ArgoCD.
   108  func getKustomizeBuildOptions(cr *argoproj.ArgoCD) string {
   109  	kbo := common.ArgoCDDefaultKustomizeBuildOptions
   110  	if len(cr.Spec.KustomizeBuildOptions) > 0 {
   111  		kbo = cr.Spec.KustomizeBuildOptions
   112  	}
   113  	return kbo
   114  }
   115  
   116  // getOIDCConfig will return the OIDC configuration for the given ArgoCD.
   117  func getOIDCConfig(cr *argoproj.ArgoCD) string {
   118  	config := common.ArgoCDDefaultOIDCConfig
   119  	if len(cr.Spec.OIDCConfig) > 0 {
   120  		config = cr.Spec.OIDCConfig
   121  	}
   122  	return config
   123  }
   124  
   125  // getRBACPolicy will return the RBAC policy for the given ArgoCD.
   126  func getRBACPolicy(cr *argoproj.ArgoCD) string {
   127  	policy := common.ArgoCDDefaultRBACPolicy
   128  	if cr.Spec.RBAC.Policy != nil {
   129  		policy = *cr.Spec.RBAC.Policy
   130  	}
   131  	return policy
   132  }
   133  
   134  // getRBACDefaultPolicy will retun the RBAC default policy for the given ArgoCD.
   135  func getRBACDefaultPolicy(cr *argoproj.ArgoCD) string {
   136  	dp := common.ArgoCDDefaultRBACDefaultPolicy
   137  	if cr.Spec.RBAC.DefaultPolicy != nil {
   138  		dp = *cr.Spec.RBAC.DefaultPolicy
   139  	}
   140  	return dp
   141  }
   142  
   143  // getRBACScopes will return the RBAC scopes for the given ArgoCD.
   144  func getRBACScopes(cr *argoproj.ArgoCD) string {
   145  	scopes := common.ArgoCDDefaultRBACScopes
   146  	if cr.Spec.RBAC.Scopes != nil {
   147  		scopes = *cr.Spec.RBAC.Scopes
   148  	}
   149  	return scopes
   150  }
   151  
   152  // getResourceHealthChecks loads health customizations to `resource.customizations.health` from argocd-cm ConfigMap
   153  func getResourceHealthChecks(cr *argoproj.ArgoCD) map[string]string {
   154  	healthCheck := make(map[string]string)
   155  	if cr.Spec.ResourceHealthChecks != nil {
   156  		resourceHealthChecks := cr.Spec.ResourceHealthChecks
   157  		for _, healthCustomization := range resourceHealthChecks {
   158  			if healthCustomization.Group != "" {
   159  				healthCustomization.Group += "_"
   160  			}
   161  			subkey := "resource.customizations.health." + healthCustomization.Group + healthCustomization.Kind
   162  			subvalue := healthCustomization.Check
   163  			healthCheck[subkey] = subvalue
   164  		}
   165  	}
   166  	return healthCheck
   167  }
   168  
   169  // getResourceIgnoreDifferences loads ignore differences customizations to `resource.customizations.ignoreDifferences` from argocd-cm ConfigMap
   170  func getResourceIgnoreDifferences(cr *argoproj.ArgoCD) (map[string]string, error) {
   171  	ignoreDiff := make(map[string]string)
   172  	if cr.Spec.ResourceIgnoreDifferences != nil {
   173  		resourceIgnoreDiff := cr.Spec.ResourceIgnoreDifferences
   174  		if !reflect.DeepEqual(resourceIgnoreDiff.All, &argoproj.IgnoreDifferenceCustomization{}) {
   175  			subkey := "resource.customizations.ignoreDifferences.all"
   176  			bytes, err := yaml.Marshal(resourceIgnoreDiff.All)
   177  			if err != nil {
   178  				return ignoreDiff, err
   179  			}
   180  			subvalue := string(bytes)
   181  			ignoreDiff[subkey] = subvalue
   182  		}
   183  		for _, ignoreDiffCustomization := range resourceIgnoreDiff.ResourceIdentifiers {
   184  			if ignoreDiffCustomization.Group != "" {
   185  				ignoreDiffCustomization.Group += "_"
   186  			}
   187  			subkey := "resource.customizations.ignoreDifferences." + ignoreDiffCustomization.Group + ignoreDiffCustomization.Kind
   188  			bytes, err := yaml.Marshal(ignoreDiffCustomization.Customization)
   189  			if err != nil {
   190  				return ignoreDiff, err
   191  			}
   192  			subvalue := string(bytes)
   193  			ignoreDiff[subkey] = subvalue
   194  		}
   195  	}
   196  	return ignoreDiff, nil
   197  }
   198  
   199  // getResourceActions loads custom actions to `resource.customizations.actions` from argocd-cm ConfigMap
   200  func getResourceActions(cr *argoproj.ArgoCD) map[string]string {
   201  	action := make(map[string]string)
   202  	if cr.Spec.ResourceActions != nil {
   203  		resourceAction := cr.Spec.ResourceActions
   204  		for _, actionCustomization := range resourceAction {
   205  			if actionCustomization.Group != "" {
   206  				actionCustomization.Group += "_"
   207  			}
   208  			subkey := "resource.customizations.actions." + actionCustomization.Group + actionCustomization.Kind
   209  			subvalue := actionCustomization.Action
   210  			action[subkey] = subvalue
   211  		}
   212  	}
   213  	return action
   214  }
   215  
   216  // getResourceExclusions will return the resource exclusions for the given ArgoCD.
   217  func getResourceExclusions(cr *argoproj.ArgoCD) string {
   218  	re := common.ArgoCDDefaultResourceExclusions
   219  	if cr.Spec.ResourceExclusions != "" {
   220  		re = cr.Spec.ResourceExclusions
   221  	}
   222  	return re
   223  }
   224  
   225  // getResourceInclusions will return the resource inclusions for the given ArgoCD.
   226  func getResourceInclusions(cr *argoproj.ArgoCD) string {
   227  	re := common.ArgoCDDefaultResourceInclusions
   228  	if cr.Spec.ResourceInclusions != "" {
   229  		re = cr.Spec.ResourceInclusions
   230  	}
   231  	return re
   232  }
   233  
   234  // getResourceTrackingMethod will return the resource tracking method for the given ArgoCD.
   235  func getResourceTrackingMethod(cr *argoproj.ArgoCD) string {
   236  	rtm := argoproj.ParseResourceTrackingMethod(cr.Spec.ResourceTrackingMethod)
   237  	if rtm == argoproj.ResourceTrackingMethodInvalid {
   238  		log.Info(fmt.Sprintf("Found '%s' as resource tracking method, which is invalid. Using default 'label' method.", cr.Spec.ResourceTrackingMethod))
   239  	} else if cr.Spec.ResourceTrackingMethod != "" {
   240  		log.Info(fmt.Sprintf("Found '%s' as tracking method", cr.Spec.ResourceTrackingMethod))
   241  	} else {
   242  		log.Info("Using default resource tracking method 'label'")
   243  	}
   244  	return rtm.String()
   245  }
   246  
   247  // getInitialRepositories will return the initial repositories for the given ArgoCD.
   248  func getInitialRepositories(cr *argoproj.ArgoCD) string {
   249  	repos := common.ArgoCDDefaultRepositories
   250  	if len(cr.Spec.InitialRepositories) > 0 {
   251  		repos = cr.Spec.InitialRepositories
   252  	}
   253  	return repos
   254  }
   255  
   256  // getRepositoryCredentials will return the repository credentials for the given ArgoCD.
   257  func getRepositoryCredentials(cr *argoproj.ArgoCD) string {
   258  	repos := common.ArgoCDDefaultRepositoryCredentials
   259  	if len(cr.Spec.RepositoryCredentials) > 0 {
   260  		repos = cr.Spec.RepositoryCredentials
   261  	}
   262  	return repos
   263  }
   264  
   265  // getSSHKnownHosts will return the SSH Known Hosts data for the given ArgoCD.
   266  func getInitialSSHKnownHosts(cr *argoproj.ArgoCD) string {
   267  	skh := common.ArgoCDDefaultSSHKnownHosts
   268  	if cr.Spec.InitialSSHKnownHosts.ExcludeDefaultHosts {
   269  		skh = ""
   270  	}
   271  	if len(cr.Spec.InitialSSHKnownHosts.Keys) > 0 {
   272  		skh += cr.Spec.InitialSSHKnownHosts.Keys
   273  	}
   274  	return skh
   275  }
   276  
   277  // getTLSCerts will return the TLS certs for the given ArgoCD.
   278  func getInitialTLSCerts(cr *argoproj.ArgoCD) map[string]string {
   279  	certs := make(map[string]string)
   280  	if len(cr.Spec.TLS.InitialCerts) > 0 {
   281  		certs = cr.Spec.TLS.InitialCerts
   282  	}
   283  	return certs
   284  }
   285  
   286  // newConfigMap returns a new ConfigMap instance for the given ArgoCD.
   287  func newConfigMap(cr *argoproj.ArgoCD) *corev1.ConfigMap {
   288  	return &corev1.ConfigMap{
   289  		ObjectMeta: metav1.ObjectMeta{
   290  			Name:      cr.Name,
   291  			Namespace: cr.Namespace,
   292  			Labels:    argoutil.LabelsForCluster(cr),
   293  		},
   294  	}
   295  }
   296  
   297  // newConfigMapWithName creates a new ConfigMap with the given name for the given ArgCD.
   298  func newConfigMapWithName(name string, cr *argoproj.ArgoCD) *corev1.ConfigMap {
   299  	cm := newConfigMap(cr)
   300  	cm.ObjectMeta.Name = name
   301  
   302  	lbls := cm.ObjectMeta.Labels
   303  	lbls[common.ArgoCDKeyName] = name
   304  	cm.ObjectMeta.Labels = lbls
   305  
   306  	return cm
   307  }
   308  
   309  // reconcileConfigMaps will ensure that all ArgoCD ConfigMaps are present.
   310  func (r *ReconcileArgoCD) reconcileConfigMaps(cr *argoproj.ArgoCD, useTLSForRedis bool) error {
   311  	if err := r.reconcileArgoConfigMap(cr); err != nil {
   312  		return err
   313  	}
   314  
   315  	if err := r.reconcileRedisConfiguration(cr, useTLSForRedis); err != nil {
   316  		return err
   317  	}
   318  
   319  	if err := r.reconcileRBAC(cr); err != nil {
   320  		return err
   321  	}
   322  
   323  	if err := r.reconcileSSHKnownHosts(cr); err != nil {
   324  		return err
   325  	}
   326  
   327  	if err := r.reconcileTLSCerts(cr); err != nil {
   328  		return err
   329  	}
   330  
   331  	if err := r.reconcileGrafanaConfiguration(cr); err != nil {
   332  		return err
   333  	}
   334  
   335  	if err := r.reconcileGrafanaDashboards(cr); err != nil {
   336  		return err
   337  	}
   338  
   339  	return r.reconcileGPGKeysConfigMap(cr)
   340  }
   341  
   342  // reconcileCAConfigMap will ensure that the Certificate Authority ConfigMap is present.
   343  // This ConfigMap holds the CA Certificate data for client use.
   344  func (r *ReconcileArgoCD) reconcileCAConfigMap(cr *argoproj.ArgoCD) error {
   345  	cm := newConfigMapWithName(getCAConfigMapName(cr), cr)
   346  	if argoutil.IsObjectFound(r.Client, cr.Namespace, cm.Name, cm) {
   347  		return nil // ConfigMap found, do nothing
   348  	}
   349  
   350  	caSecret := argoutil.NewSecretWithSuffix(cr, common.ArgoCDCASuffix)
   351  	if !argoutil.IsObjectFound(r.Client, cr.Namespace, caSecret.Name, caSecret) {
   352  		log.Info(fmt.Sprintf("ca secret [%s] not found, waiting to reconcile ca configmap [%s]", caSecret.Name, cm.Name))
   353  		return nil
   354  	}
   355  
   356  	cm.Data = map[string]string{
   357  		common.ArgoCDKeyTLSCert: string(caSecret.Data[common.ArgoCDKeyTLSCert]),
   358  	}
   359  
   360  	if err := controllerutil.SetControllerReference(cr, cm, r.Scheme); err != nil {
   361  		return err
   362  	}
   363  	return r.Client.Create(context.TODO(), cm)
   364  }
   365  
   366  // reconcileConfiguration will ensure that the main ConfigMap for ArgoCD is present.
   367  func (r *ReconcileArgoCD) reconcileArgoConfigMap(cr *argoproj.ArgoCD) error {
   368  	cm := newConfigMapWithName(common.ArgoCDConfigMapName, cr)
   369  
   370  	cm.Data = make(map[string]string)
   371  
   372  	cm.Data[common.ArgoCDKeyApplicationInstanceLabelKey] = getApplicationInstanceLabelKey(cr)
   373  	cm.Data[common.ArgoCDKeyConfigManagementPlugins] = getConfigManagementPlugins(cr)
   374  	cm.Data[common.ArgoCDKeyAdminEnabled] = fmt.Sprintf("%t", !cr.Spec.DisableAdmin)
   375  	cm.Data[common.ArgoCDKeyGATrackingID] = getGATrackingID(cr)
   376  	cm.Data[common.ArgoCDKeyGAAnonymizeUsers] = fmt.Sprint(cr.Spec.GAAnonymizeUsers)
   377  	cm.Data[common.ArgoCDKeyHelpChatURL] = getHelpChatURL(cr)
   378  	cm.Data[common.ArgoCDKeyHelpChatText] = getHelpChatText(cr)
   379  	cm.Data[common.ArgoCDKeyKustomizeBuildOptions] = getKustomizeBuildOptions(cr)
   380  
   381  	if len(cr.Spec.KustomizeVersions) > 0 {
   382  		for _, kv := range cr.Spec.KustomizeVersions {
   383  			cm.Data["kustomize.version."+kv.Version] = kv.Path
   384  		}
   385  	}
   386  
   387  	cm.Data[common.ArgoCDKeyOIDCConfig] = getOIDCConfig(cr)
   388  
   389  	if c := getResourceHealthChecks(cr); c != nil {
   390  		for k, v := range c {
   391  			cm.Data[k] = v
   392  		}
   393  	}
   394  
   395  	if c, err := getResourceIgnoreDifferences(cr); c != nil && err == nil {
   396  		for k, v := range c {
   397  			cm.Data[k] = v
   398  		}
   399  	} else {
   400  		return err
   401  	}
   402  
   403  	if c := getResourceActions(cr); c != nil {
   404  		for k, v := range c {
   405  			cm.Data[k] = v
   406  		}
   407  	}
   408  
   409  	cm.Data[common.ArgoCDKeyResourceExclusions] = getResourceExclusions(cr)
   410  	cm.Data[common.ArgoCDKeyResourceInclusions] = getResourceInclusions(cr)
   411  	cm.Data[common.ArgoCDKeyResourceTrackingMethod] = getResourceTrackingMethod(cr)
   412  	cm.Data[common.ArgoCDKeyRepositories] = getInitialRepositories(cr)
   413  	cm.Data[common.ArgoCDKeyRepositoryCredentials] = getRepositoryCredentials(cr)
   414  	cm.Data[common.ArgoCDKeyStatusBadgeEnabled] = fmt.Sprint(cr.Spec.StatusBadgeEnabled)
   415  	cm.Data[common.ArgoCDKeyServerURL] = r.getArgoServerURI(cr)
   416  	cm.Data[common.ArgoCDKeyUsersAnonymousEnabled] = fmt.Sprint(cr.Spec.UsersAnonymousEnabled)
   417  
   418  	// create dex config if dex is enabled through `.spec.sso`
   419  	if UseDex(cr) {
   420  		dexConfig := getDexConfig(cr)
   421  
   422  		// Append the default OpenShift dex config if the openShiftOAuth is requested through `.spec.sso.dex`.
   423  		if cr.Spec.SSO != nil && cr.Spec.SSO.Dex != nil && cr.Spec.SSO.Dex.OpenShiftOAuth {
   424  			cfg, err := r.getOpenShiftDexConfig(cr)
   425  			if err != nil {
   426  				return err
   427  			}
   428  			dexConfig = cfg
   429  		}
   430  		cm.Data[common.ArgoCDKeyDexConfig] = dexConfig
   431  	}
   432  
   433  	if cr.Spec.Banner != nil {
   434  		if cr.Spec.Banner.Content != "" {
   435  			cm.Data[common.ArgoCDKeyBannerContent] = cr.Spec.Banner.Content
   436  			if cr.Spec.Banner.URL != "" {
   437  				cm.Data[common.ArgoCDKeyBannerURL] = cr.Spec.Banner.URL
   438  			}
   439  		}
   440  	}
   441  
   442  	if len(cr.Spec.ExtraConfig) > 0 {
   443  		for k, v := range cr.Spec.ExtraConfig {
   444  			cm.Data[k] = v
   445  		}
   446  	}
   447  
   448  	if err := controllerutil.SetControllerReference(cr, cm, r.Scheme); err != nil {
   449  		return err
   450  	}
   451  
   452  	existingCM := &corev1.ConfigMap{}
   453  	if argoutil.IsObjectFound(r.Client, cr.Namespace, cm.Name, existingCM) {
   454  
   455  		// reconcile dex configuration if dex is enabled `.spec.sso.dex.provider` or there is
   456  		// existing dex configuration
   457  		if UseDex(cr) {
   458  			if err := r.reconcileDexConfiguration(existingCM, cr); err != nil {
   459  				return err
   460  			}
   461  		} else if cr.Spec.SSO != nil && cr.Spec.SSO.Provider.ToLower() == argoproj.SSOProviderTypeKeycloak {
   462  			// retain oidc.config during reconcilliation when keycloak is configured
   463  			cm.Data[common.ArgoCDKeyOIDCConfig] = existingCM.Data[common.ArgoCDKeyOIDCConfig]
   464  		}
   465  
   466  		if !reflect.DeepEqual(cm.Data, existingCM.Data) {
   467  			existingCM.Data = cm.Data
   468  			return r.Client.Update(context.TODO(), existingCM)
   469  		}
   470  		return nil // Do nothing as there is no change in the configmap.
   471  	}
   472  	return r.Client.Create(context.TODO(), cm)
   473  
   474  }
   475  
   476  // reconcileGrafanaConfiguration will ensure that the Grafana configuration ConfigMap is present.
   477  func (r *ReconcileArgoCD) reconcileGrafanaConfiguration(cr *argoproj.ArgoCD) error {
   478  	if !cr.Spec.Grafana.Enabled {
   479  		return nil // Grafana not enabled, do nothing.
   480  	}
   481  
   482  	log.Info(grafanaDeprecatedWarning)
   483  
   484  	return nil
   485  }
   486  
   487  // reconcileGrafanaDashboards will ensure that the Grafana dashboards ConfigMap is present.
   488  func (r *ReconcileArgoCD) reconcileGrafanaDashboards(cr *argoproj.ArgoCD) error {
   489  	if !cr.Spec.Grafana.Enabled {
   490  		return nil // Grafana not enabled, do nothing.
   491  	}
   492  
   493  	log.Info(grafanaDeprecatedWarning)
   494  
   495  	return nil
   496  }
   497  
   498  // reconcileRBAC will ensure that the ArgoCD RBAC ConfigMap is present.
   499  func (r *ReconcileArgoCD) reconcileRBAC(cr *argoproj.ArgoCD) error {
   500  	cm := newConfigMapWithName(common.ArgoCDRBACConfigMapName, cr)
   501  	if argoutil.IsObjectFound(r.Client, cr.Namespace, cm.Name, cm) {
   502  		return r.reconcileRBACConfigMap(cm, cr)
   503  	}
   504  	return r.createRBACConfigMap(cm, cr)
   505  }
   506  
   507  // reconcileRBACConfigMap will ensure that the RBAC ConfigMap is syncronized with the given ArgoCD.
   508  func (r *ReconcileArgoCD) reconcileRBACConfigMap(cm *corev1.ConfigMap, cr *argoproj.ArgoCD) error {
   509  	changed := false
   510  	// Policy CSV
   511  	if cr.Spec.RBAC.Policy != nil && cm.Data[common.ArgoCDKeyRBACPolicyCSV] != *cr.Spec.RBAC.Policy {
   512  		cm.Data[common.ArgoCDKeyRBACPolicyCSV] = *cr.Spec.RBAC.Policy
   513  		changed = true
   514  	}
   515  
   516  	// Default Policy
   517  	if cr.Spec.RBAC.DefaultPolicy != nil && cm.Data[common.ArgoCDKeyRBACPolicyDefault] != *cr.Spec.RBAC.DefaultPolicy {
   518  		cm.Data[common.ArgoCDKeyRBACPolicyDefault] = *cr.Spec.RBAC.DefaultPolicy
   519  		changed = true
   520  	}
   521  
   522  	// Default Policy Matcher Mode
   523  	if cr.Spec.RBAC.PolicyMatcherMode != nil && cm.Data[common.ArgoCDPolicyMatcherMode] != *cr.Spec.RBAC.PolicyMatcherMode {
   524  		cm.Data[common.ArgoCDPolicyMatcherMode] = *cr.Spec.RBAC.PolicyMatcherMode
   525  		changed = true
   526  	}
   527  
   528  	// Scopes
   529  	if cr.Spec.RBAC.Scopes != nil && cm.Data[common.ArgoCDKeyRBACScopes] != *cr.Spec.RBAC.Scopes {
   530  		cm.Data[common.ArgoCDKeyRBACScopes] = *cr.Spec.RBAC.Scopes
   531  		changed = true
   532  	}
   533  
   534  	if changed {
   535  		// TODO: Reload server (and dex?) if RBAC settings change?
   536  		return r.Client.Update(context.TODO(), cm)
   537  	}
   538  	return nil // ConfigMap exists and nothing to do, move along...
   539  }
   540  
   541  // reconcileRedisConfiguration will ensure that all of the Redis ConfigMaps are present for the given ArgoCD.
   542  func (r *ReconcileArgoCD) reconcileRedisConfiguration(cr *argoproj.ArgoCD, useTLSForRedis bool) error {
   543  	if err := r.reconcileRedisHAConfigMap(cr, useTLSForRedis); err != nil {
   544  		return err
   545  	}
   546  	if err := r.reconcileRedisHAHealthConfigMap(cr, useTLSForRedis); err != nil {
   547  		return err
   548  	}
   549  	return nil
   550  }
   551  
   552  // reconcileRedisHAConfigMap will ensure that the Redis HA Health ConfigMap is present for the given ArgoCD.
   553  func (r *ReconcileArgoCD) reconcileRedisHAHealthConfigMap(cr *argoproj.ArgoCD, useTLSForRedis bool) error {
   554  	cm := newConfigMapWithName(common.ArgoCDRedisHAHealthConfigMapName, cr)
   555  	if argoutil.IsObjectFound(r.Client, cr.Namespace, cm.Name, cm) {
   556  		if !cr.Spec.HA.Enabled {
   557  			// ConfigMap exists but HA enabled flag has been set to false, delete the ConfigMap
   558  			return r.Client.Delete(context.TODO(), cm)
   559  		}
   560  		return nil // ConfigMap found with nothing changed, move along...
   561  	}
   562  
   563  	if !cr.Spec.HA.Enabled {
   564  		return nil // HA not enabled, do nothing.
   565  	}
   566  
   567  	cm.Data = map[string]string{
   568  		"redis_liveness.sh":    getRedisLivenessScript(useTLSForRedis),
   569  		"redis_readiness.sh":   getRedisReadinessScript(useTLSForRedis),
   570  		"sentinel_liveness.sh": getSentinelLivenessScript(useTLSForRedis),
   571  	}
   572  
   573  	if err := controllerutil.SetControllerReference(cr, cm, r.Scheme); err != nil {
   574  		return err
   575  	}
   576  	return r.Client.Create(context.TODO(), cm)
   577  }
   578  
   579  // reconcileRedisHAConfigMap will ensure that the Redis HA ConfigMap is present for the given ArgoCD.
   580  func (r *ReconcileArgoCD) reconcileRedisHAConfigMap(cr *argoproj.ArgoCD, useTLSForRedis bool) error {
   581  	cm := newConfigMapWithName(common.ArgoCDRedisHAConfigMapName, cr)
   582  	if argoutil.IsObjectFound(r.Client, cr.Namespace, cm.Name, cm) {
   583  		if !cr.Spec.HA.Enabled {
   584  			// ConfigMap exists but HA enabled flag has been set to false, delete the ConfigMap
   585  			return r.Client.Delete(context.TODO(), cm)
   586  		}
   587  		return nil // ConfigMap found with nothing changed, move along...
   588  	}
   589  
   590  	if !cr.Spec.HA.Enabled {
   591  		return nil // HA not enabled, do nothing.
   592  	}
   593  
   594  	cm.Data = map[string]string{
   595  		"haproxy.cfg":     getRedisHAProxyConfig(cr, useTLSForRedis),
   596  		"haproxy_init.sh": getRedisHAProxyScript(cr),
   597  		"init.sh":         getRedisInitScript(cr, useTLSForRedis),
   598  		"redis.conf":      getRedisConf(useTLSForRedis),
   599  		"sentinel.conf":   getRedisSentinelConf(useTLSForRedis),
   600  	}
   601  
   602  	if err := controllerutil.SetControllerReference(cr, cm, r.Scheme); err != nil {
   603  		return err
   604  	}
   605  	return r.Client.Create(context.TODO(), cm)
   606  }
   607  
   608  func (r *ReconcileArgoCD) recreateRedisHAConfigMap(cr *argoproj.ArgoCD, useTLSForRedis bool) error {
   609  	cm := newConfigMapWithName(common.ArgoCDRedisHAConfigMapName, cr)
   610  	if argoutil.IsObjectFound(r.Client, cr.Namespace, cm.Name, cm) {
   611  		if err := r.Client.Delete(context.TODO(), cm); err != nil {
   612  			return err
   613  		}
   614  	}
   615  	return r.reconcileRedisHAConfigMap(cr, useTLSForRedis)
   616  }
   617  
   618  func (r *ReconcileArgoCD) recreateRedisHAHealthConfigMap(cr *argoproj.ArgoCD, useTLSForRedis bool) error {
   619  	cm := newConfigMapWithName(common.ArgoCDRedisHAHealthConfigMapName, cr)
   620  	if argoutil.IsObjectFound(r.Client, cr.Namespace, cm.Name, cm) {
   621  		if err := r.Client.Delete(context.TODO(), cm); err != nil {
   622  			return err
   623  		}
   624  	}
   625  	return r.reconcileRedisHAHealthConfigMap(cr, useTLSForRedis)
   626  }
   627  
   628  // reconcileSSHKnownHosts will ensure that the ArgoCD SSH Known Hosts ConfigMap is present.
   629  func (r *ReconcileArgoCD) reconcileSSHKnownHosts(cr *argoproj.ArgoCD) error {
   630  	cm := newConfigMapWithName(common.ArgoCDKnownHostsConfigMapName, cr)
   631  	if argoutil.IsObjectFound(r.Client, cr.Namespace, cm.Name, cm) {
   632  		return nil // ConfigMap found, move along...
   633  	}
   634  
   635  	cm.Data = map[string]string{
   636  		common.ArgoCDKeySSHKnownHosts: getInitialSSHKnownHosts(cr),
   637  	}
   638  
   639  	if err := controllerutil.SetControllerReference(cr, cm, r.Scheme); err != nil {
   640  		return err
   641  	}
   642  	return r.Client.Create(context.TODO(), cm)
   643  }
   644  
   645  // reconcileTLSCerts will ensure that the ArgoCD TLS Certs ConfigMap is present.
   646  func (r *ReconcileArgoCD) reconcileTLSCerts(cr *argoproj.ArgoCD) error {
   647  	cm := newConfigMapWithName(common.ArgoCDTLSCertsConfigMapName, cr)
   648  	if argoutil.IsObjectFound(r.Client, cr.Namespace, cm.Name, cm) {
   649  		return nil // ConfigMap found, move along...
   650  	}
   651  
   652  	cm.Data = getInitialTLSCerts(cr)
   653  
   654  	if err := controllerutil.SetControllerReference(cr, cm, r.Scheme); err != nil {
   655  		return err
   656  	}
   657  	return r.Client.Create(context.TODO(), cm)
   658  }
   659  
   660  // reconcileGPGKeysConfigMap creates a gpg-keys config map
   661  func (r *ReconcileArgoCD) reconcileGPGKeysConfigMap(cr *argoproj.ArgoCD) error {
   662  	cm := newConfigMapWithName(common.ArgoCDGPGKeysConfigMapName, cr)
   663  	if argoutil.IsObjectFound(r.Client, cr.Namespace, cm.Name, cm) {
   664  		return nil
   665  	}
   666  	if err := controllerutil.SetControllerReference(cr, cm, r.Scheme); err != nil {
   667  		return err
   668  	}
   669  	return r.Client.Create(context.TODO(), cm)
   670  }