Repository: argoproj-labs/argocd-operator
Pull request #747 (2022-08-01 10:10:04)

feat: add default nodeSelector for linux in workloads
Signed-off-by: saumeya <saumeyakatyal@gmail.com>

**What type of PR is this?**
 /kind enhancement

**What does this PR do / why we need it**:
This PR adds default nodeSelector for running argoCD pod only on Linux nodes.

**Have you updated the necessary documentation?**

* [ ] Documentation update is required by this PR.
* [ ] Documentation has been updated.

**Which issue(s) this PR fixes**:

Fixes #?

**How to test changes / Special notes to the reviewer**:
```make install run``` , check the nodeSelectors added to the deployments by default.


Patch:
diff --git a/OWNERS b/OWNERS
index 529d5a55..c205cd16 100644
--- a/OWNERS
+++ b/OWNERS
@@ -2,5 +2,15 @@ owners:
 - jomkz
 
 approvers:
+- iam-veeramalla
+- wtam2018
+- jannfis
+- jopit
 
 reviewers:
+- iam-veeramalla
+- wtam2018
+- jannfis
+- jopit
+- jaideepr97
+- ishitasequeira 
diff --git a/api/v1alpha1/argocd_types.go b/api/v1alpha1/argocd_types.go
index c84d9790..01b54be6 100644
--- a/api/v1alpha1/argocd_types.go
+++ b/api/v1alpha1/argocd_types.go
@@ -131,6 +131,8 @@ type ArgoCDApplicationSet struct {
 
 	// LogLevel describes the log level that should be used by the ApplicationSet controller. Defaults to ArgoCDDefaultLogLevel if not set.  Valid options are debug,info, error, and warn.
 	LogLevel string `json:"logLevel,omitempty"`
+
+	WebhookServer WebhookServerSpec `json:"webhookServer,omitempty"`
 }
 
 // ArgoCDCASpec defines the CA options for ArgCD.
@@ -352,6 +354,10 @@ type ArgoCDRBACSpec struct {
 	// If omitted, defaults to: '[groups]'.
 	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Scopes",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:fieldGroup:RBAC","urn:alm:descriptor:com.tectonic.ui:text"}
 	Scopes *string `json:"scopes,omitempty"`
+
+	// PolicyMatcherMode configures the matchers function mode for casbin.
+	// There are two options for this, 'glob' for glob matcher or 'regex' for regex matcher.
+	PolicyMatcherMode *string `json:"policyMatcherMode,omitempty"`
 }
 
 // ArgoCDRedisSpec defines the desired state for the Redis server component.
@@ -830,6 +836,20 @@ type SSHHostsSpec struct {
 	Keys string `json:"keys,omitempty"`
 }
 
+// WebhookServerSpec defines the options for the ApplicationSet Webhook Server component.
+type WebhookServerSpec struct {
+
+	// Host is the hostname to use for Ingress/Route resources.
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Host",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:fieldGroup:Server","urn:alm:descriptor:com.tectonic.ui:text"}
+	Host string `json:"host,omitempty"`
+
+	// Ingress defines the desired state for an Ingress for the Application set webhook component.
+	Ingress ArgoCDIngressSpec `json:"ingress,omitempty"`
+
+	// Route defines the desired state for an OpenShift Route for the Application set webhook component.
+	Route ArgoCDRouteSpec `json:"route,omitempty"`
+}
+
 // IsDeletionFinalizerPresent checks if the instance has deletion finalizer
 func (argocd *ArgoCD) IsDeletionFinalizerPresent() bool {
 	for _, finalizer := range argocd.GetFinalizers() {
diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go
index fd62289c..d946dcd9 100644
--- a/api/v1alpha1/zz_generated.deepcopy.go
+++ b/api/v1alpha1/zz_generated.deepcopy.go
@@ -129,6 +129,7 @@ func (in *ArgoCDApplicationSet) DeepCopyInto(out *ArgoCDApplicationSet) {
 		*out = new(v1.ResourceRequirements)
 		(*in).DeepCopyInto(*out)
 	}
+	in.WebhookServer.DeepCopyInto(&out.WebhookServer)
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ArgoCDApplicationSet.
@@ -582,6 +583,11 @@ func (in *ArgoCDRBACSpec) DeepCopyInto(out *ArgoCDRBACSpec) {
 		*out = new(string)
 		**out = **in
 	}
+	if in.PolicyMatcherMode != nil {
+		in, out := &in.PolicyMatcherMode, &out.PolicyMatcherMode
+		*out = new(string)
+		**out = **in
+	}
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ArgoCDRBACSpec.
@@ -996,3 +1002,20 @@ func (in *SSHHostsSpec) DeepCopy() *SSHHostsSpec {
 	in.DeepCopyInto(out)
 	return out
 }
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *WebhookServerSpec) DeepCopyInto(out *WebhookServerSpec) {
+	*out = *in
+	in.Ingress.DeepCopyInto(&out.Ingress)
+	in.Route.DeepCopyInto(&out.Route)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WebhookServerSpec.
+func (in *WebhookServerSpec) DeepCopy() *WebhookServerSpec {
+	if in == nil {
+		return nil
+	}
+	out := new(WebhookServerSpec)
+	in.DeepCopyInto(out)
+	return out
+}
diff --git a/bundle/manifests/argocd-operator-controller-manager-metrics-service_v1_service.yaml b/bundle/manifests/argocd-operator-controller-manager-metrics-service_v1_service.yaml
index f800102e..e7da1c70 100644
--- a/bundle/manifests/argocd-operator-controller-manager-metrics-service_v1_service.yaml
+++ b/bundle/manifests/argocd-operator-controller-manager-metrics-service_v1_service.yaml
@@ -3,7 +3,7 @@ kind: Service
 metadata:
   creationTimestamp: null
   labels:
-    control-plane: controller-manager
+    control-plane: argocd-operator
   name: argocd-operator-controller-manager-metrics-service
 spec:
   ports:
@@ -11,6 +11,6 @@ spec:
     port: 8443
     targetPort: https
   selector:
-    control-plane: controller-manager
+    control-plane: argocd-operator
 status:
   loadBalancer: {}
diff --git a/bundle/manifests/argocd-operator.clusterserviceversion.yaml b/bundle/manifests/argocd-operator.clusterserviceversion.yaml
index 17736163..59fb1b2a 100644
--- a/bundle/manifests/argocd-operator.clusterserviceversion.yaml
+++ b/bundle/manifests/argocd-operator.clusterserviceversion.yaml
@@ -301,6 +301,28 @@ spec:
         x-descriptors:
         - urn:alm:descriptor:com.tectonic.ui:text
         - urn:alm:descriptor:com.tectonic.ui:advanced
+      - description: Host is the hostname to use for Ingress/Route resources.
+        displayName: Host
+        path: applicationSet.webhookServer.host
+        x-descriptors:
+        - urn:alm:descriptor:com.tectonic.ui:fieldGroup:Server
+        - urn:alm:descriptor:com.tectonic.ui:text
+      - description: Enabled will toggle the creation of the Ingress.
+        displayName: Ingress Enabled'
+        path: applicationSet.webhookServer.ingress.enabled
+        x-descriptors:
+        - urn:alm:descriptor:com.tectonic.ui:fieldGroup:Grafana
+        - urn:alm:descriptor:com.tectonic.ui:fieldGroup:Prometheus
+        - urn:alm:descriptor:com.tectonic.ui:fieldGroup:Server
+        - urn:alm:descriptor:com.tectonic.ui:booleanSwitch
+      - description: Enabled will toggle the creation of the OpenShift Route.
+        displayName: Route Enabled'
+        path: applicationSet.webhookServer.route.enabled
+        x-descriptors:
+        - urn:alm:descriptor:com.tectonic.ui:fieldGroup:Grafana
+        - urn:alm:descriptor:com.tectonic.ui:fieldGroup:Prometheus
+        - urn:alm:descriptor:com.tectonic.ui:fieldGroup:Server
+        - urn:alm:descriptor:com.tectonic.ui:booleanSwitch
       - description: ConfigManagementPlugins is used to specify additional config
           management plugins.
         displayName: Config Management Plugins'
@@ -1019,12 +1041,12 @@ spec:
           replicas: 1
           selector:
             matchLabels:
-              control-plane: controller-manager
+              control-plane: argocd-operator
           strategy: {}
           template:
             metadata:
               labels:
-                control-plane: controller-manager
+                control-plane: argocd-operator
             spec:
               containers:
               - args:
diff --git a/bundle/manifests/argoproj.io_argocds.yaml b/bundle/manifests/argoproj.io_argocds.yaml
index 0e6e1618..b8979d76 100644
--- a/bundle/manifests/argoproj.io_argocds.yaml
+++ b/bundle/manifests/argoproj.io_argocds.yaml
@@ -81,6 +81,142 @@ spec:
                     description: Version is the Argo CD ApplicationSet image tag.
                       (optional)
                     type: string
+                  webhookServer:
+                    description: WebhookServerSpec defines the options for the ApplicationSet
+                      Webhook Server component.
+                    properties:
+                      host:
+                        description: Host is the hostname to use for Ingress/Route
+                          resources.
+                        type: string
+                      ingress:
+                        description: Ingress defines the desired state for an Ingress
+                          for the Application set webhook component.
+                        properties:
+                          annotations:
+                            additionalProperties:
+                              type: string
+                            description: Annotations is the map of annotations to
+                              apply to the Ingress.
+                            type: object
+                          enabled:
+                            description: Enabled will toggle the creation of the Ingress.
+                            type: boolean
+                          ingressClassName:
+                            description: IngressClassName for the Ingress resource.
+                            type: string
+                          path:
+                            description: Path used for the Ingress resource.
+                            type: string
+                          tls:
+                            description: TLS configuration. Currently the Ingress
+                              only supports a single TLS port, 443. If multiple members
+                              of this list specify different hosts, they will be multiplexed
+                              on the same port according to the hostname specified
+                              through the SNI TLS extension, if the ingress controller
+                              fulfilling the ingress supports SNI.
+                            items:
+                              description: IngressTLS describes the transport layer
+                                security associated with an Ingress.
+                              properties:
+                                hosts:
+                                  description: Hosts are a list of hosts included
+                                    in the TLS certificate. The values in this list
+                                    must match the name/s used in the tlsSecret. Defaults
+                                    to the wildcard host setting for the loadbalancer
+                                    controller fulfilling this Ingress, if left unspecified.
+                                  items:
+                                    type: string
+                                  type: array
+                                  x-kubernetes-list-type: atomic
+                                secretName:
+                                  description: SecretName is the name of the secret
+                                    used to terminate TLS traffic on port 443. Field
+                                    is left optional to allow TLS routing based on
+                                    SNI hostname alone. If the SNI host in a listener
+                                    conflicts with the "Host" header field used by
+                                    an IngressRule, the SNI host is used for termination
+                                    and value of the Host header is used for routing.
+                                  type: string
+                              type: object
+                            type: array
+                        required:
+                        - enabled
+                        type: object
+                      route:
+                        description: Route defines the desired state for an OpenShift
+                          Route for the Application set webhook component.
+                        properties:
+                          annotations:
+                            additionalProperties:
+                              type: string
+                            description: Annotations is the map of annotations to
+                              use for the Route resource.
+                            type: object
+                          enabled:
+                            description: Enabled will toggle the creation of the OpenShift
+                              Route.
+                            type: boolean
+                          labels:
+                            additionalProperties:
+                              type: string
+                            description: Labels is the map of labels to use for the
+                              Route resource
+                            type: object
+                          path:
+                            description: Path the router watches for, to route traffic
+                              for to the service.
+                            type: string
+                          tls:
+                            description: TLS provides the ability to configure certificates
+                              and termination for the Route.
+                            properties:
+                              caCertificate:
+                                description: caCertificate provides the cert authority
+                                  certificate contents
+                                type: string
+                              certificate:
+                                description: certificate provides certificate contents
+                                type: string
+                              destinationCACertificate:
+                                description: destinationCACertificate provides the
+                                  contents of the ca certificate of the final destination.  When
+                                  using reencrypt termination this file should be
+                                  provided in order to have routers use it for health
+                                  checks on the secure connection. If this field is
+                                  not specified, the router may provide its own destination
+                                  CA and perform hostname validation using the short
+                                  service name (service.namespace.svc), which allows
+                                  infrastructure generated certificates to automatically
+                                  verify.
+                                type: string
+                              insecureEdgeTerminationPolicy:
+                                description: "insecureEdgeTerminationPolicy indicates
+                                  the desired behavior for insecure connections to
+                                  a route. While each router may make its own decisions
+                                  on which ports to expose, this is normally port
+                                  80. \n * Allow - traffic is sent to the server on
+                                  the insecure port (default) * Disable - no traffic
+                                  is allowed on the insecure port. * Redirect - clients
+                                  are redirected to the secure port."
+                                type: string
+                              key:
+                                description: key provides key file contents
+                                type: string
+                              termination:
+                                description: termination indicates termination type.
+                                type: string
+                            required:
+                            - termination
+                            type: object
+                          wildcardPolicy:
+                            description: WildcardPolicy if any for the route. Currently
+                              only 'Subdomain' or 'None' is allowed.
+                            type: string
+                        required:
+                        - enabled
+                        type: object
+                    type: object
                 type: object
               banner:
                 description: Banner defines an additional banner to be displayed in
@@ -917,6 +1053,11 @@ spec:
                       are in the form:   g, subject, inherited-subject See https://github.com/argoproj/argo-cd/blob/master/docs/operator-manual/rbac.md
                       for additional information.'
                     type: string
+                  policyMatcherMode:
+                    description: PolicyMatcherMode configures the matchers function
+                      mode for casbin. There are two options for this, 'glob' for
+                      glob matcher or 'regex' for regex matcher.
+                    type: string
                   scopes:
                     description: 'Scopes controls which OIDC scopes to examine during
                       rbac enforcement (in addition to `sub` scope). If omitted, defaults
diff --git a/common/defaults.go b/common/defaults.go
index ec60020a..69bda900 100644
--- a/common/defaults.go
+++ b/common/defaults.go
@@ -315,3 +315,10 @@ func DefaultAnnotations(name string, namespace string) map[string]string {
 		AnnotationNamespace: namespace,
 	}
 }
+
+// DefaultNodeSelector returns the defult nodeSelector for ArgoCD workloads
+func DefaultNodeSelector() map[string]string {
+	return map[string]string{
+		"kubernetes.io/os": "linux",
+	}
+}
diff --git a/common/keys.go b/common/keys.go
index 64f7dcee..6b12a32d 100644
--- a/common/keys.go
+++ b/common/keys.go
@@ -170,6 +170,10 @@ const (
 	// ArgoCDKeyTLSPrivateKey is the key for TLS private keys.
 	ArgoCDKeyTLSPrivateKey = corev1.TLSPrivateKeyKey
 
+	// 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"
+
 	// ArgoCDKeyTolerateUnreadyEndpounts is the resource tolerate unready endpoints key for labels.
 	ArgoCDKeyTolerateUnreadyEndpounts = "service.alpha.kubernetes.io/tolerate-unready-endpoints"
 
diff --git a/common/values.go b/common/values.go
index 1613c255..da670791 100644
--- a/common/values.go
+++ b/common/values.go
@@ -85,4 +85,7 @@ const (
 
 	// ArgoCDServerTLSSecretName is the name of the TLS secret for the argocd-server
 	ArgoCDServerTLSSecretName = "argocd-server-tls"
+
+	//ApplicationSetServiceNameSuffix is the suffix for Apllication Set Controller Service
+	ApplicationSetServiceNameSuffix = "applicationset-controller"
 )
diff --git a/config/crd/bases/argoproj.io_argocds.yaml b/config/crd/bases/argoproj.io_argocds.yaml
index 22da49a7..a733dfcb 100644
--- a/config/crd/bases/argoproj.io_argocds.yaml
+++ b/config/crd/bases/argoproj.io_argocds.yaml
@@ -83,6 +83,142 @@ spec:
                     description: Version is the Argo CD ApplicationSet image tag.
                       (optional)
                     type: string
+                  webhookServer:
+                    description: WebhookServerSpec defines the options for the ApplicationSet
+                      Webhook Server component.
+                    properties:
+                      host:
+                        description: Host is the hostname to use for Ingress/Route
+                          resources.
+                        type: string
+                      ingress:
+                        description: Ingress defines the desired state for an Ingress
+                          for the Application set webhook component.
+                        properties:
+                          annotations:
+                            additionalProperties:
+                              type: string
+                            description: Annotations is the map of annotations to
+                              apply to the Ingress.
+                            type: object
+                          enabled:
+                            description: Enabled will toggle the creation of the Ingress.
+                            type: boolean
+                          ingressClassName:
+                            description: IngressClassName for the Ingress resource.
+                            type: string
+                          path:
+                            description: Path used for the Ingress resource.
+                            type: string
+                          tls:
+                            description: TLS configuration. Currently the Ingress
+                              only supports a single TLS port, 443. If multiple members
+                              of this list specify different hosts, they will be multiplexed
+                              on the same port according to the hostname specified
+                              through the SNI TLS extension, if the ingress controller
+                              fulfilling the ingress supports SNI.
+                            items:
+                              description: IngressTLS describes the transport layer
+                                security associated with an Ingress.
+                              properties:
+                                hosts:
+                                  description: Hosts are a list of hosts included
+                                    in the TLS certificate. The values in this list
+                                    must match the name/s used in the tlsSecret. Defaults
+                                    to the wildcard host setting for the loadbalancer
+                                    controller fulfilling this Ingress, if left unspecified.
+                                  items:
+                                    type: string
+                                  type: array
+                                  x-kubernetes-list-type: atomic
+                                secretName:
+                                  description: SecretName is the name of the secret
+                                    used to terminate TLS traffic on port 443. Field
+                                    is left optional to allow TLS routing based on
+                                    SNI hostname alone. If the SNI host in a listener
+                                    conflicts with the "Host" header field used by
+                                    an IngressRule, the SNI host is used for termination
+                                    and value of the Host header is used for routing.
+                                  type: string
+                              type: object
+                            type: array
+                        required:
+                        - enabled
+                        type: object
+                      route:
+                        description: Route defines the desired state for an OpenShift
+                          Route for the Application set webhook component.
+                        properties:
+                          annotations:
+                            additionalProperties:
+                              type: string
+                            description: Annotations is the map of annotations to
+                              use for the Route resource.
+                            type: object
+                          enabled:
+                            description: Enabled will toggle the creation of the OpenShift
+                              Route.
+                            type: boolean
+                          labels:
+                            additionalProperties:
+                              type: string
+                            description: Labels is the map of labels to use for the
+                              Route resource
+                            type: object
+                          path:
+                            description: Path the router watches for, to route traffic
+                              for to the service.
+                            type: string
+                          tls:
+                            description: TLS provides the ability to configure certificates
+                              and termination for the Route.
+                            properties:
+                              caCertificate:
+                                description: caCertificate provides the cert authority
+                                  certificate contents
+                                type: string
+                              certificate:
+                                description: certificate provides certificate contents
+                                type: string
+                              destinationCACertificate:
+                                description: destinationCACertificate provides the
+                                  contents of the ca certificate of the final destination.  When
+                                  using reencrypt termination this file should be
+                                  provided in order to have routers use it for health
+                                  checks on the secure connection. If this field is
+                                  not specified, the router may provide its own destination
+                                  CA and perform hostname validation using the short
+                                  service name (service.namespace.svc), which allows
+                                  infrastructure generated certificates to automatically
+                                  verify.
+                                type: string
+                              insecureEdgeTerminationPolicy:
+                                description: "insecureEdgeTerminationPolicy indicates
+                                  the desired behavior for insecure connections to
+                                  a route. While each router may make its own decisions
+                                  on which ports to expose, this is normally port
+                                  80. \n * Allow - traffic is sent to the server on
+                                  the insecure port (default) * Disable - no traffic
+                                  is allowed on the insecure port. * Redirect - clients
+                                  are redirected to the secure port."
+                                type: string
+                              key:
+                                description: key provides key file contents
+                                type: string
+                              termination:
+                                description: termination indicates termination type.
+                                type: string
+                            required:
+                            - termination
+                            type: object
+                          wildcardPolicy:
+                            description: WildcardPolicy if any for the route. Currently
+                              only 'Subdomain' or 'None' is allowed.
+                            type: string
+                        required:
+                        - enabled
+                        type: object
+                    type: object
                 type: object
               banner:
                 description: Banner defines an additional banner to be displayed in
@@ -919,6 +1055,11 @@ spec:
                       are in the form:   g, subject, inherited-subject See https://github.com/argoproj/argo-cd/blob/master/docs/operator-manual/rbac.md
                       for additional information.'
                     type: string
+                  policyMatcherMode:
+                    description: PolicyMatcherMode configures the matchers function
+                      mode for casbin. There are two options for this, 'glob' for
+                      glob matcher or 'regex' for regex matcher.
+                    type: string
                   scopes:
                     description: 'Scopes controls which OIDC scopes to examine during
                       rbac enforcement (in addition to `sub` scope). If omitted, defaults
diff --git a/config/manager/manager.yaml b/config/manager/manager.yaml
index cc42d89c..7190e112 100644
--- a/config/manager/manager.yaml
+++ b/config/manager/manager.yaml
@@ -2,7 +2,7 @@ apiVersion: v1
 kind: Namespace
 metadata:
   labels:
-    control-plane: controller-manager
+    control-plane: argocd-operator
   name: system
 ---
 apiVersion: apps/v1
@@ -11,16 +11,16 @@ metadata:
   name: controller-manager
   namespace: system
   labels:
-    control-plane: controller-manager
+    control-plane: argocd-operator
 spec:
   selector:
     matchLabels:
-      control-plane: controller-manager
+      control-plane: argocd-operator
   replicas: 1
   template:
     metadata:
       labels:
-        control-plane: controller-manager
+        control-plane: argocd-operator
     spec:
       securityContext:
         runAsNonRoot: true
diff --git a/config/manifests/bases/argocd-operator.clusterserviceversion.yaml b/config/manifests/bases/argocd-operator.clusterserviceversion.yaml
index 34034767..88db44a0 100644
--- a/config/manifests/bases/argocd-operator.clusterserviceversion.yaml
+++ b/config/manifests/bases/argocd-operator.clusterserviceversion.yaml
@@ -175,6 +175,28 @@ spec:
         x-descriptors:
         - urn:alm:descriptor:com.tectonic.ui:text
         - urn:alm:descriptor:com.tectonic.ui:advanced
+      - description: Host is the hostname to use for Ingress/Route resources.
+        displayName: Host
+        path: applicationSet.webhookServer.host
+        x-descriptors:
+        - urn:alm:descriptor:com.tectonic.ui:fieldGroup:Server
+        - urn:alm:descriptor:com.tectonic.ui:text
+      - description: Enabled will toggle the creation of the Ingress.
+        displayName: Ingress Enabled'
+        path: applicationSet.webhookServer.ingress.enabled
+        x-descriptors:
+        - urn:alm:descriptor:com.tectonic.ui:fieldGroup:Grafana
+        - urn:alm:descriptor:com.tectonic.ui:fieldGroup:Prometheus
+        - urn:alm:descriptor:com.tectonic.ui:fieldGroup:Server
+        - urn:alm:descriptor:com.tectonic.ui:booleanSwitch
+      - description: Enabled will toggle the creation of the OpenShift Route.
+        displayName: Route Enabled'
+        path: applicationSet.webhookServer.route.enabled
+        x-descriptors:
+        - urn:alm:descriptor:com.tectonic.ui:fieldGroup:Grafana
+        - urn:alm:descriptor:com.tectonic.ui:fieldGroup:Prometheus
+        - urn:alm:descriptor:com.tectonic.ui:fieldGroup:Server
+        - urn:alm:descriptor:com.tectonic.ui:booleanSwitch
       - description: ConfigManagementPlugins is used to specify additional config
           management plugins.
         displayName: Config Management Plugins'
diff --git a/config/prometheus/monitor.yaml b/config/prometheus/monitor.yaml
index d19136ae..dd2aaaed 100644
--- a/config/prometheus/monitor.yaml
+++ b/config/prometheus/monitor.yaml
@@ -4,7 +4,7 @@ apiVersion: monitoring.coreos.com/v1
 kind: ServiceMonitor
 metadata:
   labels:
-    control-plane: controller-manager
+    control-plane: argocd-operator
   name: controller-manager-metrics-monitor
   namespace: system
 spec:
@@ -17,4 +17,4 @@ spec:
         insecureSkipVerify: true
   selector:
     matchLabels:
-      control-plane: controller-manager
+      control-plane: argocd-operator
diff --git a/config/rbac/auth_proxy_service.yaml b/config/rbac/auth_proxy_service.yaml
index 6cf656be..7e367547 100644
--- a/config/rbac/auth_proxy_service.yaml
+++ b/config/rbac/auth_proxy_service.yaml
@@ -2,7 +2,7 @@ apiVersion: v1
 kind: Service
 metadata:
   labels:
-    control-plane: controller-manager
+    control-plane: argocd-operator
   name: controller-manager-metrics-service
   namespace: system
 spec:
@@ -11,4 +11,4 @@ spec:
     port: 8443
     targetPort: https
   selector:
-    control-plane: controller-manager
+    control-plane: argocd-operator
diff --git a/controllers/argocd/applicationset.go b/controllers/argocd/applicationset.go
index f1daa4fe..a9beecf5 100644
--- a/controllers/argocd/applicationset.go
+++ b/controllers/argocd/applicationset.go
@@ -25,6 +25,7 @@ import (
 	"k8s.io/apimachinery/pkg/api/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/types"
+	"k8s.io/apimachinery/pkg/util/intstr"
 	"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
 
 	argoprojv1a1 "github.com/argoproj-labs/argocd-operator/api/v1alpha1"
@@ -72,6 +73,11 @@ func (r *ReconcileArgoCD) reconcileApplicationSetController(cr *argoprojv1a1.Arg
 		return err
 	}
 
+	log.Info("reconciling applicationset service")
+	if err := r.reconcileApplicationSetService(cr); err != nil {
+		return err
+	}
+
 	return nil
 }
 
@@ -455,3 +461,50 @@ func setAppSetLabels(obj *metav1.ObjectMeta) {
 	obj.Labels["app.kubernetes.io/part-of"] = "argocd-applicationset"
 	obj.Labels["app.kubernetes.io/component"] = "controller"
 }
+
+// reconcileApplicationSetService will ensure that the Service is present for the ApplicationSet webhook and metrics component.
+func (r *ReconcileArgoCD) reconcileApplicationSetService(cr *argoprojv1a1.ArgoCD) error {
+	log.Info("reconciling applicationset service")
+
+	svc := newServiceWithSuffix(common.ApplicationSetServiceNameSuffix, common.ApplicationSetServiceNameSuffix, cr)
+	if cr.Spec.ApplicationSet == nil {
+
+		if argoutil.IsObjectFound(r.Client, cr.Namespace, svc.Name, svc) {
+			err := argoutil.FetchObject(r.Client, cr.Namespace, svc.Name, svc)
+			if err != nil {
+				return err
+			}
+			log.Info(fmt.Sprintf("Deleting applicationset controller service %s as applicationset is disabled", svc.Name))
+			err = r.Delete(context.TODO(), svc)
+			if err != nil {
+				return err
+			}
+		}
+	} else {
+		if argoutil.IsObjectFound(r.Client, cr.Namespace, svc.Name, svc) {
+			return nil // Service found, do nothing
+		}
+	}
+	svc.Spec.Ports = []corev1.ServicePort{
+		{
+			Name:       "webhook",
+			Port:       7000,
+			Protocol:   corev1.ProtocolTCP,
+			TargetPort: intstr.FromInt(7000),
+		}, {
+			Name:       "metrics",
+			Port:       8080,
+			Protocol:   corev1.ProtocolTCP,
+			TargetPort: intstr.FromInt(8080),
+		},
+	}
+
+	svc.Spec.Selector = map[string]string{
+		common.ArgoCDKeyName: nameWithSuffix(common.ApplicationSetServiceNameSuffix, cr),
+	}
+
+	if err := controllerutil.SetControllerReference(cr, svc, r.Scheme); err != nil {
+		return err
+	}
+	return r.Client.Create(context.TODO(), svc)
+}
diff --git a/controllers/argocd/configmap.go b/controllers/argocd/configmap.go
index ce8cc908..a59dceb1 100644
--- a/controllers/argocd/configmap.go
+++ b/controllers/argocd/configmap.go
@@ -509,6 +509,12 @@ func (r *ReconcileArgoCD) reconcileRBACConfigMap(cm *corev1.ConfigMap, cr *argop
 		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
diff --git a/controllers/argocd/deployment.go b/controllers/argocd/deployment.go
index 9ba3baee..b316ffae 100644
--- a/controllers/argocd/deployment.go
+++ b/controllers/argocd/deployment.go
@@ -372,11 +372,14 @@ func newDeploymentWithName(name string, component string, cr *argoprojv1a1.ArgoC
 					common.ArgoCDKeyName: name,
 				},
 			},
+			Spec: corev1.PodSpec{
+				NodeSelector: common.DefaultNodeSelector(),
+			},
 		},
 	}
 
 	if cr.Spec.NodePlacement != nil {
-		deploy.Spec.Template.Spec.NodeSelector = cr.Spec.NodePlacement.NodeSelector
+		deploy.Spec.Template.Spec.NodeSelector = argoutil.AppendStringMap(deploy.Spec.Template.Spec.NodeSelector, cr.Spec.NodePlacement.NodeSelector)
 		deploy.Spec.Template.Spec.Tolerations = cr.Spec.NodePlacement.Tolerations
 	}
 	return deploy
diff --git a/controllers/argocd/ingress.go b/controllers/argocd/ingress.go
index 903454ae..f28596b3 100644
--- a/controllers/argocd/ingress.go
+++ b/controllers/argocd/ingress.go
@@ -81,6 +81,11 @@ func (r *ReconcileArgoCD) reconcileIngresses(cr *argoprojv1a1.ArgoCD) error {
 	if err := r.reconcilePrometheusIngress(cr); err != nil {
 		return err
 	}
+
+	if err := r.reconcileApplicationSetControllerIngress(cr); err != nil {
+		return err
+	}
+
 	return nil
 }
 
@@ -385,3 +390,67 @@ func (r *ReconcileArgoCD) reconcilePrometheusIngress(cr *argoprojv1a1.ArgoCD) er
 	}
 	return r.Client.Create(context.TODO(), ingress)
 }
+
+// reconcileApplicationSetControllerIngress will ensure that the ApplicationSetController Ingress is present.
+func (r *ReconcileArgoCD) reconcileApplicationSetControllerIngress(cr *argoprojv1a1.ArgoCD) error {
+	ingress := newIngressWithSuffix(common.ApplicationSetServiceNameSuffix, cr)
+	if argoutil.IsObjectFound(r.Client, cr.Namespace, ingress.Name, ingress) {
+		if cr.Spec.ApplicationSet == nil || !cr.Spec.ApplicationSet.WebhookServer.Ingress.Enabled {
+			return r.Client.Delete(context.TODO(), ingress)
+		}
+		return nil // Ingress found and enabled, do nothing
+	}
+
+	if cr.Spec.ApplicationSet == nil || !cr.Spec.ApplicationSet.WebhookServer.Ingress.Enabled {
+		log.Info("not enabled")
+		return nil // Ingress not enabled, move along...
+	}
+
+	// Add annotations
+	atns := make(map[string]string)
+	atns[common.ArgoCDKeyIngressSSLRedirect] = "true"
+	atns[common.ArgoCDKeyIngressBackendProtocol] = "HTTP"
+
+	// Override default annotations if specified
+	if len(cr.Spec.ApplicationSet.WebhookServer.Ingress.Annotations) > 0 {
+		atns = cr.Spec.ApplicationSet.WebhookServer.Ingress.Annotations
+	}
+
+	ingress.ObjectMeta.Annotations = atns
+
+	pathType := networkingv1.PathTypeImplementationSpecific
+	// Add rules
+	ingress.Spec.Rules = []networkingv1.IngressRule{
+		{
+			Host: getApplicationSetHTTPServerHost(cr),
+			IngressRuleValue: networkingv1.IngressRuleValue{
+				HTTP: &networkingv1.HTTPIngressRuleValue{
+					Paths: []networkingv1.HTTPIngressPath{
+						{
+							Path: "/api/webhook",
+							Backend: networkingv1.IngressBackend{
+								Service: &networkingv1.IngressServiceBackend{
+									Name: nameWithSuffix(common.ApplicationSetServiceNameSuffix, cr),
+									Port: networkingv1.ServiceBackendPort{
+										Name: "webhook",
+									},
+								},
+							},
+							PathType: &pathType,
+						},
+					},
+				},
+			},
+		},
+	}
+
+	// Allow override of TLS options if specified
+	if len(cr.Spec.ApplicationSet.WebhookServer.Ingress.TLS) > 0 {
+		ingress.Spec.TLS = cr.Spec.ApplicationSet.WebhookServer.Ingress.TLS
+	}
+
+	if err := controllerutil.SetControllerReference(cr, ingress, r.Scheme); err != nil {
+		return err
+	}
+	return r.Client.Create(context.TODO(), ingress)
+}
diff --git a/controllers/argocd/keycloak.go b/controllers/argocd/keycloak.go
index 44798580..038a1647 100644
--- a/controllers/argocd/keycloak.go
+++ b/controllers/argocd/keycloak.go
@@ -407,6 +407,7 @@ func getKeycloakDeploymentConfigTemplate(cr *argoprojv1a1.ArgoCD) *appsv1.Deploy
 							},
 						},
 					},
+					NodeSelector: common.DefaultNodeSelector(),
 				},
 			},
 			Triggers: appsv1.DeploymentTriggerPolicies{
@@ -418,7 +419,7 @@ func getKeycloakDeploymentConfigTemplate(cr *argoprojv1a1.ArgoCD) *appsv1.Deploy
 	}
 
 	if cr.Spec.NodePlacement != nil {
-		dc.Spec.Template.Spec.NodeSelector = cr.Spec.NodePlacement.NodeSelector
+		dc.Spec.Template.Spec.NodeSelector = argoutil.AppendStringMap(dc.Spec.Template.Spec.NodeSelector, cr.Spec.NodePlacement.NodeSelector)
 		dc.Spec.Template.Spec.Tolerations = cr.Spec.NodePlacement.Tolerations
 	}
 
diff --git a/controllers/argocd/role.go b/controllers/argocd/role.go
index 1e7e1ce2..1874661e 100644
--- a/controllers/argocd/role.go
+++ b/controllers/argocd/role.go
@@ -78,6 +78,11 @@ func (r *ReconcileArgoCD) reconcileRole(name string, policyRules []v1.PolicyRule
 
 	// create policy rules for each namespace
 	for _, namespace := range r.ManagedNamespaces.Items {
+		// Skip terminating namespaces.
+		if namespace.DeletionTimestamp != nil {
+			continue
+		}
+
 		list := &argoprojv1a1.ArgoCDList{}
 		listOption := &client.ListOptions{Namespace: namespace.Name}
 		err := r.Client.List(context.TODO(), list, listOption)
diff --git a/controllers/argocd/rolebinding.go b/controllers/argocd/rolebinding.go
index a9ac988f..1c9f32df 100644
--- a/controllers/argocd/rolebinding.go
+++ b/controllers/argocd/rolebinding.go
@@ -95,6 +95,11 @@ func (r *ReconcileArgoCD) reconcileRoleBinding(name string, rules []v1.PolicyRul
 	}
 
 	for _, namespace := range r.ManagedNamespaces.Items {
+		// Skip terminating namespaces.
+		if namespace.DeletionTimestamp != nil {
+			continue
+		}
+
 		list := &argoprojv1a1.ArgoCDList{}
 		listOption := &client.ListOptions{Namespace: namespace.Name}
 		err := r.Client.List(context.TODO(), list, listOption)
diff --git a/controllers/argocd/route.go b/controllers/argocd/route.go
index 2a5ec957..70daa62e 100644
--- a/controllers/argocd/route.go
+++ b/controllers/argocd/route.go
@@ -86,6 +86,11 @@ func (r *ReconcileArgoCD) reconcileRoutes(cr *argoprojv1a1.ArgoCD) error {
 	if err := r.reconcileServerRoute(cr); err != nil {
 		return err
 	}
+
+	if err := r.reconcileApplicationSetControllerWebhookRoute(cr); err != nil {
+		return err
+	}
+
 	return nil
 }
 
@@ -284,3 +289,80 @@ func (r *ReconcileArgoCD) reconcileServerRoute(cr *argoprojv1a1.ArgoCD) error {
 	}
 	return r.Client.Update(context.TODO(), route)
 }
+
+// reconcileApplicationSetControllerWebhookRoute will ensure that the ArgoCD Server Route is present.
+func (r *ReconcileArgoCD) reconcileApplicationSetControllerWebhookRoute(cr *argoprojv1a1.ArgoCD) error {
+	name := fmt.Sprintf("%s-%s", common.ApplicationSetServiceNameSuffix, "webhook")
+	route := newRouteWithSuffix(name, cr)
+	found := argoutil.IsObjectFound(r.Client, cr.Namespace, route.Name, route)
+	if found {
+		if cr.Spec.ApplicationSet == nil || !cr.Spec.ApplicationSet.WebhookServer.Route.Enabled {
+			// Route exists but enabled flag has been set to false, delete the Route
+			return r.Client.Delete(context.TODO(), route)
+		}
+	}
+
+	if cr.Spec.ApplicationSet == nil || !cr.Spec.ApplicationSet.WebhookServer.Route.Enabled {
+		return nil // Route not enabled, move along...
+	}
+
+	// Allow override of the Annotations for the Route.
+	if len(cr.Spec.ApplicationSet.WebhookServer.Route.Annotations) > 0 {
+		route.Annotations = cr.Spec.Server.Route.Annotations
+	}
+
+	// Allow override of the Labels for the Route.
+	if len(cr.Spec.ApplicationSet.WebhookServer.Route.Labels) > 0 {
+		labels := route.Labels
+		for key, val := range cr.Spec.Server.Route.Labels {
+			labels[key] = val
+		}
+		route.Labels = labels
+	}
+
+	// Allow override of the Host for the Route.
+	if len(cr.Spec.Server.Host) > 0 {
+		route.Spec.Host = cr.Spec.ApplicationSet.WebhookServer.Host
+	}
+
+	if cr.Spec.Server.Insecure {
+		// Disable TLS and rely on the cluster certificate.
+		route.Spec.Port = &routev1.RoutePort{
+			TargetPort: intstr.FromString("webhook"),
+		}
+		route.Spec.TLS = &routev1.TLSConfig{
+			InsecureEdgeTerminationPolicy: routev1.InsecureEdgeTerminationPolicyRedirect,
+			Termination:                   routev1.TLSTerminationEdge,
+		}
+	} else {
+		// Server is using TLS configure passthrough.
+		route.Spec.Port = &routev1.RoutePort{
+			TargetPort: intstr.FromString("webhook"),
+		}
+		route.Spec.TLS = &routev1.TLSConfig{
+			InsecureEdgeTerminationPolicy: routev1.InsecureEdgeTerminationPolicyRedirect,
+			Termination:                   routev1.TLSTerminationPassthrough,
+		}
+	}
+
+	// Allow override of TLS options for the Route
+	if cr.Spec.Server.Route.TLS != nil {
+		route.Spec.TLS = cr.Spec.Server.Route.TLS
+	}
+
+	route.Spec.To.Kind = "Service"
+	route.Spec.To.Name = nameWithSuffix(common.ApplicationSetServiceNameSuffix, cr)
+
+	// Allow override of the WildcardPolicy for the Route
+	if cr.Spec.Server.Route.WildcardPolicy != nil && len(*cr.Spec.Server.Route.WildcardPolicy) > 0 {
+		route.Spec.WildcardPolicy = *cr.Spec.Server.Route.WildcardPolicy
+	}
+
+	if err := controllerutil.SetControllerReference(cr, route, r.Scheme); err != nil {
+		return err
+	}
+	if !found {
+		return r.Client.Create(context.TODO(), route)
+	}
+	return r.Client.Update(context.TODO(), route)
+}
diff --git a/controllers/argocd/statefulset.go b/controllers/argocd/statefulset.go
index f15003cb..1ccb7a29 100644
--- a/controllers/argocd/statefulset.go
+++ b/controllers/argocd/statefulset.go
@@ -71,10 +71,13 @@ func newStatefulSetWithName(name string, component string, cr *argoprojv1a1.Argo
 					common.ArgoCDKeyName: name,
 				},
 			},
+			Spec: corev1.PodSpec{
+				NodeSelector: common.DefaultNodeSelector(),
+			},
 		},
 	}
 	if cr.Spec.NodePlacement != nil {
-		ss.Spec.Template.Spec.NodeSelector = cr.Spec.NodePlacement.NodeSelector
+		ss.Spec.Template.Spec.NodeSelector = argoutil.AppendStringMap(ss.Spec.Template.Spec.NodeSelector, cr.Spec.NodePlacement.NodeSelector)
 		ss.Spec.Template.Spec.Tolerations = cr.Spec.NodePlacement.Tolerations
 	}
 	ss.Spec.ServiceName = name
diff --git a/controllers/argocd/util.go b/controllers/argocd/util.go
index 044be379..b49a434e 100644
--- a/controllers/argocd/util.go
+++ b/controllers/argocd/util.go
@@ -1476,3 +1476,12 @@ func contains(s []string, g string) bool {
 	}
 	return false
 }
+
+// getApplicationSetHTTPServerHost will return the host for the given ArgoCD.
+func getApplicationSetHTTPServerHost(cr *argoprojv1a1.ArgoCD) string {
+	host := cr.Name
+	if len(cr.Spec.ApplicationSet.WebhookServer.Host) > 0 {
+		host = cr.Spec.ApplicationSet.WebhookServer.Host
+	}
+	return host
+}
diff --git a/deploy/catalog_source.yaml b/deploy/catalog_source.yaml
deleted file mode 100644
index 59538e2f..00000000
--- a/deploy/catalog_source.yaml
+++ /dev/null
@@ -1,9 +0,0 @@
-apiVersion: operators.coreos.com/v1alpha1
-kind: CatalogSource
-metadata:
-  name: argocd-catalog
-spec:
-  sourceType: grpc
-  image: quay.io/argoprojlabs/argocd-operator-registry@sha256:becf932b398c1b89b6abb486b18725c3d408f7cce136d0d2784fd305b6ea41e2
-  displayName: Argo CD Operators
-  publisher: Argo CD Community
diff --git a/deploy/olm-catalog/argocd-operator/0.4.0/argocd-operator.v0.4.0.clusterserviceversion.yaml b/deploy/olm-catalog/argocd-operator/0.4.0/argocd-operator.v0.4.0.clusterserviceversion.yaml
index c5536cda..92f0ab6b 100644
--- a/deploy/olm-catalog/argocd-operator/0.4.0/argocd-operator.v0.4.0.clusterserviceversion.yaml
+++ b/deploy/olm-catalog/argocd-operator/0.4.0/argocd-operator.v0.4.0.clusterserviceversion.yaml
@@ -301,6 +301,28 @@ spec:
         x-descriptors:
         - urn:alm:descriptor:com.tectonic.ui:text
         - urn:alm:descriptor:com.tectonic.ui:advanced
+      - description: Host is the hostname to use for Ingress/Route resources.
+        displayName: Host
+        path: applicationSet.webhookServer.host
+        x-descriptors:
+        - urn:alm:descriptor:com.tectonic.ui:fieldGroup:Server
+        - urn:alm:descriptor:com.tectonic.ui:text
+      - description: Enabled will toggle the creation of the Ingress.
+        displayName: Ingress Enabled'
+        path: applicationSet.webhookServer.ingress.enabled
+        x-descriptors:
+        - urn:alm:descriptor:com.tectonic.ui:fieldGroup:Grafana
+        - urn:alm:descriptor:com.tectonic.ui:fieldGroup:Prometheus
+        - urn:alm:descriptor:com.tectonic.ui:fieldGroup:Server
+        - urn:alm:descriptor:com.tectonic.ui:booleanSwitch
+      - description: Enabled will toggle the creation of the OpenShift Route.
+        displayName: Route Enabled'
+        path: applicationSet.webhookServer.route.enabled
+        x-descriptors:
+        - urn:alm:descriptor:com.tectonic.ui:fieldGroup:Grafana
+        - urn:alm:descriptor:com.tectonic.ui:fieldGroup:Prometheus
+        - urn:alm:descriptor:com.tectonic.ui:fieldGroup:Server
+        - urn:alm:descriptor:com.tectonic.ui:booleanSwitch
       - description: ConfigManagementPlugins is used to specify additional config
           management plugins.
         displayName: Config Management Plugins'
diff --git a/deploy/olm-catalog/argocd-operator/0.4.0/argoproj.io_argocds.yaml b/deploy/olm-catalog/argocd-operator/0.4.0/argoproj.io_argocds.yaml
index 0e6e1618..d869c2ec 100644
--- a/deploy/olm-catalog/argocd-operator/0.4.0/argoproj.io_argocds.yaml
+++ b/deploy/olm-catalog/argocd-operator/0.4.0/argoproj.io_argocds.yaml
@@ -81,6 +81,139 @@ spec:
                     description: Version is the Argo CD ApplicationSet image tag.
                       (optional)
                     type: string
+                  webhookServer:
+                    description: WebhookServerSpec defines the options for the ApplicationSet
+                      Webhook Server component.
+                    properties:
+                      host:
+                        description: Host is the hostname to use for Ingress/Route
+                          resources.
+                        type: string
+                      ingress:
+                        description: Ingress defines the desired state for an Ingress
+                          for the Application set webhook component.
+                        properties:
+                          annotations:
+                            additionalProperties:
+                              type: string
+                            description: Annotations is the map of annotations to
+                              apply to the Ingress.
+                            type: object
+                          enabled:
+                            description: Enabled will toggle the creation of the Ingress.
+                            type: boolean
+                          path:
+                            description: Path used for the Ingress resource.
+                            type: string
+                          tls:
+                            description: TLS configuration. Currently the Ingress
+                              only supports a single TLS port, 443. If multiple members
+                              of this list specify different hosts, they will be multiplexed
+                              on the same port according to the hostname specified
+                              through the SNI TLS extension, if the ingress controller
+                              fulfilling the ingress supports SNI.
+                            items:
+                              description: IngressTLS describes the transport layer
+                                security associated with an Ingress.
+                              properties:
+                                hosts:
+                                  description: Hosts are a list of hosts included
+                                    in the TLS certificate. The values in this list
+                                    must match the name/s used in the tlsSecret. Defaults
+                                    to the wildcard host setting for the loadbalancer
+                                    controller fulfilling this Ingress, if left unspecified.
+                                  items:
+                                    type: string
+                                  type: array
+                                  x-kubernetes-list-type: atomic
+                                secretName:
+                                  description: SecretName is the name of the secret
+                                    used to terminate TLS traffic on port 443. Field
+                                    is left optional to allow TLS routing based on
+                                    SNI hostname alone. If the SNI host in a listener
+                                    conflicts with the "Host" header field used by
+                                    an IngressRule, the SNI host is used for termination
+                                    and value of the Host header is used for routing.
+                                  type: string
+                              type: object
+                            type: array
+                        required:
+                        - enabled
+                        type: object
+                      route:
+                        description: Route defines the desired state for an OpenShift
+                          Route for the Application set webhook component.
+                        properties:
+                          annotations:
+                            additionalProperties:
+                              type: string
+                            description: Annotations is the map of annotations to
+                              use for the Route resource.
+                            type: object
+                          enabled:
+                            description: Enabled will toggle the creation of the OpenShift
+                              Route.
+                            type: boolean
+                          labels:
+                            additionalProperties:
+                              type: string
+                            description: Labels is the map of labels to use for the
+                              Route resource
+                            type: object
+                          path:
+                            description: Path the router watches for, to route traffic
+                              for to the service.
+                            type: string
+                          tls:
+                            description: TLS provides the ability to configure certificates
+                              and termination for the Route.
+                            properties:
+                              caCertificate:
+                                description: caCertificate provides the cert authority
+                                  certificate contents
+                                type: string
+                              certificate:
+                                description: certificate provides certificate contents
+                                type: string
+                              destinationCACertificate:
+                                description: destinationCACertificate provides the
+                                  contents of the ca certificate of the final destination.  When
+                                  using reencrypt termination this file should be
+                                  provided in order to have routers use it for health
+                                  checks on the secure connection. If this field is
+                                  not specified, the router may provide its own destination
+                                  CA and perform hostname validation using the short
+                                  service name (service.namespace.svc), which allows
+                                  infrastructure generated certificates to automatically
+                                  verify.
+                                type: string
+                              insecureEdgeTerminationPolicy:
+                                description: "insecureEdgeTerminationPolicy indicates
+                                  the desired behavior for insecure connections to
+                                  a route. While each router may make its own decisions
+                                  on which ports to expose, this is normally port
+                                  80. \n * Allow - traffic is sent to the server on
+                                  the insecure port (default) * Disable - no traffic
+                                  is allowed on the insecure port. * Redirect - clients
+                                  are redirected to the secure port."
+                                type: string
+                              key:
+                                description: key provides key file contents
+                                type: string
+                              termination:
+                                description: termination indicates termination type.
+                                type: string
+                            required:
+                            - termination
+                            type: object
+                          wildcardPolicy:
+                            description: WildcardPolicy if any for the route. Currently
+                              only 'Subdomain' or 'None' is allowed.
+                            type: string
+                        required:
+                        - enabled
+                        type: object
+                    type: object
                 type: object
               banner:
                 description: Banner defines an additional banner to be displayed in
diff --git a/deploy/olm-catalog/argocd-operator/0.5.0/argocd-operator-controller-manager-metrics-service_v1_service.yaml b/deploy/olm-catalog/argocd-operator/0.5.0/argocd-operator-controller-manager-metrics-service_v1_service.yaml
index f800102e..e7da1c70 100644
--- a/deploy/olm-catalog/argocd-operator/0.5.0/argocd-operator-controller-manager-metrics-service_v1_service.yaml
+++ b/deploy/olm-catalog/argocd-operator/0.5.0/argocd-operator-controller-manager-metrics-service_v1_service.yaml
@@ -3,7 +3,7 @@ kind: Service
 metadata:
   creationTimestamp: null
   labels:
-    control-plane: controller-manager
+    control-plane: argocd-operator
   name: argocd-operator-controller-manager-metrics-service
 spec:
   ports:
@@ -11,6 +11,6 @@ spec:
     port: 8443
     targetPort: https
   selector:
-    control-plane: controller-manager
+    control-plane: argocd-operator
 status:
   loadBalancer: {}
diff --git a/deploy/olm-catalog/argocd-operator/0.5.0/argocd-operator.v0.5.0.clusterserviceversion.yaml b/deploy/olm-catalog/argocd-operator/0.5.0/argocd-operator.v0.5.0.clusterserviceversion.yaml
index 17736163..59fb1b2a 100644
--- a/deploy/olm-catalog/argocd-operator/0.5.0/argocd-operator.v0.5.0.clusterserviceversion.yaml
+++ b/deploy/olm-catalog/argocd-operator/0.5.0/argocd-operator.v0.5.0.clusterserviceversion.yaml
@@ -301,6 +301,28 @@ spec:
         x-descriptors:
         - urn:alm:descriptor:com.tectonic.ui:text
         - urn:alm:descriptor:com.tectonic.ui:advanced
+      - description: Host is the hostname to use for Ingress/Route resources.
+        displayName: Host
+        path: applicationSet.webhookServer.host
+        x-descriptors:
+        - urn:alm:descriptor:com.tectonic.ui:fieldGroup:Server
+        - urn:alm:descriptor:com.tectonic.ui:text
+      - description: Enabled will toggle the creation of the Ingress.
+        displayName: Ingress Enabled'
+        path: applicationSet.webhookServer.ingress.enabled
+        x-descriptors:
+        - urn:alm:descriptor:com.tectonic.ui:fieldGroup:Grafana
+        - urn:alm:descriptor:com.tectonic.ui:fieldGroup:Prometheus
+        - urn:alm:descriptor:com.tectonic.ui:fieldGroup:Server
+        - urn:alm:descriptor:com.tectonic.ui:booleanSwitch
+      - description: Enabled will toggle the creation of the OpenShift Route.
+        displayName: Route Enabled'
+        path: applicationSet.webhookServer.route.enabled
+        x-descriptors:
+        - urn:alm:descriptor:com.tectonic.ui:fieldGroup:Grafana
+        - urn:alm:descriptor:com.tectonic.ui:fieldGroup:Prometheus
+        - urn:alm:descriptor:com.tectonic.ui:fieldGroup:Server
+        - urn:alm:descriptor:com.tectonic.ui:booleanSwitch
       - description: ConfigManagementPlugins is used to specify additional config
           management plugins.
         displayName: Config Management Plugins'
@@ -1019,12 +1041,12 @@ spec:
           replicas: 1
           selector:
             matchLabels:
-              control-plane: controller-manager
+              control-plane: argocd-operator
           strategy: {}
           template:
             metadata:
               labels:
-                control-plane: controller-manager
+                control-plane: argocd-operator
             spec:
               containers:
               - args:
diff --git a/deploy/olm-catalog/argocd-operator/0.5.0/argoproj.io_argocds.yaml b/deploy/olm-catalog/argocd-operator/0.5.0/argoproj.io_argocds.yaml
index 0e6e1618..b8979d76 100644
--- a/deploy/olm-catalog/argocd-operator/0.5.0/argoproj.io_argocds.yaml
+++ b/deploy/olm-catalog/argocd-operator/0.5.0/argoproj.io_argocds.yaml
@@ -81,6 +81,142 @@ spec:
                     description: Version is the Argo CD ApplicationSet image tag.
                       (optional)
                     type: string
+                  webhookServer:
+                    description: WebhookServerSpec defines the options for the ApplicationSet
+                      Webhook Server component.
+                    properties:
+                      host:
+                        description: Host is the hostname to use for Ingress/Route
+                          resources.
+                        type: string
+                      ingress:
+                        description: Ingress defines the desired state for an Ingress
+                          for the Application set webhook component.
+                        properties:
+                          annotations:
+                            additionalProperties:
+                              type: string
+                            description: Annotations is the map of annotations to
+                              apply to the Ingress.
+                            type: object
+                          enabled:
+                            description: Enabled will toggle the creation of the Ingress.
+                            type: boolean
+                          ingressClassName:
+                            description: IngressClassName for the Ingress resource.
+                            type: string
+                          path:
+                            description: Path used for the Ingress resource.
+                            type: string
+                          tls:
+                            description: TLS configuration. Currently the Ingress
+                              only supports a single TLS port, 443. If multiple members
+                              of this list specify different hosts, they will be multiplexed
+                              on the same port according to the hostname specified
+                              through the SNI TLS extension, if the ingress controller
+                              fulfilling the ingress supports SNI.
+                            items:
+                              description: IngressTLS describes the transport layer
+                                security associated with an Ingress.
+                              properties:
+                                hosts:
+                                  description: Hosts are a list of hosts included
+                                    in the TLS certificate. The values in this list
+                                    must match the name/s used in the tlsSecret. Defaults
+                                    to the wildcard host setting for the loadbalancer
+                                    controller fulfilling this Ingress, if left unspecified.
+                                  items:
+                                    type: string
+                                  type: array
+                                  x-kubernetes-list-type: atomic
+                                secretName:
+                                  description: SecretName is the name of the secret
+                                    used to terminate TLS traffic on port 443. Field
+                                    is left optional to allow TLS routing based on
+                                    SNI hostname alone. If the SNI host in a listener
+                                    conflicts with the "Host" header field used by
+                                    an IngressRule, the SNI host is used for termination
+                                    and value of the Host header is used for routing.
+                                  type: string
+                              type: object
+                            type: array
+                        required:
+                        - enabled
+                        type: object
+                      route:
+                        description: Route defines the desired state for an OpenShift
+                          Route for the Application set webhook component.
+                        properties:
+                          annotations:
+                            additionalProperties:
+                              type: string
+                            description: Annotations is the map of annotations to
+                              use for the Route resource.
+                            type: object
+                          enabled:
+                            description: Enabled will toggle the creation of the OpenShift
+                              Route.
+                            type: boolean
+                          labels:
+                            additionalProperties:
+                              type: string
+                            description: Labels is the map of labels to use for the
+                              Route resource
+                            type: object
+                          path:
+                            description: Path the router watches for, to route traffic
+                              for to the service.
+                            type: string
+                          tls:
+                            description: TLS provides the ability to configure certificates
+                              and termination for the Route.
+                            properties:
+                              caCertificate:
+                                description: caCertificate provides the cert authority
+                                  certificate contents
+                                type: string
+                              certificate:
+                                description: certificate provides certificate contents
+                                type: string
+                              destinationCACertificate:
+                                description: destinationCACertificate provides the
+                                  contents of the ca certificate of the final destination.  When
+                                  using reencrypt termination this file should be
+                                  provided in order to have routers use it for health
+                                  checks on the secure connection. If this field is
+                                  not specified, the router may provide its own destination
+                                  CA and perform hostname validation using the short
+                                  service name (service.namespace.svc), which allows
+                                  infrastructure generated certificates to automatically
+                                  verify.
+                                type: string
+                              insecureEdgeTerminationPolicy:
+                                description: "insecureEdgeTerminationPolicy indicates
+                                  the desired behavior for insecure connections to
+                                  a route. While each router may make its own decisions
+                                  on which ports to expose, this is normally port
+                                  80. \n * Allow - traffic is sent to the server on
+                                  the insecure port (default) * Disable - no traffic
+                                  is allowed on the insecure port. * Redirect - clients
+                                  are redirected to the secure port."
+                                type: string
+                              key:
+                                description: key provides key file contents
+                                type: string
+                              termination:
+                                description: termination indicates termination type.
+                                type: string
+                            required:
+                            - termination
+                            type: object
+                          wildcardPolicy:
+                            description: WildcardPolicy if any for the route. Currently
+                              only 'Subdomain' or 'None' is allowed.
+                            type: string
+                        required:
+                        - enabled
+                        type: object
+                    type: object
                 type: object
               banner:
                 description: Banner defines an additional banner to be displayed in
@@ -917,6 +1053,11 @@ spec:
                       are in the form:   g, subject, inherited-subject See https://github.com/argoproj/argo-cd/blob/master/docs/operator-manual/rbac.md
                       for additional information.'
                     type: string
+                  policyMatcherMode:
+                    description: PolicyMatcherMode configures the matchers function
+                      mode for casbin. There are two options for this, 'glob' for
+                      glob matcher or 'regex' for regex matcher.
+                    type: string
                   scopes:
                     description: 'Scopes controls which OIDC scopes to examine during
                       rbac enforcement (in addition to `sub` scope). If omitted, defaults
diff --git a/docs/reference/argocd.md b/docs/reference/argocd.md
index 3ae542c0..3a7c61c5 100644
--- a/docs/reference/argocd.md
+++ b/docs/reference/argocd.md
@@ -75,7 +75,7 @@ The following properties are available for configuring the ApplicationSet contro
 
 Name | Default | Description
 --- | --- | ---
-Image | `quay.io/argocdapplicationset/argocd-applicationset` | The container image for the ApplicationSet controller. This overrides the `ARGOCD_APPLICATIONSET_IMAGE` environment variable.
+Image | `quay.io/argoproj/argocd-applicationset` | The container image for the ApplicationSet controller. This overrides the `ARGOCD_APPLICATIONSET_IMAGE` environment variable.
 Version | *(recent ApplicationSet version)* | The tag to use with the ApplicationSet container image.
 Resources | [Empty] | The container compute resources.
 LogLevel | info | The log level to be used by the ArgoCD Application Controller component. Valid options are debug, info, error, and warn.
@@ -842,6 +842,7 @@ Name | Default | Description
 --- | --- | ---
 DefaultPolicy | `role:readonly` | The `policy.default` property in the `argocd-rbac-cm` ConfigMap. The name of the default role which Argo CD will falls back to, when authorizing API requests.
 Policy | [Empty] | The `policy.csv` property in the `argocd-rbac-cm` ConfigMap. CSV data containing user-defined RBAC policies and role definitions.
+PolicyMatcherMode | `glob` | The `policy.matchMode` property in the `argocd-rbac-cm` ConfigMap. There are two options for this, 'glob' for glob matcher and 'regex' for regex matcher.
 Scopes | `[groups]` | The `scopes` property in the `argocd-rbac-cm` ConfigMap.  Controls which OIDC scopes to examine during rbac enforcement (in addition to `sub` scope).
 
 ### RBAC Example
@@ -858,6 +859,7 @@ metadata:
 spec:
   rbac:
     defaultPolicy: 'role:readonly'
+    policyMatcherMode: 'glob'
     policy: |
       g, system:cluster-admins, role:admin
     scopes: '[groups]'
diff --git a/go.mod b/go.mod
index 08df0655..914769cb 100644
--- a/go.mod
+++ b/go.mod
@@ -6,7 +6,7 @@ require (
 	github.com/argoproj/argo-cd/v2 v2.4.7
 	github.com/coreos/prometheus-operator v0.40.0
 	github.com/go-logr/logr v1.2.3
-	github.com/google/go-cmp v0.5.7
+	github.com/google/go-cmp v0.5.8
 	github.com/json-iterator/go v1.1.12
 	github.com/keycloak/keycloak-operator v0.0.0-20220104081708-ab17327be9e1
 	github.com/onsi/ginkgo v1.16.5
@@ -17,7 +17,7 @@ require (
 	github.com/pkg/errors v0.9.1
 	github.com/sethvargo/go-password v0.2.0
 	github.com/stretchr/testify v1.7.1
-	golang.org/x/mod v0.5.1-0.20210830214625-1b1db11ec8f4
+	golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3
 	gopkg.in/yaml.v2 v2.4.0
 	k8s.io/api v0.23.3
 	k8s.io/apimachinery v0.23.3
diff --git a/go.sum b/go.sum
index 1c0d0dad..6e577223 100644
--- a/go.sum
+++ b/go.sum
@@ -569,8 +569,8 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
 github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
-github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
+github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
+github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
 github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
 github.com/google/go-jsonnet v0.16.0/go.mod h1:sOcuej3UW1vpPTZOr8L7RQimqai1a57bt5j22LzGZCw=
 github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
@@ -1337,8 +1337,8 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.5.1-0.20210830214625-1b1db11ec8f4 h1:7Qds88gNaRx0Dz/1wOwXlR7asekh1B1u26wEwN6FcEI=
-golang.org/x/mod v0.5.1-0.20210830214625-1b1db11ec8f4/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
+golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o=
+golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -1669,7 +1669,6 @@ golang.org/x/tools v0.1.6-0.20210820212750-d4cc65f0b2ff/go.mod h1:YD9qOF0M9xpSpd
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 gomodules.xyz/jsonpatch/v2 v2.0.1/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU=
 gomodules.xyz/jsonpatch/v2 v2.2.0 h1:4pT439QV83L+G9FkcCriY6EkpcK6r6bK+A5FBUMI7qY=


Test patch:
diff --git a/controllers/argocd/applicationset_test.go b/controllers/argocd/applicationset_test.go
index 9b1e9d12..b99bba01 100644
--- a/controllers/argocd/applicationset_test.go
+++ b/controllers/argocd/applicationset_test.go
@@ -486,3 +486,14 @@ func setProxyEnvVars(t *testing.T) {
 	t.Setenv("HTTP_PROXY", "http://example.com")
 	t.Setenv("NO_PROXY", ".cluster.local")
 }
+
+func TestReconcileApplicationSet_Service(t *testing.T) {
+	logf.SetLogger(ZapLogger(true))
+	a := makeTestArgoCD()
+	r := makeTestReconciler(t, a)
+
+	s := newServiceWithSuffix(common.ApplicationSetServiceNameSuffix, common.ApplicationSetServiceNameSuffix, a)
+
+	assert.NoError(t, r.reconcileApplicationSetService(a))
+	assert.NoError(t, r.Client.Get(context.TODO(), types.NamespacedName{Namespace: s.Namespace, Name: s.Name}, s))
+}
diff --git a/controllers/argocd/configmap_test.go b/controllers/argocd/configmap_test.go
index 3ad05e0b..996b01df 100644
--- a/controllers/argocd/configmap_test.go
+++ b/controllers/argocd/configmap_test.go
@@ -869,3 +869,27 @@ func TestReconcileArgoCD_reconcileArgoConfigMap_withExtraConfig(t *testing.T) {
 	assert.Equal(t, cm.Data["admin.enabled"], "false")
 
 }
+
+func Test_reconcileRBAC(t *testing.T) {
+	a := makeTestArgoCD()
+	r := makeTestReconciler(t, a)
+
+	err := r.reconcileRBAC(a)
+	assert.NoError(t, err)
+
+	// Verify ArgoCD CR can be used to configure the RBAC policy matcher mode.\
+	matcherMode := "regex"
+	a.Spec.RBAC.PolicyMatcherMode = &matcherMode
+
+	err = r.reconcileRBAC(a)
+	assert.NoError(t, err)
+
+	cm := &corev1.ConfigMap{}
+	err = r.Client.Get(context.TODO(), types.NamespacedName{
+		Name:      common.ArgoCDRBACConfigMapName,
+		Namespace: testNamespace,
+	}, cm)
+
+	assert.NoError(t, err)
+	assert.Equal(t, cm.Data["policy.matchMode"], matcherMode)
+}
diff --git a/controllers/argocd/deployment_test.go b/controllers/argocd/deployment_test.go
index 94f876b0..f518369d 100644
--- a/controllers/argocd/deployment_test.go
+++ b/controllers/argocd/deployment_test.go
@@ -743,7 +743,10 @@ func TestReconcileArgoCD_reconcileDeployment_nodePlacement(t *testing.T) {
 	}, deployment)
 	assert.NoError(t, err)
 
-	if diff := cmp.Diff(deploymentDefaultNodeSelector(), deployment.Spec.Template.Spec.NodeSelector); diff != "" {
+	nSelectors := deploymentDefaultNodeSelector()
+	nSelectors = argoutil.AppendStringMap(nSelectors, common.DefaultNodeSelector())
+
+	if diff := cmp.Diff(nSelectors, deployment.Spec.Template.Spec.NodeSelector); diff != "" {
 		t.Fatalf("reconcileDeployment failed:\n%s", diff)
 	}
 	if diff := cmp.Diff(deploymentDefaultTolerations(), deployment.Spec.Template.Spec.Tolerations); diff != "" {
@@ -906,6 +909,7 @@ func TestReconcileArgoCD_reconcileServerDeployment(t *testing.T) {
 		},
 		Volumes:            serverDefaultVolumes(),
 		ServiceAccountName: "argocd-argocd-server",
+		NodeSelector:       common.DefaultNodeSelector(),
 	}
 
 	assert.Equal(t, want, deployment.Spec.Template.Spec)
@@ -1120,6 +1124,7 @@ func TestReconcileArgoCD_reconcileServerDeploymentWithInsecure(t *testing.T) {
 		},
 		Volumes:            serverDefaultVolumes(),
 		ServiceAccountName: "argocd-argocd-server",
+		NodeSelector:       common.DefaultNodeSelector(),
 	}
 
 	assert.Equal(t, want, deployment.Spec.Template.Spec)
@@ -1205,6 +1210,7 @@ func TestReconcileArgoCD_reconcileServerDeploymentChangedToInsecure(t *testing.T
 		},
 		Volumes:            serverDefaultVolumes(),
 		ServiceAccountName: "argocd-argocd-server",
+		NodeSelector:       common.DefaultNodeSelector(),
 	}
 
 	assert.Equal(t, want, deployment.Spec.Template.Spec)
diff --git a/controllers/argocd/dex_test.go b/controllers/argocd/dex_test.go
index c143ed51..7107bcb1 100644
--- a/controllers/argocd/dex_test.go
+++ b/controllers/argocd/dex_test.go
@@ -424,6 +424,7 @@ func TestReconcileArgoCD_reconcileDexDeployment(t *testing.T) {
 			},
 		},
 		ServiceAccountName: "argocd-argocd-dex-server",
+		NodeSelector:       common.DefaultNodeSelector(),
 	}
 	assert.Equal(t, want, deployment.Spec.Template.Spec)
 }
@@ -514,6 +515,7 @@ func TestReconcileArgoCD_reconcileDexDeployment_withUpdate(t *testing.T) {
 			},
 		},
 		ServiceAccountName: "argocd-argocd-dex-server",
+		NodeSelector:       common.DefaultNodeSelector(),
 	}
 
 	tests := []struct {
diff --git a/controllers/argocd/ingress_test.go b/controllers/argocd/ingress_test.go
index 9141ce33..bc32ca75 100644
--- a/controllers/argocd/ingress_test.go
+++ b/controllers/argocd/ingress_test.go
@@ -4,13 +4,13 @@ import (
 	"context"
 	"testing"
 
+	"github.com/argoproj-labs/argocd-operator/api/v1alpha1"
+	argoprojv1alpha1 "github.com/argoproj-labs/argocd-operator/api/v1alpha1"
+	"github.com/argoproj-labs/argocd-operator/common"
+	"github.com/stretchr/testify/assert"
 	networkingv1 "k8s.io/api/networking/v1"
 	"k8s.io/apimachinery/pkg/types"
 	logf "sigs.k8s.io/controller-runtime/pkg/log"
-
-	"github.com/stretchr/testify/assert"
-
-	argoprojv1alpha1 "github.com/argoproj-labs/argocd-operator/api/v1alpha1"
 )
 
 func TestReconcileArgoCD_reconcile_ServerIngress_ingressClassName(t *testing.T) {
@@ -182,3 +182,20 @@ func TestReconcileArgoCD_reconcile_PrometheusIngress_ingressClassName(t *testing
 		})
 	}
 }
+
+func TestReconcileApplicationSetService_Ingress(t *testing.T) {
+	logf.SetLogger(ZapLogger(true))
+	a := makeTestArgoCD()
+	obj := v1alpha1.ArgoCDApplicationSet{
+		WebhookServer: v1alpha1.WebhookServerSpec{
+			Ingress: v1alpha1.ArgoCDIngressSpec{
+				Enabled: true,
+			},
+		},
+	}
+	a.Spec.ApplicationSet = &obj
+	r := makeTestReconciler(t, a)
+	ingress := newIngressWithSuffix(common.ApplicationSetServiceNameSuffix, a)
+	assert.NoError(t, r.reconcileApplicationSetControllerIngress(a))
+	assert.NoError(t, r.Client.Get(context.TODO(), types.NamespacedName{Namespace: ingress.Namespace, Name: ingress.Name}, ingress))
+}
diff --git a/controllers/argocd/keycloak_test.go b/controllers/argocd/keycloak_test.go
index b93d56e9..06afdd2c 100644
--- a/controllers/argocd/keycloak_test.go
+++ b/controllers/argocd/keycloak_test.go
@@ -30,6 +30,7 @@ import (
 	argoappv1 "github.com/argoproj-labs/argocd-operator/api/v1alpha1"
 	argoprojv1alpha1 "github.com/argoproj-labs/argocd-operator/api/v1alpha1"
 	"github.com/argoproj-labs/argocd-operator/common"
+	"github.com/argoproj-labs/argocd-operator/controllers/argoutil"
 )
 
 var (
@@ -521,7 +522,10 @@ func TestKeycloak_NodeLabelSelector(t *testing.T) {
 	}
 
 	dc := getKeycloakDeploymentConfigTemplate(a)
-	assert.Equal(t, dc.Spec.Template.Spec.NodeSelector, a.Spec.NodePlacement.NodeSelector)
+
+	nSelectors := deploymentDefaultNodeSelector()
+	nSelectors = argoutil.AppendStringMap(nSelectors, common.DefaultNodeSelector())
+	assert.Equal(t, dc.Spec.Template.Spec.NodeSelector, nSelectors)
 	assert.Equal(t, dc.Spec.Template.Spec.Tolerations, a.Spec.NodePlacement.Tolerations)
 }
 
diff --git a/controllers/argocd/role_test.go b/controllers/argocd/role_test.go
index d74777ff..1f012965 100644
--- a/controllers/argocd/role_test.go
+++ b/controllers/argocd/role_test.go
@@ -7,8 +7,10 @@ import (
 	"testing"
 
 	"github.com/stretchr/testify/assert"
+	corev1 "k8s.io/api/core/v1"
 	v1 "k8s.io/api/rbac/v1"
 	"k8s.io/apimachinery/pkg/api/errors"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/types"
 	logf "sigs.k8s.io/controller-runtime/pkg/log"
 
@@ -175,3 +177,69 @@ func TestReconcileArgoCD_reconcileRole_custom_role(t *testing.T) {
 		t.Fatal(err)
 	}
 }
+
+// This test validates the behavior of the operator reconciliation when a managed namespace is not properly terminated
+// or remains terminating may be because of some resources in the namespace not getting deleted.
+func TestReconcileRoles_ManagedTerminatingNamespace(t *testing.T) {
+
+	a := makeTestArgoCD()
+	r := makeTestReconciler(t, a)
+	assert.NoError(t, createNamespace(r, a.Namespace, ""))
+
+	// Create a managed namespace
+	assert.NoError(t, createNamespace(r, "managedNS", a.Namespace))
+
+	workloadIdentifier := "x"
+	expectedRules := policyRuleForApplicationController()
+	_, err := r.reconcileRole(workloadIdentifier, expectedRules, a)
+	assert.NoError(t, err)
+
+	expectedName := fmt.Sprintf("%s-%s", a.Name, workloadIdentifier)
+	reconciledRole := &v1.Role{}
+	assert.NoError(t, r.Client.Get(context.TODO(), types.NamespacedName{Name: expectedName, Namespace: a.Namespace}, reconciledRole))
+	assert.Equal(t, expectedRules, reconciledRole.Rules)
+
+	// Check if roles are created for the new namespace as well
+	assert.NoError(t, r.Client.Get(context.TODO(), types.NamespacedName{Name: expectedName, Namespace: "managedNS"}, reconciledRole))
+	assert.Equal(t, expectedRules, reconciledRole.Rules)
+
+	// Create a configmap with an invalid finalizer in the "managedNS".
+	configMap := &corev1.ConfigMap{
+		ObjectMeta: metav1.ObjectMeta{
+			Name:      "dummy",
+			Namespace: "managedNS",
+			Finalizers: []string{
+				"nonexistent.finalizer/dummy",
+			},
+		},
+	}
+	assert.NoError(t, r.Client.Create(
+		context.TODO(), configMap))
+
+	// Delete the newNamespaceTest ns.
+	// Verify that operator should not reconcile back to create the roles in terminating ns.
+	newNS := &corev1.Namespace{}
+	r.Client.Get(context.TODO(), types.NamespacedName{Namespace: "managedNS", Name: "managedNS"}, newNS)
+	r.Client.Delete(context.TODO(), newNS)
+
+	// Verify that the namespace exists and is in terminating state.
+	r.Client.Get(context.TODO(), types.NamespacedName{Namespace: "managedNS", Name: "managedNS"}, newNS)
+	assert.NotEqual(t, newNS.DeletionTimestamp, nil)
+
+	_, err = r.reconcileRole(workloadIdentifier, expectedRules, a)
+	assert.NoError(t, err)
+
+	// Verify that the roles are deleted
+	err = r.Client.Get(context.TODO(), types.NamespacedName{Name: expectedName, Namespace: "managedNS2"}, reconciledRole)
+	assert.ErrorContains(t, err, "not found")
+
+	// Create another managed namespace
+	assert.NoError(t, createNamespace(r, "managedNS2", a.Namespace))
+
+	// Check if roles are created for the new namespace as well
+	_, err = r.reconcileRole(workloadIdentifier, expectedRules, a)
+	assert.NoError(t, err)
+
+	assert.NoError(t, r.Client.Get(context.TODO(), types.NamespacedName{Name: expectedName, Namespace: "managedNS2"}, reconciledRole))
+	assert.Equal(t, expectedRules, reconciledRole.Rules)
+}
diff --git a/controllers/argocd/rolebinding_test.go b/controllers/argocd/rolebinding_test.go
index f3c5cb44..27877aa2 100644
--- a/controllers/argocd/rolebinding_test.go
+++ b/controllers/argocd/rolebinding_test.go
@@ -6,6 +6,7 @@ import (
 	"testing"
 
 	"github.com/stretchr/testify/assert"
+	corev1 "k8s.io/api/core/v1"
 	rbacv1 "k8s.io/api/rbac/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/types"
@@ -67,6 +68,62 @@ func TestReconcileArgoCD_reconcileRoleBinding_for_new_namespace(t *testing.T) {
 	assert.Error(t, r.Client.Get(context.TODO(), types.NamespacedName{Name: expectedName, Namespace: "newTestNamespace"}, roleBinding))
 }
 
+// This test validates the behavior of the operator reconciliation when a managed namespace is not properly terminated
+// or remains terminating may be because of some resources in the namespace not getting deleted.
+func TestReconcileRoleBinding_for_Managed_Teminating_Namespace(t *testing.T) {
+	a := makeTestArgoCD()
+	r := makeTestReconciler(t, a)
+
+	assert.NoError(t, createNamespace(r, a.Namespace, ""))
+	assert.NoError(t, createNamespace(r, "managedNS", a.Namespace))
+
+	// Verify role bindings are created for the new namespace with managed-by label
+	roleBinding := &rbacv1.RoleBinding{}
+	workloadIdentifier := common.ArgoCDApplicationControllerComponent
+	expectedRules := policyRuleForApplicationController()
+	expectedName := fmt.Sprintf("%s-%s", a.Name, workloadIdentifier)
+	assert.NoError(t, r.reconcileRoleBinding(workloadIdentifier, expectedRules, a))
+	assert.NoError(t, r.Client.Get(context.TODO(), types.NamespacedName{Name: expectedName, Namespace: "managedNS"}, roleBinding))
+
+	// Create a configmap with an invalid finalizer in the "managedNS".
+	configMap := &corev1.ConfigMap{
+		ObjectMeta: metav1.ObjectMeta{
+			Name:      "dummy",
+			Namespace: "managedNS",
+			Finalizers: []string{
+				"nonexistent.finalizer/dummy",
+			},
+		},
+	}
+	assert.NoError(t, r.Client.Create(
+		context.TODO(), configMap))
+
+	// Delete the newNamespaceTest ns.
+	// Verify that operator should not reconcile back to create the roleBindings in terminating ns.
+	newNS := &corev1.Namespace{}
+	r.Client.Get(context.TODO(), types.NamespacedName{Namespace: "managedNS", Name: "managedNS"}, newNS)
+	r.Client.Delete(context.TODO(), newNS)
+
+	// Verify that the namespace exists and is in terminating state.
+	r.Client.Get(context.TODO(), types.NamespacedName{Namespace: "managedNS", Name: "managedNS"}, newNS)
+	assert.NotEqual(t, newNS.DeletionTimestamp, nil)
+
+	err := r.reconcileRoleBinding(workloadIdentifier, expectedRules, a)
+	assert.NoError(t, err)
+
+	// Verify that the role bindings are deleted
+	err = r.Client.Get(context.TODO(), types.NamespacedName{Name: expectedName, Namespace: "managedNS2"}, roleBinding)
+	assert.ErrorContains(t, err, "not found")
+
+	// Create another managed namespace
+	assert.NoError(t, createNamespace(r, "managedNS2", a.Namespace))
+
+	// Check if roleBindings are created for the new namespace as well
+	err = r.reconcileRoleBinding(workloadIdentifier, expectedRules, a)
+	assert.NoError(t, err)
+	assert.NoError(t, r.Client.Get(context.TODO(), types.NamespacedName{Name: expectedName, Namespace: "managedNS2"}, roleBinding))
+}
+
 func TestReconcileArgoCD_reconcileClusterRoleBinding(t *testing.T) {
 	logf.SetLogger(ZapLogger(true))
 	a := makeTestArgoCD()
diff --git a/tests/k8s/1-001_validate_basic/05-applicationset.yaml b/tests/k8s/1-001_validate_basic/05-applicationset.yaml
new file mode 100644
index 00000000..f6582332
--- /dev/null
+++ b/tests/k8s/1-001_validate_basic/05-applicationset.yaml
@@ -0,0 +1,20 @@
+# Delete previous cluster
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+delete:
+- apiVersion: argoproj.io/v1alpha1
+  kind: ArgoCD
+  name: example-argocd
+commands:
+  # Sleep to allow resources to be completely deleted
+  - command: sleep 30s
+---
+apiVersion: argoproj.io/v1alpha1
+kind: ArgoCD
+metadata:
+  name: example-argocd
+spec:
+  applicationSet: 
+    webhookServer:
+     ingress:
+       enabled: true
\ No newline at end of file
diff --git a/tests/k8s/1-001_validate_basic/05-assert.yaml b/tests/k8s/1-001_validate_basic/05-assert.yaml
new file mode 100644
index 00000000..871040c6
--- /dev/null
+++ b/tests/k8s/1-001_validate_basic/05-assert.yaml
@@ -0,0 +1,42 @@
+apiVersion: kuttl.dev/v1beta1
+kind: TestAssert
+timeout: 720
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: example-argocd-applicationset-controller
+status:
+  readyReplicas: 1
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: example-argocd-applicationset-controller
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+  name: example-argocd-applicationset-controller
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  name: example-argocd-applicationset-controller
+---
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+  name: example-argocd-applicationset-controller
+spec:
+  rules:
+  - host: example-argocd
+    http:
+      paths:
+      - backend:
+          service:
+            name: example-argocd-applicationset-controller
+            port:
+              name: webhook
+        path: /api/webhook
+        pathType: ImplementationSpecific
diff --git a/tests/k8s/1-001_validate_basic/06-disable-applicationset-ingress.yaml b/tests/k8s/1-001_validate_basic/06-disable-applicationset-ingress.yaml
new file mode 100644
index 00000000..a8685cc5
--- /dev/null
+++ b/tests/k8s/1-001_validate_basic/06-disable-applicationset-ingress.yaml
@@ -0,0 +1,7 @@
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+commands:
+# patches to disable applicationset
+- script: |
+    kubectl patch --type=merge -n $NAMESPACE argocd/example-argocd --patch '{"spec":{"applicationSet":{"webhookServer":{"ingress":{"enabled":false}}}}}'
+- script: sleep 10
\ No newline at end of file
diff --git a/tests/k8s/1-001_validate_basic/06-errors.yaml b/tests/k8s/1-001_validate_basic/06-errors.yaml
new file mode 100644
index 00000000..923a2e82
--- /dev/null
+++ b/tests/k8s/1-001_validate_basic/06-errors.yaml
@@ -0,0 +1,4 @@
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+  name: example-argocd-applicationset-controller
\ No newline at end of file
diff --git a/tests/k8s/1-023_validate_node_placement/01-assert.yaml b/tests/k8s/1-023_validate_node_placement/01-assert.yaml
new file mode 100644
index 00000000..dff34170
--- /dev/null
+++ b/tests/k8s/1-023_validate_node_placement/01-assert.yaml
@@ -0,0 +1,43 @@
+apiVersion: kuttl.dev/v1beta1
+kind: TestAssert
+timeout: 120
+---
+apiVersion: apps/v1
+kind: StatefulSet
+metadata:
+  name: example-argocd-application-controller
+spec:
+  template:
+    spec:
+      nodeSelector: 
+        kubernetes.io/os: linux 
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: example-argocd-redis
+spec:
+  template:
+    spec:
+      nodeSelector: 
+        kubernetes.io/os: linux
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: example-argocd-repo-server
+spec:
+  template:
+    spec:
+      nodeSelector: 
+        kubernetes.io/os: linux
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: example-argocd-server
+spec:
+  template:
+    spec:
+      nodeSelector: 
+        kubernetes.io/os: linux
\ No newline at end of file
diff --git a/tests/k8s/1-023_validate_node_placement/01-default-node-selector.yaml b/tests/k8s/1-023_validate_node_placement/01-default-node-selector.yaml
new file mode 100644
index 00000000..2ccddd82
--- /dev/null
+++ b/tests/k8s/1-023_validate_node_placement/01-default-node-selector.yaml
@@ -0,0 +1,7 @@
+apiVersion: argoproj.io/v1alpha1
+kind: ArgoCD
+metadata:
+  name: example-argocd
+  labels:
+    example: basic
+spec: {}
\ No newline at end of file
diff --git a/tests/k8s/1-023_validate_node_placement/02-assert.yaml b/tests/k8s/1-023_validate_node_placement/02-assert.yaml
new file mode 100644
index 00000000..39759aad
--- /dev/null
+++ b/tests/k8s/1-023_validate_node_placement/02-assert.yaml
@@ -0,0 +1,43 @@
+apiVersion: apps/v1
+kind: StatefulSet
+metadata:
+  name: example-argocd-application-controller
+spec:
+  template:
+    spec:
+      nodeSelector: 
+        kubernetes.io/os: linux 
+        key1: value1
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: example-argocd-redis
+spec:
+  template:
+    spec:
+      nodeSelector: 
+        kubernetes.io/os: linux
+        key1: value1
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: example-argocd-repo-server
+spec:
+  template:
+    spec:
+      nodeSelector: 
+        kubernetes.io/os: linux
+        key1: value1
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: example-argocd-server
+spec:
+  template:
+    spec:
+      nodeSelector: 
+        kubernetes.io/os: linux
+        key1: value1
\ No newline at end of file
diff --git a/tests/k8s/1-023_validate_node_placement/02-custom-node-placement.yaml b/tests/k8s/1-023_validate_node_placement/02-custom-node-placement.yaml
new file mode 100644
index 00000000..67a5ad9f
--- /dev/null
+++ b/tests/k8s/1-023_validate_node_placement/02-custom-node-placement.yaml
@@ -0,0 +1,10 @@
+apiVersion: argoproj.io/v1alpha1
+kind: ArgoCD
+metadata:
+  name: example-argocd
+  labels:
+    example: basic
+spec:
+  nodePlacement:
+    nodeSelector:
+      key1: value1
\ No newline at end of file
diff --git a/tests/k8s/1-023_validate_node_placement/03-assert.yaml b/tests/k8s/1-023_validate_node_placement/03-assert.yaml
new file mode 100644
index 00000000..c41d1b1f
--- /dev/null
+++ b/tests/k8s/1-023_validate_node_placement/03-assert.yaml
@@ -0,0 +1,64 @@
+apiVersion: apps/v1
+kind: StatefulSet
+metadata:
+  name: example-argocd-application-controller
+spec:
+  template:
+    spec:
+      nodeSelector: 
+        kubernetes.io/os: linux 
+        key1: value1
+      tolerations: 
+      - key: key1
+        operator: Equal
+        value: value1
+        effect: NoSchedule  
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: example-argocd-redis
+spec:
+  template:
+    spec:
+      nodeSelector: 
+        kubernetes.io/os: linux
+        key1: value1
+      tolerations: 
+      - key: key1
+        operator: Equal
+        value: value1
+        effect: NoSchedule  
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: example-argocd-repo-server
+spec:
+  template:
+    spec:
+      nodeSelector: 
+        kubernetes.io/os: linux
+        key1: value1
+      tolerations: 
+      - key: key1
+        operator: Equal
+        value: value1
+        effect: NoSchedule  
+        
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: example-argocd-server
+spec:
+  template:
+    spec:
+      nodeSelector: 
+        kubernetes.io/os: linux
+        key1: value1
+      tolerations: 
+      - key: key1
+        operator: Equal
+        value: value1
+        effect: NoSchedule  
\ No newline at end of file
diff --git a/tests/k8s/1-023_validate_node_placement/03-node-placement-with-toleration.yaml b/tests/k8s/1-023_validate_node_placement/03-node-placement-with-toleration.yaml
new file mode 100644
index 00000000..d3e895cd
--- /dev/null
+++ b/tests/k8s/1-023_validate_node_placement/03-node-placement-with-toleration.yaml
@@ -0,0 +1,16 @@
+apiVersion: argoproj.io/v1alpha1
+kind: ArgoCD
+metadata:
+  name: example-argocd
+  labels:
+    example: basic
+spec:
+  nodePlacement:
+    nodeSelector:
+      key1: value1
+    tolerations: 
+    - key: key1
+      operator: Equal
+      value: value1
+      effect: NoSchedule
+         
\ No newline at end of file