diff --git a/common/TOBEREMOVED.go b/common/TOBEREMOVED.go index 9b90d3c1f..c6ce3ab01 100644 --- a/common/TOBEREMOVED.go +++ b/common/TOBEREMOVED.go @@ -117,6 +117,49 @@ const ( // ArgoCDNotificationsControllerComponent is the name of the Notifications controller control plane component ArgoCDNotificationsControllerComponent = "argocd-notifications-controller" + + ArgoCDDefaultRedisSuffix = "redis" + + // ArgoCDRedisComponent is the name of the Redis control plane component + ArgoCDRedisComponent = "argocd-redis" + + // ArgoCDRedisHAComponent is the name of the Redis HA control plane component + ArgoCDRedisHAComponent = "argocd-redis-ha" + + // ArgoCDDefaultRedisPort is the default listen port for Redis. + ArgoCDDefaultRedisPort = 6379 + + // ArgoCDDefaultRedisImage is the Redis container image to use when not specified. + ArgoCDDefaultRedisImage = "redis" + + // ArgoCDDefaultRedisSentinelPort is the default listen port for Redis sentinel. + ArgoCDDefaultRedisSentinelPort = 26379 + + // ArgoCDDefaultRedisVersion is the Redis container image tag to use when not specified. + ArgoCDDefaultRedisVersion = "sha256:8061ca607db2a0c80010aeb5fc9bed0253448bc68711eaa14253a392f6c48280" // 6.2.4-alpine + + // ArgoCDDefaultRedisVersionHA is the Redis container image tag to use when not specified in HA mode. + ArgoCDDefaultRedisVersionHA = "sha256:8061ca607db2a0c80010aeb5fc9bed0253448bc68711eaa14253a392f6c48280" // 6.2.4-alpine + + // ArgoCDDefaultRedisConfigPath is the default Redis configuration directory when not specified. + ArgoCDDefaultRedisConfigPath = "/var/lib/redis" + + // ArgoCDDefaultRedisHAReplicas is the defaul number of replicas for Redis when rinning in HA mode. + ArgoCDDefaultRedisHAReplicas = int32(3) + + // ArgoCDDefaultRedisHAProxyImage is the default Redis HAProxy image to use when not specified. + ArgoCDDefaultRedisHAProxyImage = "haproxy" + + // ArgoCDDefaultRedisHAProxyVersion is the default Redis HAProxy image tag to use when not specified. + ArgoCDDefaultRedisHAProxyVersion = "sha256:7392fbbbb53e9e063ca94891da6656e6062f9d021c0e514888a91535b9f73231" // 2.0.25-alpine + + // ArgoCDRedisHAProxyImageEnvVar is the environment variable used to get the image + // to used for the Redis HA Proxy container. + ArgoCDRedisHAProxyImageEnvVar = "ARGOCD_REDIS_HA_PROXY_IMAGE" + + // ArgoCDRedisHAImageEnvVar is the environment variable used to get the image + // to used for the the Redis container in HA mode. + ArgoCDRedisHAImageEnvVar = "ARGOCD_REDIS_HA_IMAGE" ) // DefaultLabels returns the default set of labels for controllers. diff --git a/common/envVars.go b/common/envVars.go index f7e705382..9b8593f28 100644 --- a/common/envVars.go +++ b/common/envVars.go @@ -18,18 +18,6 @@ const ( // to used for the Dex container. ArgoCDRepoImageEnvVar = "ARGOCD_REPOSERVER_IMAGE" - // ArgoCDRedisHAProxyImageEnvVar is the environment variable used to get the image - // to used for the Redis HA Proxy container. - ArgoCDRedisHAProxyImageEnvVar = "ARGOCD_REDIS_HA_PROXY_IMAGE" - - // ArgoCDRedisHAImageEnvVar is the environment variable used to get the image - // to used for the the Redis container in HA mode. - ArgoCDRedisHAImageEnvVar = "ARGOCD_REDIS_HA_IMAGE" - - // ArgoCDRedisImageEnvVar is the environment variable used to get the image - // to used for the Redis container. - ArgoCDRedisImageEnvVar = "ARGOCD_REDIS_IMAGE" - // ArgoCDGrafanaImageEnvVar is the environment variable used to get the image // to used for the Grafana container. ArgoCDGrafanaImageEnvVar = "ARGOCD_GRAFANA_IMAGE" diff --git a/common/keys.go b/common/keys.go index 956ece08d..2998bdc37 100644 --- a/common/keys.go +++ b/common/keys.go @@ -208,3 +208,8 @@ const ( // ArgoCDArgoprojKeyManagedByClusterArgoCD is needed to identify namespace mentioned as sourceNamespace on ArgoCD ArgoCDArgoprojKeyManagedByClusterArgoCD = "argocd.argoproj.io/managed-by-cluster-argocd" ) + +// misc +const ( + TLSSecretNameKey = "tls-secret-name" +) diff --git a/common/redis.go b/common/redis.go index 97302fe2c..b687da112 100644 --- a/common/redis.go +++ b/common/redis.go @@ -2,14 +2,12 @@ package common // names const ( - // ArgoCDRedisComponent is the name of the Redis control plane component - ArgoCDRedisComponent = "argocd-redis" + RedisController = "redis-controller" - // ArgoCDRedisHAComponent is the name of the Redis HA control plane component - ArgoCDRedisHAComponent = "argocd-redis-ha" + // RedisComponentName is the Redis control plane component + RedisComponent = "redis" - //ArgoCDDefaultRedisSuffix is the default suffix to use for Redis resources. - ArgoCDDefaultRedisSuffix = "redis" + HAProxyName = "haproxy" // ArgoCDRedisHAConfigMapName is the upstream ArgoCD Redis HA ConfigMap name. ArgoCDRedisHAConfigMapName = "argocd-redis-ha-configmap" @@ -24,33 +22,70 @@ const ( ArgoCDRedisServerTLSSecretName = "argocd-operator-redis-tls" ) -// deafults +// suffixes const ( + //RedisSuffix is the default suffix to use for Redis resources. + RedisSuffix = "redis" - // ArgoCDDefaultRedisConfigPath is the default Redis configuration directory when not specified. - ArgoCDDefaultRedisConfigPath = "/var/lib/redis" + RedisHASuffix = "redis-ha" - // ArgoCDDefaultRedisHAReplicas is the defaul number of replicas for Redis when rinning in HA mode. - ArgoCDDefaultRedisHAReplicas = int32(3) + RedisHAProxySuffix = "redis-ha-haproxy" - // ArgoCDDefaultRedisHAProxyImage is the default Redis HAProxy image to use when not specified. - ArgoCDDefaultRedisHAProxyImage = "haproxy" + RedisHAServerSuffix = "redis-ha-server" - // ArgoCDDefaultRedisHAProxyVersion is the default Redis HAProxy image tag to use when not specified. - ArgoCDDefaultRedisHAProxyVersion = "sha256:7392fbbbb53e9e063ca94891da6656e6062f9d021c0e514888a91535b9f73231" // 2.0.25-alpine + RedisHAAnnouceSuffix = "redis-ha-announce" +) + +// defaults +const ( + + // DefaultRedisConfigPath is the default Redis configuration directory when not specified. + DefaultRedisConfigPath = "/var/lib/redis" + + // DefaultRedisHAReplicas is the defaul number of replicas for Redis when rinning in HA mode. + DefaultRedisHAReplicas = int32(3) + + // DefaultRedisHAProxyImage is the default Redis HAProxy image to use when not specified. + DefaultRedisHAProxyImage = "haproxy" + + // DefaultRedisHAProxyVersion is the default Redis HAProxy image tag to use when not specified. + DefaultRedisHAProxyVersion = "sha256:7392fbbbb53e9e063ca94891da6656e6062f9d021c0e514888a91535b9f73231" // 2.0.25-alpine // ArgoCDDefaultRedisImage is the Redis container image to use when not specified. - ArgoCDDefaultRedisImage = "redis" + DefaultRedisImage = "redis" + + // DefaultRedisPort is the default listen port for Redis. + DefaultRedisPort = 6379 - // ArgoCDDefaultRedisPort is the default listen port for Redis. - ArgoCDDefaultRedisPort = 6379 + // DefaultRedisSentinelPort is the default listen port for Redis sentinel. + DefaultRedisSentinelPort = 26379 - // ArgoCDDefaultRedisSentinelPort is the default listen port for Redis sentinel. - ArgoCDDefaultRedisSentinelPort = 26379 + // DefaultRedisVersion is the Redis container image tag to use when not specified. + DefaultRedisVersion = "sha256:8061ca607db2a0c80010aeb5fc9bed0253448bc68711eaa14253a392f6c48280" // 6.2.4-alpine - // ArgoCDDefaultRedisVersion is the Redis container image tag to use when not specified. - ArgoCDDefaultRedisVersion = "sha256:8061ca607db2a0c80010aeb5fc9bed0253448bc68711eaa14253a392f6c48280" // 6.2.4-alpine + // DefaultRedisVersionHA is the Redis container image tag to use when not specified in HA mode. + DefaultRedisVersionHA = "sha256:8061ca607db2a0c80010aeb5fc9bed0253448bc68711eaa14253a392f6c48280" // 6.2.4-alpine +) + +// env vars +const ( + // RedisHAProxyImageEnvVar is the environment variable used to get the image + // to used for the Redis HA Proxy container. + RedisHAProxyImageEnvVar = "ARGOCD_REDIS_HA_PROXY_IMAGE" + + // RedisHAImageEnvVar is the environment variable used to get the image + // to used for the the Redis container in HA mode. + RedisHAImageEnvVar = "ARGOCD_REDIS_HA_IMAGE" - // ArgoCDDefaultRedisVersionHA is the Redis container image tag to use when not specified in HA mode. - ArgoCDDefaultRedisVersionHA = "sha256:8061ca607db2a0c80010aeb5fc9bed0253448bc68711eaa14253a392f6c48280" // 6.2.4-alpine + // RedisImageEnvVar is the environment variable used to get the image + // to used for the Redis container. + RedisImageEnvVar = "ARGOCD_REDIS_IMAGE" + + // RedisConfigPathEnvVar is the environment variiable used to get the redis configuration templates + RedisConfigPathEnvVar = "REDIS_CONFIG_PATH" +) + +// keys +const ( + RedisTLSCertChangedKey = "redis.tls.cert.changed" ) diff --git a/common/reposerver.go b/common/reposerver.go index 51a190700..17575b899 100644 --- a/common/reposerver.go +++ b/common/reposerver.go @@ -4,6 +4,8 @@ package common const ( // ArgoCDRepoServerTLSSecretName is the name of the TLS secret for the repo-server ArgoCDRepoServerTLSSecretName = "argocd-repo-server-tls" + + RepoServerSuffix = "-repo-server" ) // values diff --git a/common/values.go b/common/values.go index 0747801be..5e3b002be 100644 --- a/common/values.go +++ b/common/values.go @@ -41,6 +41,14 @@ const ( // ArgoCDMetrics is the resource metrics key for labels. ArgoCDMetrics = "metrics" + + ArgoCDStatusUnknown = "Unknown" + + ArgoCDStatusPending = "Pending" + + ArgoCDStatusRunning = "Running" + + ArgoCDStatusAvailable = "Available" ) // general values @@ -75,6 +83,7 @@ const ( SecretKind = "Secret" ServiceKind = "Service" ServiceAccountKind = "ServiceAccount" + ArgoCDKind = "ArgoCD" ) // Commnds diff --git a/pkg/cluster/event.go b/pkg/cluster/event.go index ee3f082eb..3a1b4f343 100644 --- a/pkg/cluster/event.go +++ b/pkg/cluster/event.go @@ -8,6 +8,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" cntrlClient "sigs.k8s.io/controller-runtime/pkg/client" + argoproj "github.com/argoproj-labs/argocd-operator/api/v1beta1" "github.com/argoproj-labs/argocd-operator/pkg/argoutil" "github.com/argoproj-labs/argocd-operator/pkg/mutation" ) @@ -23,10 +24,13 @@ type EventRequest struct { CreationTimestamp metav1.Time FirstTimestamp metav1.Time LastTimestamp metav1.Time + Instance *argoproj.ArgoCD // array of functions to mutate event before returning to requester Mutations []mutation.MutateFunc - Client cntrlClient.Client + // array of arguments to pass to the mutation funcs + MutationArgs []interface{} + Client cntrlClient.Client } func newEvent(objMeta metav1.ObjectMeta, typeMeta metav1.TypeMeta, eventType, action, message, reason string) *corev1.Event { @@ -61,7 +65,7 @@ func RequestEvent(request EventRequest) (*corev1.Event, error) { if len(request.Mutations) > 0 { for _, mutation := range request.Mutations { - err := mutation(nil, event, request.Client) + err := mutation(request.Instance, event, request.Client, request.MutationArgs) if err != nil { mutationErr = err } diff --git a/pkg/cluster/namespace.go b/pkg/cluster/namespace.go index ffcbf17b0..5abfd58d8 100644 --- a/pkg/cluster/namespace.go +++ b/pkg/cluster/namespace.go @@ -10,6 +10,7 @@ import ( "github.com/argoproj-labs/argocd-operator/pkg/mutation" "github.com/argoproj-labs/argocd-operator/pkg/resource" + argoproj "github.com/argoproj-labs/argocd-operator/api/v1beta1" cntrlClient "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -17,10 +18,13 @@ import ( type NamespaceRequest struct { ObjectMeta metav1.ObjectMeta Spec corev1.NamespaceSpec + Instance *argoproj.ArgoCD - // array of functions to mutate role before returning to requester + // array of functions to mutate obj before returning to requester Mutations []mutation.MutateFunc - Client cntrlClient.Client + // array of arguments to pass to the mutation funcs + MutationArgs []interface{} + Client cntrlClient.Client } func newNamespace(objMeta metav1.ObjectMeta, spec corev1.NamespaceSpec) *corev1.Namespace { @@ -40,7 +44,7 @@ func RequestNamespace(request NamespaceRequest) (*corev1.Namespace, error) { if len(request.Mutations) > 0 { for _, mutation := range request.Mutations { - err := mutation(nil, namespace, request.Client) + err := mutation(request.Instance, namespace, request.Client, request.MutationArgs) if err != nil { mutationErr = err } diff --git a/pkg/cluster/namespace_test.go b/pkg/cluster/namespace_test.go index 71f795509..a2743e2a7 100644 --- a/pkg/cluster/namespace_test.go +++ b/pkg/cluster/namespace_test.go @@ -36,11 +36,11 @@ var ( } ) -func testMutationFuncFailed(cr *argoproj.ArgoCD, resource interface{}, client cntrlClient.Client) error { +func testMutationFuncFailed(cr *argoproj.ArgoCD, resource interface{}, client cntrlClient.Client, args ...interface{}) error { return errors.New("test-mutation-error") } -func testMutationFuncSuccessful(cr *argoproj.ArgoCD, resource interface{}, client cntrlClient.Client) error { +func testMutationFuncSuccessful(cr *argoproj.ArgoCD, resource interface{}, client cntrlClient.Client, args ...interface{}) error { switch obj := resource.(type) { case *corev1.Namespace: if _, ok := obj.Labels[testKey]; ok { diff --git a/pkg/monitoring/monitoring_test.go b/pkg/monitoring/monitoring_test.go index 64ff1e1e2..834b1c34c 100644 --- a/pkg/monitoring/monitoring_test.go +++ b/pkg/monitoring/monitoring_test.go @@ -26,11 +26,11 @@ var ( } ) -func testMutationFuncFailed(cr *argoproj.ArgoCD, resource interface{}, client cntrlClient.Client) error { +func testMutationFuncFailed(cr *argoproj.ArgoCD, resource interface{}, client cntrlClient.Client, args ...interface{}) error { return errors.New("test-mutation-error") } -func testMutationFuncSuccessful(cr *argoproj.ArgoCD, resource interface{}, client cntrlClient.Client) error { +func testMutationFuncSuccessful(cr *argoproj.ArgoCD, resource interface{}, client cntrlClient.Client, args ...interface{}) error { switch obj := resource.(type) { case *monitoringv1.PrometheusRule: obj.Name = testPrometheusRuleNameMutated diff --git a/pkg/monitoring/prometheusRule.go b/pkg/monitoring/prometheusRule.go index 1d4d8f9a9..f3cbf02a4 100644 --- a/pkg/monitoring/prometheusRule.go +++ b/pkg/monitoring/prometheusRule.go @@ -8,6 +8,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" cntrlClient "sigs.k8s.io/controller-runtime/pkg/client" + argoproj "github.com/argoproj-labs/argocd-operator/api/v1beta1" "github.com/argoproj-labs/argocd-operator/pkg/mutation" "github.com/argoproj-labs/argocd-operator/pkg/resource" ) @@ -17,9 +18,13 @@ type PrometheusRuleRequest struct { ObjectMeta metav1.ObjectMeta Spec monitoringv1.PrometheusRuleSpec - // array of functions to mutate role before returning to requester + Instance *argoproj.ArgoCD + + // array of functions to mutate obj before returning to requester Mutations []mutation.MutateFunc - Client cntrlClient.Client + // array of arguments to pass to the mutation funcs + MutationArgs []interface{} + Client cntrlClient.Client } // newPrometheusRule returns a new PrometheusRule instance for the given ArgoCD. @@ -38,7 +43,7 @@ func RequestPrometheusRule(request PrometheusRuleRequest) (*monitoringv1.Prometh if len(request.Mutations) > 0 { for _, mutation := range request.Mutations { - err := mutation(nil, prometheusRule, request.Client) + err := mutation(request.Instance, prometheusRule, request.Client, request.MutationArgs) if err != nil { mutationErr = err } diff --git a/pkg/monitoring/serviceMonitor.go b/pkg/monitoring/serviceMonitor.go index adcf54a34..1d231684a 100644 --- a/pkg/monitoring/serviceMonitor.go +++ b/pkg/monitoring/serviceMonitor.go @@ -8,6 +8,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" cntrlClient "sigs.k8s.io/controller-runtime/pkg/client" + argoproj "github.com/argoproj-labs/argocd-operator/api/v1beta1" "github.com/argoproj-labs/argocd-operator/pkg/mutation" "github.com/argoproj-labs/argocd-operator/pkg/resource" ) @@ -16,10 +17,13 @@ import ( type ServiceMonitorRequest struct { ObjectMeta metav1.ObjectMeta Spec monitoringv1.ServiceMonitorSpec + Instance *argoproj.ArgoCD - // array of functions to mutate role before returning to requester + // array of functions to mutate obj before returning to requester Mutations []mutation.MutateFunc - Client cntrlClient.Client + // array of arguments to pass to the mutation funcs + MutationArgs []interface{} + Client cntrlClient.Client } // newServiceMonitor returns a new ServiceMonitor instance for the given ArgoCD. @@ -38,7 +42,7 @@ func RequestServiceMonitor(request ServiceMonitorRequest) (*monitoringv1.Service if len(request.Mutations) > 0 { for _, mutation := range request.Mutations { - err := mutation(nil, serviceMonitor, request.Client) + err := mutation(request.Instance, serviceMonitor, request.Client, request.MutationArgs) if err != nil { mutationErr = err } diff --git a/pkg/mutation/mutation.go b/pkg/mutation/mutation.go index 24c32a6cf..307db7746 100644 --- a/pkg/mutation/mutation.go +++ b/pkg/mutation/mutation.go @@ -14,7 +14,7 @@ var ( ) // MutateFunc defines the function signature for any mutation functions that need to be executed by this package -type MutateFunc func(*argoproj.ArgoCD, interface{}, client.Client) error +type MutateFunc func(*argoproj.ArgoCD, interface{}, client.Client, ...interface{}) error // Register adds a modifier for updating resources during reconciliation. func Register(m ...MutateFunc) { @@ -23,11 +23,11 @@ func Register(m ...MutateFunc) { mutateFuncs = append(mutateFuncs, m...) } -func ApplyReconcilerMutation(cr *argoproj.ArgoCD, resource interface{}, client client.Client) error { +func ApplyReconcilerMutation(cr *argoproj.ArgoCD, resource interface{}, client client.Client, args ...interface{}) error { mutex.Lock() defer mutex.Unlock() for _, mutateFunc := range mutateFuncs { - if err := mutateFunc(cr, resource, client); err != nil { + if err := mutateFunc(cr, resource, client, args...); err != nil { return err } } diff --git a/pkg/networking/ingress.go b/pkg/networking/ingress.go index 25bdda9db..a660ce22d 100644 --- a/pkg/networking/ingress.go +++ b/pkg/networking/ingress.go @@ -8,6 +8,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" cntrlClient "sigs.k8s.io/controller-runtime/pkg/client" + argoproj "github.com/argoproj-labs/argocd-operator/api/v1beta1" "github.com/argoproj-labs/argocd-operator/pkg/mutation" "github.com/argoproj-labs/argocd-operator/pkg/resource" ) @@ -16,10 +17,13 @@ import ( type IngressRequest struct { ObjectMeta metav1.ObjectMeta Spec networkingv1.IngressSpec + Instance *argoproj.ArgoCD - // array of functions to mutate role before returning to requester + // array of functions to mutate obj before returning to requester Mutations []mutation.MutateFunc - Client cntrlClient.Client + // array of arguments to pass to the mutation funcs + MutationArgs []interface{} + Client cntrlClient.Client } // newIngress returns a new Ingress instance for the given ArgoCD. @@ -38,7 +42,7 @@ func RequestIngress(request IngressRequest) (*networkingv1.Ingress, error) { if len(request.Mutations) > 0 { for _, mutation := range request.Mutations { - err := mutation(nil, ingress, request.Client) + err := mutation(request.Instance, ingress, request.Client, request.MutationArgs) if err != nil { mutationErr = err } diff --git a/pkg/networking/networking_test.go b/pkg/networking/networking_test.go index 3aaaa37a9..449fc36f8 100644 --- a/pkg/networking/networking_test.go +++ b/pkg/networking/networking_test.go @@ -30,11 +30,11 @@ var ( } ) -func testMutationFuncFailed(cr *argoproj.ArgoCD, resource interface{}, client cntrlClient.Client) error { +func testMutationFuncFailed(cr *argoproj.ArgoCD, resource interface{}, client cntrlClient.Client, args ...interface{}) error { return errors.New("test-mutation-error") } -func testMutationFuncSuccessful(cr *argoproj.ArgoCD, resource interface{}, client cntrlClient.Client) error { +func testMutationFuncSuccessful(cr *argoproj.ArgoCD, resource interface{}, client cntrlClient.Client, args ...interface{}) error { switch obj := resource.(type) { case *corev1.Service: obj.Name = testServiceNameMutated diff --git a/pkg/networking/service.go b/pkg/networking/service.go index d4b21df26..d5b72858a 100644 --- a/pkg/networking/service.go +++ b/pkg/networking/service.go @@ -10,16 +10,21 @@ import ( "github.com/argoproj-labs/argocd-operator/pkg/mutation" "github.com/argoproj-labs/argocd-operator/pkg/resource" + + argoproj "github.com/argoproj-labs/argocd-operator/api/v1beta1" ) // ServiceRequest objects contain all the required information to produce a service object in return type ServiceRequest struct { ObjectMeta metav1.ObjectMeta Spec corev1.ServiceSpec + Instance *argoproj.ArgoCD - // array of functions to mutate role before returning to requester + // array of functions to mutate obj before returning to requester Mutations []mutation.MutateFunc - Client cntrlClient.Client + // array of arguments to pass to the mutation funcs + MutationArgs []interface{} + Client cntrlClient.Client } // newService returns a new Service instance for the given ArgoCD. @@ -38,7 +43,7 @@ func RequestService(request ServiceRequest) (*corev1.Service, error) { if len(request.Mutations) > 0 { for _, mutation := range request.Mutations { - err := mutation(nil, service, request.Client) + err := mutation(request.Instance, service, request.Client, request.MutationArgs...) if err != nil { mutationErr = err } diff --git a/pkg/openshift/mutation.go b/pkg/openshift/mutation.go index 20f1728e2..20e812b59 100644 --- a/pkg/openshift/mutation.go +++ b/pkg/openshift/mutation.go @@ -8,34 +8,158 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" argoproj "github.com/argoproj-labs/argocd-operator/api/v1beta1" + "github.com/argoproj-labs/argocd-operator/common" "github.com/argoproj-labs/argocd-operator/pkg/mutation" + "github.com/pkg/errors" + appsv1 "k8s.io/api/apps/v1" + rbacv1 "k8s.io/api/rbac/v1" ) func init() { mutation.Register(AddSeccompProfileForOpenShift) + mutation.Register(AddNonRootSCCForOpenShift) + mutation.Register(AddAutoTLSAnnotationForOpenShift) } -func AddSeccompProfileForOpenShift(cr *argoproj.ArgoCD, resource interface{}, client client.Client) error { +// TO DO: Add dedicated e2e tests for all these mutations + +// AddAutoTLSAnnotationForOpenShift adds the OpenShift Service CA TLS cert request annotaiton to the provided service object, using the provided secret name as the value +func AddAutoTLSAnnotationForOpenShift(cr *argoproj.ArgoCD, resource interface{}, client client.Client, args ...interface{}) error { if !IsOpenShiftEnv() { return nil } switch obj := resource.(type) { - case *corev1.PodSpec: + case *corev1.Service: + if cr == nil { + return nil + } + // return if autoTLS is not requested + if !cr.Spec.Redis.WantsAutoTLS() { + return nil + } + + if obj.Annotations == nil { + obj.Annotations = make(map[string]string) + } + + // Ensure that args carries only one argument, which is a map of type map[string]string + // containing the key "tls-secret-name". If this is the case, the associated value + // can be used within the service annotation + if len(args) == 1 { + for _, arg := range args { + argMap := arg.(map[string]string) + if val, ok := argMap[common.TLSSecretNameKey]; ok { + obj.Annotations[common.ServiceBetaOpenshiftKeyCertSecret] = val + } + } + } + } + return nil +} + +func AddSeccompProfileForOpenShift(cr *argoproj.ArgoCD, resource interface{}, client client.Client, args ...interface{}) error { + if !IsOpenShiftEnv() { + return nil + } + + addSeccompProfile := func(podSpec *corev1.PodSpec) error { + if !IsVersionAPIAvailable() { + return nil + } version, err := GetClusterVersion(client) if err != nil { - return err + return errors.Wrapf(err, "AddSeccompProfileForOpenShift: failed to retrieve OpenShift cluster version") } + if version == "" || semver.Compare(fmt.Sprintf("v%s", version), "v4.10.999") > 0 { - if obj.SecurityContext == nil { - obj.SecurityContext = &corev1.PodSecurityContext{} + if podSpec.SecurityContext == nil { + podSpec.SecurityContext = &corev1.PodSecurityContext{} } - if obj.SecurityContext.SeccompProfile == nil { - obj.SecurityContext.SeccompProfile = &corev1.SeccompProfile{} + if podSpec.SecurityContext.SeccompProfile == nil { + podSpec.SecurityContext.SeccompProfile = &corev1.SeccompProfile{} } - if len(obj.SecurityContext.SeccompProfile.Type) == 0 { - obj.SecurityContext.SeccompProfile.Type = corev1.SeccompProfileTypeRuntimeDefault + if len(podSpec.SecurityContext.SeccompProfile.Type) == 0 { + podSpec.SecurityContext.SeccompProfile.Type = corev1.SeccompProfileTypeRuntimeDefault } + + containers := []corev1.Container{} + for _, container := range podSpec.Containers { + if container.SecurityContext.SeccompProfile == nil { + container.SecurityContext.SeccompProfile = &corev1.SeccompProfile{} + } + if len(container.SecurityContext.SeccompProfile.Type) == 0 { + container.SecurityContext.SeccompProfile.Type = corev1.SeccompProfileTypeRuntimeDefault + } + containers = append(containers, container) + } + podSpec.Containers = containers + + initContainers := []corev1.Container{} + for _, initc := range podSpec.InitContainers { + if initc.SecurityContext.SeccompProfile == nil { + initc.SecurityContext.SeccompProfile = &corev1.SeccompProfile{} + } + if len(initc.SecurityContext.SeccompProfile.Type) == 0 { + initc.SecurityContext.SeccompProfile.Type = corev1.SeccompProfileTypeRuntimeDefault + } + initContainers = append(initContainers, initc) + } + podSpec.InitContainers = initContainers + } + return nil } + + switch obj := resource.(type) { + case *appsv1.StatefulSet: + return addSeccompProfile(&obj.Spec.Template.Spec) + case *appsv1.Deployment: + return addSeccompProfile(&obj.Spec.Template.Spec) + } + return nil +} + +func AddNonRootSCCForOpenShift(cr *argoproj.ArgoCD, resource interface{}, client client.Client, args ...interface{}) error { + if !IsOpenShiftEnv() { + return nil + } + switch obj := resource.(type) { + case *rbacv1.Role: + // This mutation only applies to redis and redis-ha roles + if component, ok := obj.Labels[common.AppK8sKeyComponent]; !ok || (ok && component != common.RedisComponent) { + return nil + } + + if !IsVersionAPIAvailable() { + return nil + } + // Starting with OpenShift 4.11, we need to use the resource name "nonroot-v2" instead of "nonroot" + resourceName := "nonroot" + version, err := GetClusterVersion(client) + if err != nil { + return errors.Wrapf(err, "AppendNonRootSCCForOpenShift: failed to retrieve OpenShift cluster version") + } + + if version == "" || semver.Compare(fmt.Sprintf("v%s", version), "v4.10.999") > 0 { + resourceName = "nonroot-v2" + } + + orules := rbacv1.PolicyRule{ + APIGroups: []string{ + "security.openshift.io", + }, + ResourceNames: []string{ + resourceName, + }, + Resources: []string{ + "securitycontextconstraints", + }, + Verbs: []string{ + "use", + }, + } + obj.Rules = append(obj.Rules, orules) + } + return nil } diff --git a/pkg/openshift/networking.go b/pkg/openshift/networking.go index 697d5554b..6f1f329ee 100644 --- a/pkg/openshift/networking.go +++ b/pkg/openshift/networking.go @@ -8,6 +8,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" cntrlClient "sigs.k8s.io/controller-runtime/pkg/client" + argoproj "github.com/argoproj-labs/argocd-operator/api/v1beta1" "github.com/argoproj-labs/argocd-operator/pkg/argoutil" "github.com/argoproj-labs/argocd-operator/pkg/mutation" "github.com/argoproj-labs/argocd-operator/pkg/resource" @@ -39,10 +40,13 @@ func VerifyRouteAPI() error { type RouteRequest struct { ObjectMeta metav1.ObjectMeta Spec routev1.RouteSpec + Instance *argoproj.ArgoCD - // array of functions to mutate role before returning to requester + // array of functions to mutate obj before returning to requester Mutations []mutation.MutateFunc - Client cntrlClient.Client + // array of arguments to pass to the mutation funcs + MutationArgs []interface{} + Client cntrlClient.Client } // newRoute returns a new Route instance for the given ArgoCD. @@ -61,7 +65,7 @@ func RequestRoute(request RouteRequest) (*routev1.Route, error) { if len(request.Mutations) > 0 { for _, mutation := range request.Mutations { - err := mutation(nil, route, request.Client) + err := mutation(request.Instance, route, request.Client, request.MutationArgs) if err != nil { mutationErr = err } diff --git a/pkg/openshift/openshift_test.go b/pkg/openshift/openshift_test.go index 7f8cb67af..e6aebd238 100644 --- a/pkg/openshift/openshift_test.go +++ b/pkg/openshift/openshift_test.go @@ -27,11 +27,11 @@ var ( } ) -func testMutationFuncFailed(cr *argoproj.ArgoCD, resource interface{}, client cntrlClient.Client) error { +func testMutationFuncFailed(cr *argoproj.ArgoCD, resource interface{}, client cntrlClient.Client, args ...interface{}) error { return errors.New("test-mutation-error") } -func testMutationFuncSuccessful(cr *argoproj.ArgoCD, resource interface{}, client cntrlClient.Client) error { +func testMutationFuncSuccessful(cr *argoproj.ArgoCD, resource interface{}, client cntrlClient.Client, args ...interface{}) error { switch obj := resource.(type) { case *oappsv1.DeploymentConfig: obj.Name = testNameMutated diff --git a/pkg/openshift/workloads.go b/pkg/openshift/workloads.go index 2851faf43..69b06a8f8 100644 --- a/pkg/openshift/workloads.go +++ b/pkg/openshift/workloads.go @@ -8,6 +8,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" cntrlClient "sigs.k8s.io/controller-runtime/pkg/client" + argoproj "github.com/argoproj-labs/argocd-operator/api/v1beta1" "github.com/argoproj-labs/argocd-operator/pkg/mutation" "github.com/argoproj-labs/argocd-operator/pkg/resource" ) @@ -16,10 +17,13 @@ import ( type DeploymentConfigRequest struct { ObjectMeta metav1.ObjectMeta Spec oappsv1.DeploymentConfigSpec + Instance *argoproj.ArgoCD - // array of functions to mutate role before returning to requester + // array of functions to mutate obj before returning to requester Mutations []mutation.MutateFunc - Client cntrlClient.Client + // array of arguments to pass to the mutation funcs + MutationArgs []interface{} + Client cntrlClient.Client } // newDeploymentConfig returns a new DeploymentConfig instance for the given ArgoCD. @@ -37,7 +41,7 @@ func RequestDeploymentConfig(request DeploymentConfigRequest) (*oappsv1.Deployme deploymentConfig := newDeploymentConfig(request.ObjectMeta, request.Spec) if len(request.Mutations) > 0 { for _, mutation := range request.Mutations { - err := mutation(nil, deploymentConfig, request.Client) + err := mutation(request.Instance, deploymentConfig, request.Client, request.MutationArgs) if err != nil { mutationErr = err } diff --git a/pkg/permissions/clusterrole.go b/pkg/permissions/clusterrole.go index 9a1f016f3..1f401e92f 100644 --- a/pkg/permissions/clusterrole.go +++ b/pkg/permissions/clusterrole.go @@ -8,6 +8,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" cntrlClient "sigs.k8s.io/controller-runtime/pkg/client" + argoproj "github.com/argoproj-labs/argocd-operator/api/v1beta1" "github.com/argoproj-labs/argocd-operator/pkg/mutation" "github.com/argoproj-labs/argocd-operator/pkg/resource" ) @@ -16,10 +17,13 @@ import ( type ClusterRoleRequest struct { ObjectMeta metav1.ObjectMeta Rules []rbacv1.PolicyRule + Instance *argoproj.ArgoCD // array of functions to mutate clusterRole before returning to requester Mutations []mutation.MutateFunc - Client cntrlClient.Client + // array of arguments to pass to the mutation funcs + MutationArgs []interface{} + Client cntrlClient.Client } // newClusterRole returns a new clusterRole instance. @@ -41,7 +45,7 @@ func RequestClusterRole(request ClusterRoleRequest) (*rbacv1.ClusterRole, error) if len(request.Mutations) > 0 { for _, mutation := range request.Mutations { - err := mutation(nil, clusterRole, request.Client) + err := mutation(request.Instance, clusterRole, request.Client, request.MutationArgs) if err != nil { mutationErr = err } diff --git a/pkg/permissions/permissions_test.go b/pkg/permissions/permissions_test.go index 5bfc8ceb6..f3b920f57 100644 --- a/pkg/permissions/permissions_test.go +++ b/pkg/permissions/permissions_test.go @@ -62,11 +62,11 @@ var ( } ) -func testMutationFuncFailed(cr *argoproj.ArgoCD, resource interface{}, client cntrlClient.Client) error { +func testMutationFuncFailed(cr *argoproj.ArgoCD, resource interface{}, client cntrlClient.Client, args ...interface{}) error { return errors.New("test-mutation-error") } -func testMutationFuncSuccessful(cr *argoproj.ArgoCD, resource interface{}, client cntrlClient.Client) error { +func testMutationFuncSuccessful(cr *argoproj.ArgoCD, resource interface{}, client cntrlClient.Client, args ...interface{}) error { switch obj := resource.(type) { case *rbacv1.Role: if obj.Namespace == testNamespace { diff --git a/pkg/permissions/role.go b/pkg/permissions/role.go index 83b1b436c..97f9fa361 100644 --- a/pkg/permissions/role.go +++ b/pkg/permissions/role.go @@ -8,6 +8,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" cntrlClient "sigs.k8s.io/controller-runtime/pkg/client" + argoproj "github.com/argoproj-labs/argocd-operator/api/v1beta1" "github.com/argoproj-labs/argocd-operator/pkg/mutation" "github.com/argoproj-labs/argocd-operator/pkg/resource" ) @@ -16,10 +17,13 @@ import ( type RoleRequest struct { ObjectMeta metav1.ObjectMeta Rules []rbacv1.PolicyRule + Instance *argoproj.ArgoCD - // array of functions to mutate role before returning to requester + // array of functions to mutate obj before returning to requester Mutations []mutation.MutateFunc - Client cntrlClient.Client + // array of arguments to pass to the mutation funcs + MutationArgs []interface{} + Client cntrlClient.Client } // newRole returns a new Role instance. @@ -40,7 +44,7 @@ func RequestRole(request RoleRequest) (*rbacv1.Role, error) { if len(request.Mutations) > 0 { for _, mutation := range request.Mutations { - err := mutation(nil, role, request.Client) + err := mutation(request.Instance, role, request.Client, request.MutationArgs) if err != nil { mutationErr = err } diff --git a/pkg/workloads/configmap.go b/pkg/workloads/configmap.go index 322e6931a..6270a7373 100644 --- a/pkg/workloads/configmap.go +++ b/pkg/workloads/configmap.go @@ -8,6 +8,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" cntrlClient "sigs.k8s.io/controller-runtime/pkg/client" + argoproj "github.com/argoproj-labs/argocd-operator/api/v1beta1" "github.com/argoproj-labs/argocd-operator/pkg/mutation" "github.com/argoproj-labs/argocd-operator/pkg/resource" ) @@ -16,10 +17,13 @@ import ( type ConfigMapRequest struct { ObjectMeta metav1.ObjectMeta Data map[string]string + Instance *argoproj.ArgoCD - // array of functions to mutate role before returning to requester + // array of functions to mutate obj before returning to requester Mutations []mutation.MutateFunc - Client cntrlClient.Client + // array of arguments to pass to the mutation funcs + MutationArgs []interface{} + Client cntrlClient.Client } // newConfigMap returns a new ConfigMap instance for the given ArgoCD. @@ -38,7 +42,7 @@ func RequestConfigMap(request ConfigMapRequest) (*corev1.ConfigMap, error) { if len(request.Mutations) > 0 { for _, mutation := range request.Mutations { - err := mutation(nil, configMap, request.Client) + err := mutation(request.Instance, configMap, request.Client, request.MutationArgs) if err != nil { mutationErr = err } diff --git a/pkg/workloads/deployment.go b/pkg/workloads/deployment.go index d4f1d2382..efb76e5e3 100644 --- a/pkg/workloads/deployment.go +++ b/pkg/workloads/deployment.go @@ -8,6 +8,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" cntrlClient "sigs.k8s.io/controller-runtime/pkg/client" + argoproj "github.com/argoproj-labs/argocd-operator/api/v1beta1" "github.com/argoproj-labs/argocd-operator/pkg/mutation" "github.com/argoproj-labs/argocd-operator/pkg/resource" ) @@ -16,10 +17,13 @@ import ( type DeploymentRequest struct { ObjectMeta metav1.ObjectMeta Spec appsv1.DeploymentSpec + Instance *argoproj.ArgoCD - // array of functions to mutate role before returning to requester + // array of functions to mutate obj before returning to requester Mutations []mutation.MutateFunc - Client cntrlClient.Client + // array of arguments to pass to the mutation funcs + MutationArgs []interface{} + Client cntrlClient.Client } // newDeployment returns a new Deployment instance for the given ArgoCD. @@ -39,7 +43,7 @@ func RequestDeployment(request DeploymentRequest) (*appsv1.Deployment, error) { if len(request.Mutations) > 0 { for _, mutation := range request.Mutations { - err := mutation(nil, deployment, request.Client) + err := mutation(request.Instance, deployment, request.Client, request.MutationArgs) if err != nil { mutationErr = err } diff --git a/pkg/workloads/hpa.go b/pkg/workloads/hpa.go index 43c52baec..cef858db4 100644 --- a/pkg/workloads/hpa.go +++ b/pkg/workloads/hpa.go @@ -8,6 +8,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" cntrlClient "sigs.k8s.io/controller-runtime/pkg/client" + argoproj "github.com/argoproj-labs/argocd-operator/api/v1beta1" "github.com/argoproj-labs/argocd-operator/pkg/mutation" "github.com/argoproj-labs/argocd-operator/pkg/resource" ) @@ -16,10 +17,13 @@ import ( type HorizontalPodAutoscalerRequest struct { ObjectMeta metav1.ObjectMeta Spec autoscaling.HorizontalPodAutoscalerSpec + Instance *argoproj.ArgoCD - // array of functions to mutate role before returning to requester + // array of functions to mutate obj before returning to requester Mutations []mutation.MutateFunc - Client cntrlClient.Client + // array of arguments to pass to the mutation funcs + MutationArgs []interface{} + Client cntrlClient.Client } // newHorizontalPodAutoscaler returns a new HorizontalPodAutoscaler instance for the given ArgoCD. @@ -39,7 +43,7 @@ func RequestHorizontalPodAutoscaler(request HorizontalPodAutoscalerRequest) (*au if len(request.Mutations) > 0 { for _, mutation := range request.Mutations { - err := mutation(nil, horizontalPodAutoscaler, request.Client) + err := mutation(request.Instance, horizontalPodAutoscaler, request.Client, request.MutationArgs, request.MutationArgs) if err != nil { mutationErr = err } diff --git a/pkg/workloads/secret.go b/pkg/workloads/secret.go index 2ca52c719..82e663b89 100644 --- a/pkg/workloads/secret.go +++ b/pkg/workloads/secret.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" + argoproj "github.com/argoproj-labs/argocd-operator/api/v1beta1" "github.com/argoproj-labs/argocd-operator/pkg/mutation" "github.com/argoproj-labs/argocd-operator/pkg/resource" @@ -18,10 +19,13 @@ type SecretRequest struct { Data map[string][]byte StringData map[string]string Type corev1.SecretType + Instance *argoproj.ArgoCD - // array of functions to mutate role before returning to requester + // array of functions to mutate obj before returning to requester Mutations []mutation.MutateFunc - Client cntrlClient.Client + // array of arguments to pass to the mutation funcs + MutationArgs []interface{} + Client cntrlClient.Client } // newSecret returns a new Secret instance for the given ArgoCD. @@ -42,7 +46,7 @@ func RequestSecret(request SecretRequest) (*corev1.Secret, error) { if len(request.Mutations) > 0 { for _, mutation := range request.Mutations { - err := mutation(nil, secret, request.Client) + err := mutation(request.Instance, secret, request.Client, request.MutationArgs) if err != nil { mutationErr = err } diff --git a/pkg/workloads/statefulset.go b/pkg/workloads/statefulset.go index e1c389430..3cb0322f4 100644 --- a/pkg/workloads/statefulset.go +++ b/pkg/workloads/statefulset.go @@ -8,6 +8,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" cntrlClient "sigs.k8s.io/controller-runtime/pkg/client" + argoproj "github.com/argoproj-labs/argocd-operator/api/v1beta1" "github.com/argoproj-labs/argocd-operator/pkg/mutation" "github.com/argoproj-labs/argocd-operator/pkg/resource" ) @@ -16,9 +17,13 @@ import ( type StatefulSetRequest struct { ObjectMeta metav1.ObjectMeta Spec appsv1.StatefulSetSpec - // array of functions to mutate role before returning to requester + Instance *argoproj.ArgoCD + + // array of functions to mutate obj before returning to requester Mutations []mutation.MutateFunc - Client cntrlClient.Client + // array of arguments to pass to the mutation funcs + MutationArgs []interface{} + Client cntrlClient.Client } // newStateful returns a new Stateful instance for the given ArgoCD. @@ -38,7 +43,7 @@ func RequestStatefulSet(request StatefulSetRequest) (*appsv1.StatefulSet, error) if len(request.Mutations) > 0 { for _, mutation := range request.Mutations { - err := mutation(nil, StatefulSet, request.Client) + err := mutation(request.Instance, StatefulSet, request.Client, request.MutationArgs, request.MutationArgs) if err != nil { mutationErr = err } diff --git a/pkg/workloads/workloads_test.go b/pkg/workloads/workloads_test.go index fe9a50ed7..ff378ab8b 100644 --- a/pkg/workloads/workloads_test.go +++ b/pkg/workloads/workloads_test.go @@ -33,11 +33,11 @@ var ( } ) -func testMutationFuncFailed(cr *argoproj.ArgoCD, resource interface{}, client cntrlClient.Client) error { +func testMutationFuncFailed(cr *argoproj.ArgoCD, resource interface{}, client cntrlClient.Client, args ...interface{}) error { return errors.New("test-mutation-error") } -func testMutationFuncSuccessful(cr *argoproj.ArgoCD, resource interface{}, client cntrlClient.Client) error { +func testMutationFuncSuccessful(cr *argoproj.ArgoCD, resource interface{}, client cntrlClient.Client, args ...interface{}) error { switch obj := resource.(type) { case *appsv1.Deployment: obj.Name = testNameMutated