Repository: argoproj-labs/argocd-operator
Pull request #793 (2022-10-10 13:03:01)

add support for new subkeys in resource customizations
**What type of PR is this?**
 /kind enhancement

**What does this PR do / why we need it**:
This PR adds support for new resource customization subkeys that were introduced in Argo CD (see[ this article](https://medium.com/argo-project/argo-cd-v2-1-first-release-candidate-is-ready-c1aab7795638) for more information about that)

**Have you updated the necessary documentation?**
* [x] Documentation has been updated.

**Which issue(s) this PR fixes**:
In gitops-operator: https://github.com/redhat-developer/gitops-operator/issues/248
JIRA issue: https://issues.redhat.com/browse/GITOPS-1561 

**How to test changes / Special notes to the reviewer**:
1. start your k8s cluster
2. run `make docker-build`, `make docker-push`, and `make deploy`
3. add the argocd instance:
```
cat <<EOF | kubectl apply -f -                                                                    
apiVersion: argoproj.io/v1alpha1
kind: ArgoCD
metadata:
  name: argocd
spec: {}
EOF
```
4. run `oc edit argocd argocd`
5. add the following customizations for `resourceHealthChecks`, `resourceIgnoreDifferences`, and `resourceActions` to your argocd spec: 
```
spec:
  resourceIgnoreDifferences:
    all:
      jqPathExpressions:
          - xyz
          - abc
      jsonPointers:
          - xyz
          - abc
      managedFieldsManagers:
          - xyz
          - abc
    resourceIdentifiers:
      - group: apps
        kind: deployments
        customization:
          jqPathExpressions:
            - xyz
            - abc
          jsonPointers:
            - xyz
            - abc
          managedFieldManagers:
            - xyz
            - abc
      - group: batch
        kind: jobs
        customization:
          jqPathExpressions:
            - xyz
            - abc
          jsonPointers:
            - xyz
            - abc
          managedFieldsManagers:
            - xyz
            - abc
  resourceHealthChecks:
    - group: certmanager.k8s.io
      kind: Certificate
      check: |
        hs = {}
        if obj.status ~= nil then
          if obj.status.conditions ~= nil then
            for i, condition in ipairs(obj.status.conditions) do
              if condition.type == "Ready" and condition.status == "False" then
                hs.status = "Degraded"
                hs.message = condition.message
                return hs
              end
              if condition.type == "Ready" and condition.status == "True" then
                hs.status = "Healthy"
                hs.message = condition.message
                return hs
              end
            end
          end
        end
        hs.status = "Progressing"
        hs.message = "Waiting for certificate"
        return hs
  resourceActions:
    - group: apps
      kind: Deployment
      action: |
        discovery.lua: |
        actions = {}
        actions["restart"] = {}
        return actions
        definitions:
        - name: restart
          # Lua Script to modify the obj
          action.lua: |
            local os = require("os")
            if obj.spec.template.metadata == nil then
                obj.spec.template.metadata = {}
            end
            if obj.spec.template.metadata.annotations == nil then
                obj.spec.template.metadata.annotations = {}
            end
            obj.spec.template.metadata.annotations["kubectl.kubernetes.io/restartedAt"] = os.date("!%Y-%m-%dT%XZ")
            return obj
```

6. check your argocd-cm to make sure it was added correctly with `kubectl describe configmap argocd-cm`.



jaideepr97: heads up @reginapizza 
there have been some changes to the deprecation event emission logic since https://github.com/argoproj-labs/argocd-operator/pull/797 was merged

The problem with having a single toggle variable is that once it has been toggled after the first time the event is emitted, the event will not be emitted for any other namespace/instance that follows and may also need that event 

Instead we may be able to extend the new map that has been put in place to track which instances have emitted the event already, and which ones have not (but need to). This would help ensure that all instances (and by extension the teams that may be controlling those instances) using the old resource customizations format have sufficient warning about it 


jaideepr97: tested it locally and it works fine 
LGTM, thanks @reginapizza 
jaideepr97: @reginapizza some minor comments that should help the e2e test pass
other than that LGTM :) 
jaideepr97: > some minor comments that should help the e2e test pass
Oops, it seems I was mistaken when I made those comments, feel free to ignore

reginapizza: /retest

Patch:
diff --git a/api/v1alpha1/argocd_types.go b/api/v1alpha1/argocd_types.go
index c618b5c6..9e483e6c 100644
--- a/api/v1alpha1/argocd_types.go
+++ b/api/v1alpha1/argocd_types.go
@@ -541,6 +541,39 @@ type ArgoCDServerServiceSpec struct {
 	Type corev1.ServiceType `json:"type"`
 }
 
+// Resource Customization for custom health check
+type ResourceHealthCheck struct {
+	Group string `json:"group,omitempty"`
+	Kind  string `json:"kind,omitempty"`
+	Check string `json:"check,omitempty"`
+}
+
+// Resource Customization for ignore difference
+type ResourceIgnoreDifference struct {
+	All                 *IgnoreDifferenceCustomization `json:"all,omitempty"`
+	ResourceIdentifiers []ResourceIdentifiers          `json:"resourceIdentifiers,omitempty"`
+}
+
+// Resource Customization fields for ignore difference
+type ResourceIdentifiers struct {
+	Group         string                        `json:"group,omitempty"`
+	Kind          string                        `json:"kind,omitempty"`
+	Customization IgnoreDifferenceCustomization `json:"customization,omitempty"`
+}
+
+type IgnoreDifferenceCustomization struct {
+	JqPathExpressions     []string `json:"jqPathExpressions,omitempty"`
+	JsonPointers          []string `json:"jsonPointers,omitempty"`
+	ManagedFieldsManagers []string `json:"managedFieldsManagers,omitempty"`
+}
+
+// Resource Customization for custom action
+type ResourceAction struct {
+	Group  string `json:"group,omitempty"`
+	Kind   string `json:"kind,omitempty"`
+	Action string `json:"action,omitempty"`
+}
+
 // SSOProviderType string defines the type of SSO provider.
 type SSOProviderType string
 
@@ -689,10 +722,22 @@ type ArgoCDSpec struct {
 	// RepositoryCredentials are the Git pull credentials to configure Argo CD with upon creation of the cluster.
 	RepositoryCredentials string `json:"repositoryCredentials,omitempty"`
 
-	// ResourceCustomizations customizes resource behavior. Keys are in the form: group/Kind.
+	// ResourceCustomizations customizes resource behavior. Keys are in the form: group/Kind. Please note that this is being deprecated in favor of ResourceHealthChecks, ResourceIgnoreDifferences, and ResourceActions.
 	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Resource Customizations'",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text","urn:alm:descriptor:com.tectonic.ui:advanced"}
 	ResourceCustomizations string `json:"resourceCustomizations,omitempty"`
 
+	// ResourceHealthChecks customizes resource health check behavior.
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Resource Health Check Customizations'",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text","urn:alm:descriptor:com.tectonic.ui:advanced"}
+	ResourceHealthChecks []ResourceHealthCheck `json:"resourceHealthChecks,omitempty"`
+
+	// ResourceIgnoreDifferences customizes resource ignore difference behavior.
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Resource Ignore Difference Customizations'",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text","urn:alm:descriptor:com.tectonic.ui:advanced"}
+	ResourceIgnoreDifferences *ResourceIgnoreDifference `json:"resourceIgnoreDifferences,omitempty"`
+
+	// ResourceActions customizes resource action behavior.
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Resource Action Customizations'",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text","urn:alm:descriptor:com.tectonic.ui:advanced"}
+	ResourceActions []ResourceAction `json:"resourceActions,omitempty"`
+
 	// ResourceExclusions is used to completely ignore entire classes of resource group/kinds.
 	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Resource Exclusions'",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text","urn:alm:descriptor:com.tectonic.ui:advanced"}
 	ResourceExclusions string `json:"resourceExclusions,omitempty"`
diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go
index 79f4b023..f98cbe95 100644
--- a/api/v1alpha1/zz_generated.deepcopy.go
+++ b/api/v1alpha1/zz_generated.deepcopy.go
@@ -903,6 +903,21 @@ func (in *ArgoCDSpec) DeepCopyInto(out *ArgoCDSpec) {
 	in.RBAC.DeepCopyInto(&out.RBAC)
 	in.Redis.DeepCopyInto(&out.Redis)
 	in.Repo.DeepCopyInto(&out.Repo)
+	if in.ResourceHealthChecks != nil {
+		in, out := &in.ResourceHealthChecks, &out.ResourceHealthChecks
+		*out = make([]ResourceHealthCheck, len(*in))
+		copy(*out, *in)
+	}
+	if in.ResourceIgnoreDifferences != nil {
+		in, out := &in.ResourceIgnoreDifferences, &out.ResourceIgnoreDifferences
+		*out = new(ResourceIgnoreDifference)
+		(*in).DeepCopyInto(*out)
+	}
+	if in.ResourceActions != nil {
+		in, out := &in.ResourceActions, &out.ResourceActions
+		*out = make([]ResourceAction, len(*in))
+		copy(*out, *in)
+	}
 	in.Server.DeepCopyInto(&out.Server)
 	if in.SourceNamespaces != nil {
 		in, out := &in.SourceNamespaces, &out.SourceNamespaces
@@ -985,6 +1000,36 @@ func (in *Banner) DeepCopy() *Banner {
 	return out
 }
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *IgnoreDifferenceCustomization) DeepCopyInto(out *IgnoreDifferenceCustomization) {
+	*out = *in
+	if in.JqPathExpressions != nil {
+		in, out := &in.JqPathExpressions, &out.JqPathExpressions
+		*out = make([]string, len(*in))
+		copy(*out, *in)
+	}
+	if in.JsonPointers != nil {
+		in, out := &in.JsonPointers, &out.JsonPointers
+		*out = make([]string, len(*in))
+		copy(*out, *in)
+	}
+	if in.ManagedFieldsManagers != nil {
+		in, out := &in.ManagedFieldsManagers, &out.ManagedFieldsManagers
+		*out = make([]string, len(*in))
+		copy(*out, *in)
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IgnoreDifferenceCustomization.
+func (in *IgnoreDifferenceCustomization) DeepCopy() *IgnoreDifferenceCustomization {
+	if in == nil {
+		return nil
+	}
+	out := new(IgnoreDifferenceCustomization)
+	in.DeepCopyInto(out)
+	return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *KustomizeVersionSpec) DeepCopyInto(out *KustomizeVersionSpec) {
 	*out = *in
@@ -1000,6 +1045,79 @@ func (in *KustomizeVersionSpec) DeepCopy() *KustomizeVersionSpec {
 	return out
 }
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ResourceAction) DeepCopyInto(out *ResourceAction) {
+	*out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceAction.
+func (in *ResourceAction) DeepCopy() *ResourceAction {
+	if in == nil {
+		return nil
+	}
+	out := new(ResourceAction)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ResourceHealthCheck) DeepCopyInto(out *ResourceHealthCheck) {
+	*out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceHealthCheck.
+func (in *ResourceHealthCheck) DeepCopy() *ResourceHealthCheck {
+	if in == nil {
+		return nil
+	}
+	out := new(ResourceHealthCheck)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ResourceIdentifiers) DeepCopyInto(out *ResourceIdentifiers) {
+	*out = *in
+	in.Customization.DeepCopyInto(&out.Customization)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceIdentifiers.
+func (in *ResourceIdentifiers) DeepCopy() *ResourceIdentifiers {
+	if in == nil {
+		return nil
+	}
+	out := new(ResourceIdentifiers)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ResourceIgnoreDifference) DeepCopyInto(out *ResourceIgnoreDifference) {
+	*out = *in
+	if in.All != nil {
+		in, out := &in.All, &out.All
+		*out = new(IgnoreDifferenceCustomization)
+		(*in).DeepCopyInto(*out)
+	}
+	if in.ResourceIdentifiers != nil {
+		in, out := &in.ResourceIdentifiers, &out.ResourceIdentifiers
+		*out = make([]ResourceIdentifiers, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceIgnoreDifference.
+func (in *ResourceIgnoreDifference) DeepCopy() *ResourceIgnoreDifference {
+	if in == nil {
+		return nil
+	}
+	out := new(ResourceIgnoreDifference)
+	in.DeepCopyInto(out)
+	return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *SSHHostsSpec) DeepCopyInto(out *SSHHostsSpec) {
 	*out = *in
diff --git a/bundle/manifests/argocd-operator.clusterserviceversion.yaml b/bundle/manifests/argocd-operator.clusterserviceversion.yaml
index 59fb1b2a..e4532565 100644
--- a/bundle/manifests/argocd-operator.clusterserviceversion.yaml
+++ b/bundle/manifests/argocd-operator.clusterserviceversion.yaml
@@ -591,8 +591,15 @@ spec:
         x-descriptors:
         - urn:alm:descriptor:com.tectonic.ui:fieldGroup:Repo
         - urn:alm:descriptor:com.tectonic.ui:resourceRequirements
+      - description: ResourceActions customizes resource action behavior.
+        displayName: Resource Action Customizations'
+        path: resourceActions
+        x-descriptors:
+        - urn:alm:descriptor:com.tectonic.ui:text
+        - urn:alm:descriptor:com.tectonic.ui:advanced
       - description: 'ResourceCustomizations customizes resource behavior. Keys are
-          in the form: group/Kind.'
+          in the form: group/Kind. Please note that this is being deprecated in favor
+          of ResourceHealthChecks, ResourceIgnoreDifferences, and ResourceActions.'
         displayName: Resource Customizations'
         path: resourceCustomizations
         x-descriptors:
@@ -605,6 +612,19 @@ spec:
         x-descriptors:
         - urn:alm:descriptor:com.tectonic.ui:text
         - urn:alm:descriptor:com.tectonic.ui:advanced
+      - description: ResourceHealthChecks customizes resource health check behavior.
+        displayName: Resource Health Check Customizations'
+        path: resourceHealthChecks
+        x-descriptors:
+        - urn:alm:descriptor:com.tectonic.ui:text
+        - urn:alm:descriptor:com.tectonic.ui:advanced
+      - description: ResourceIgnoreDifferences customizes resource ignore difference
+          behavior.
+        displayName: Resource Ignore Difference Customizations'
+        path: resourceIgnoreDifferences
+        x-descriptors:
+        - urn:alm:descriptor:com.tectonic.ui:text
+        - urn:alm:descriptor:com.tectonic.ui:advanced
       - description: ResourceTrackingMethod defines how Argo CD should track resources
           that it manages
         displayName: Resource Tracking Method'
diff --git a/bundle/manifests/argoproj.io_argocds.yaml b/bundle/manifests/argoproj.io_argocds.yaml
index d0aab458..ac9429ea 100644
--- a/bundle/manifests/argoproj.io_argocds.yaml
+++ b/bundle/manifests/argoproj.io_argocds.yaml
@@ -5480,14 +5480,88 @@ spec:
                 description: RepositoryCredentials are the Git pull credentials to
                   configure Argo CD with upon creation of the cluster.
                 type: string
+              resourceActions:
+                description: ResourceActions customizes resource action behavior.
+                items:
+                  description: Resource Customization for custom action
+                  properties:
+                    action:
+                      type: string
+                    group:
+                      type: string
+                    kind:
+                      type: string
+                  type: object
+                type: array
               resourceCustomizations:
                 description: 'ResourceCustomizations customizes resource behavior.
-                  Keys are in the form: group/Kind.'
+                  Keys are in the form: group/Kind. Please note that this is being
+                  deprecated in favor of ResourceHealthChecks, ResourceIgnoreDifferences,
+                  and ResourceActions.'
                 type: string
               resourceExclusions:
                 description: ResourceExclusions is used to completely ignore entire
                   classes of resource group/kinds.
                 type: string
+              resourceHealthChecks:
+                description: ResourceHealthChecks customizes resource health check
+                  behavior.
+                items:
+                  description: Resource Customization for custom health check
+                  properties:
+                    check:
+                      type: string
+                    group:
+                      type: string
+                    kind:
+                      type: string
+                  type: object
+                type: array
+              resourceIgnoreDifferences:
+                description: ResourceIgnoreDifferences customizes resource ignore
+                  difference behavior.
+                properties:
+                  all:
+                    properties:
+                      jqPathExpressions:
+                        items:
+                          type: string
+                        type: array
+                      jsonPointers:
+                        items:
+                          type: string
+                        type: array
+                      managedFieldsManagers:
+                        items:
+                          type: string
+                        type: array
+                    type: object
+                  resourceIdentifiers:
+                    items:
+                      description: Resource Customization fields for ignore difference
+                      properties:
+                        customization:
+                          properties:
+                            jqPathExpressions:
+                              items:
+                                type: string
+                              type: array
+                            jsonPointers:
+                              items:
+                                type: string
+                              type: array
+                            managedFieldsManagers:
+                              items:
+                                type: string
+                              type: array
+                          type: object
+                        group:
+                          type: string
+                        kind:
+                          type: string
+                      type: object
+                    type: array
+                type: object
               resourceInclusions:
                 description: ResourceInclusions is used to only include specific group/kinds
                   in the reconciliation process.
diff --git a/config/crd/bases/argoproj.io_argocds.yaml b/config/crd/bases/argoproj.io_argocds.yaml
index 7fbf7dd5..f361245e 100644
--- a/config/crd/bases/argoproj.io_argocds.yaml
+++ b/config/crd/bases/argoproj.io_argocds.yaml
@@ -5482,14 +5482,88 @@ spec:
                 description: RepositoryCredentials are the Git pull credentials to
                   configure Argo CD with upon creation of the cluster.
                 type: string
+              resourceActions:
+                description: ResourceActions customizes resource action behavior.
+                items:
+                  description: Resource Customization for custom action
+                  properties:
+                    action:
+                      type: string
+                    group:
+                      type: string
+                    kind:
+                      type: string
+                  type: object
+                type: array
               resourceCustomizations:
                 description: 'ResourceCustomizations customizes resource behavior.
-                  Keys are in the form: group/Kind.'
+                  Keys are in the form: group/Kind. Please note that this is being
+                  deprecated in favor of ResourceHealthChecks, ResourceIgnoreDifferences,
+                  and ResourceActions.'
                 type: string
               resourceExclusions:
                 description: ResourceExclusions is used to completely ignore entire
                   classes of resource group/kinds.
                 type: string
+              resourceHealthChecks:
+                description: ResourceHealthChecks customizes resource health check
+                  behavior.
+                items:
+                  description: Resource Customization for custom health check
+                  properties:
+                    check:
+                      type: string
+                    group:
+                      type: string
+                    kind:
+                      type: string
+                  type: object
+                type: array
+              resourceIgnoreDifferences:
+                description: ResourceIgnoreDifferences customizes resource ignore
+                  difference behavior.
+                properties:
+                  all:
+                    properties:
+                      jqPathExpressions:
+                        items:
+                          type: string
+                        type: array
+                      jsonPointers:
+                        items:
+                          type: string
+                        type: array
+                      managedFieldsManagers:
+                        items:
+                          type: string
+                        type: array
+                    type: object
+                  resourceIdentifiers:
+                    items:
+                      description: Resource Customization fields for ignore difference
+                      properties:
+                        customization:
+                          properties:
+                            jqPathExpressions:
+                              items:
+                                type: string
+                              type: array
+                            jsonPointers:
+                              items:
+                                type: string
+                              type: array
+                            managedFieldsManagers:
+                              items:
+                                type: string
+                              type: array
+                          type: object
+                        group:
+                          type: string
+                        kind:
+                          type: string
+                      type: object
+                    type: array
+                type: object
               resourceInclusions:
                 description: ResourceInclusions is used to only include specific group/kinds
                   in the reconciliation process.
diff --git a/config/manifests/bases/argocd-operator.clusterserviceversion.yaml b/config/manifests/bases/argocd-operator.clusterserviceversion.yaml
index 88db44a0..ac62e881 100644
--- a/config/manifests/bases/argocd-operator.clusterserviceversion.yaml
+++ b/config/manifests/bases/argocd-operator.clusterserviceversion.yaml
@@ -465,8 +465,15 @@ spec:
         x-descriptors:
         - urn:alm:descriptor:com.tectonic.ui:fieldGroup:Repo
         - urn:alm:descriptor:com.tectonic.ui:resourceRequirements
+      - description: ResourceActions customizes resource action behavior.
+        displayName: Resource Action Customizations'
+        path: resourceActions
+        x-descriptors:
+        - urn:alm:descriptor:com.tectonic.ui:text
+        - urn:alm:descriptor:com.tectonic.ui:advanced
       - description: 'ResourceCustomizations customizes resource behavior. Keys are
-          in the form: group/Kind.'
+          in the form: group/Kind. Please note that this is being deprecated in favor
+          of ResourceHealthChecks, ResourceIgnoreDifferences, and ResourceActions.'
         displayName: Resource Customizations'
         path: resourceCustomizations
         x-descriptors:
@@ -479,6 +486,19 @@ spec:
         x-descriptors:
         - urn:alm:descriptor:com.tectonic.ui:text
         - urn:alm:descriptor:com.tectonic.ui:advanced
+      - description: ResourceHealthChecks customizes resource health check behavior.
+        displayName: Resource Health Check Customizations'
+        path: resourceHealthChecks
+        x-descriptors:
+        - urn:alm:descriptor:com.tectonic.ui:text
+        - urn:alm:descriptor:com.tectonic.ui:advanced
+      - description: ResourceIgnoreDifferences customizes resource ignore difference
+          behavior.
+        displayName: Resource Ignore Difference Customizations'
+        path: resourceIgnoreDifferences
+        x-descriptors:
+        - urn:alm:descriptor:com.tectonic.ui:text
+        - urn:alm:descriptor:com.tectonic.ui:advanced
       - description: ResourceTrackingMethod defines how Argo CD should track resources
           that it manages
         displayName: Resource Tracking Method'
diff --git a/controllers/argocd/configmap.go b/controllers/argocd/configmap.go
index a59dceb1..049a3364 100644
--- a/controllers/argocd/configmap.go
+++ b/controllers/argocd/configmap.go
@@ -22,6 +22,7 @@ import (
 	"reflect"
 	"strings"
 
+	"gopkg.in/yaml.v2"
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
@@ -144,15 +145,71 @@ func getRBACScopes(cr *argoprojv1a1.ArgoCD) string {
 	return scopes
 }
 
-// getResourceCustomizations will return the resource customizations for the given ArgoCD.
+// getResourceCustomizations loads Resource Customizations from argocd-cm ConfigMap
 func getResourceCustomizations(cr *argoprojv1a1.ArgoCD) string {
 	rc := common.ArgoCDDefaultResourceCustomizations
 	if cr.Spec.ResourceCustomizations != "" {
 		rc = cr.Spec.ResourceCustomizations
 	}
+
 	return rc
 }
 
+// getResourceHealthChecks loads health customizations to `resource.customizations.health` from argocd-cm ConfigMap
+func getResourceHealthChecks(cr *argoprojv1a1.ArgoCD) map[string]string {
+	healthCheck := make(map[string]string)
+	if cr.Spec.ResourceHealthChecks != nil {
+		resourceHealthChecks := cr.Spec.ResourceHealthChecks
+		for _, healthCustomization := range resourceHealthChecks {
+			subkey := "resource.customizations.health." + healthCustomization.Group + "_" + healthCustomization.Kind
+			subvalue := healthCustomization.Check
+			healthCheck[subkey] = subvalue
+		}
+	}
+	return healthCheck
+}
+
+// getResourceIgnoreDifferences loads ignore differences customizations to `resource.customizations.ignoreDifferences` from argocd-cm ConfigMap
+func getResourceIgnoreDifferences(cr *argoprojv1a1.ArgoCD) (map[string]string, error) {
+	ignoreDiff := make(map[string]string)
+	if cr.Spec.ResourceIgnoreDifferences != nil {
+		resourceIgnoreDiff := cr.Spec.ResourceIgnoreDifferences
+		if !reflect.DeepEqual(resourceIgnoreDiff.All, &v1alpha1.IgnoreDifferenceCustomization{}) {
+			subkey := "resource.customizations.ignoreDifferences.all"
+			bytes, err := yaml.Marshal(resourceIgnoreDiff.All)
+			if err != nil {
+				return ignoreDiff, err
+			}
+			subvalue := string(bytes)
+			ignoreDiff[subkey] = subvalue
+		}
+		for _, ignoreDiffCustomization := range resourceIgnoreDiff.ResourceIdentifiers {
+			subkey := "resource.customizations.ignoreDifferences." + ignoreDiffCustomization.Group + "_" + ignoreDiffCustomization.Kind
+			bytes, err := yaml.Marshal(ignoreDiffCustomization.Customization)
+			if err != nil {
+				return ignoreDiff, err
+			}
+			subvalue := string(bytes)
+			ignoreDiff[subkey] = subvalue
+		}
+	}
+	return ignoreDiff, nil
+}
+
+// getResourceActions loads custom actions to `resource.customizations.actions` from argocd-cm ConfigMap
+func getResourceActions(cr *argoprojv1a1.ArgoCD) map[string]string {
+	action := make(map[string]string)
+	if cr.Spec.ResourceActions != nil {
+		resourceAction := cr.Spec.ResourceActions
+		for _, actionCustomization := range resourceAction {
+			subkey := "resource.customizations.actions." + actionCustomization.Group + "_" + actionCustomization.Kind
+			subvalue := actionCustomization.Action
+			action[subkey] = subvalue
+		}
+	}
+	return action
+}
+
 // getResourceExclusions will return the resource exclusions for the given ArgoCD.
 func getResourceExclusions(cr *argoprojv1a1.ArgoCD) string {
 	re := common.ArgoCDDefaultResourceExclusions
@@ -331,9 +388,47 @@ func (r *ReconcileArgoCD) reconcileArgoConfigMap(cr *argoprojv1a1.ArgoCD) error
 	}
 
 	cm.Data[common.ArgoCDKeyOIDCConfig] = getOIDCConfig(cr)
+
+	if c := getResourceHealthChecks(cr); c != nil {
+		for k, v := range c {
+			cm.Data[k] = v
+		}
+	}
+
+	if c, err := getResourceIgnoreDifferences(cr); c != nil && err == nil {
+		for k, v := range c {
+			cm.Data[k] = v
+		}
+	} else {
+		return err
+	}
+
+	if c := getResourceActions(cr); c != nil {
+		for k, v := range c {
+			cm.Data[k] = v
+		}
+	}
+
+	// old format of ResourceCustomizations
 	if c := getResourceCustomizations(cr); c != "" {
+
+		// Emit event providing users with deprecation notice for ResourceCustomization if not emitted already
+		if currentInstanceEventEmissionStatus, ok := DeprecationEventEmissionTracker[cr.Namespace]; !ok || !currentInstanceEventEmissionStatus.ResourceCustomizationsDeprecationWarningEmitted {
+			err := argoutil.CreateEvent(r.Client, "Warning", "Deprecated", "ResourceCustomizations is deprecated, please use the new formats `ResourceHealthChecks`, `ResourceIgnoreDifferences`, and `ResourceActions` instead.", "DeprecationNotice", cr.ObjectMeta, cr.TypeMeta)
+			if err != nil {
+				return err
+			}
+
+			if !ok {
+				currentInstanceEventEmissionStatus = DeprecationEventEmissionStatus{ResourceCustomizationsDeprecationWarningEmitted: true}
+			} else {
+				currentInstanceEventEmissionStatus.ResourceCustomizationsDeprecationWarningEmitted = true
+			}
+			DeprecationEventEmissionTracker[cr.Namespace] = currentInstanceEventEmissionStatus
+		}
 		cm.Data[common.ArgoCDKeyResourceCustomizations] = c
 	}
+
 	cm.Data[common.ArgoCDKeyResourceExclusions] = getResourceExclusions(cr)
 	cm.Data[common.ArgoCDKeyResourceInclusions] = getResourceInclusions(cr)
 	cm.Data[common.ArgoCDKeyResourceTrackingMethod] = getResourceTrackingMethod(cr)
diff --git a/controllers/argocd/sso.go b/controllers/argocd/sso.go
index 961c8318..987ef291 100644
--- a/controllers/argocd/sso.go
+++ b/controllers/argocd/sso.go
@@ -36,24 +36,11 @@ const (
 	multipleSSOConfiguration string = "multiple SSO configuration: "
 )
 
-// DeprecationEventEmissionStatus is meant to track which deprecation events have been emitted already. This is temporary and can be removed in v0.0.6 once we have provided enough
-// deprecation notice
-type DeprecationEventEmissionStatus struct {
-	SSOSpecDeprecationWarningEmitted    bool
-	DexSpecDeprecationWarningEmitted    bool
-	DisableDexDeprecationWarningEmitted bool
-}
-
 var (
 	templateAPIFound     = false
 	ssoConfigLegalStatus string
 )
 
-// DeprecationEventEmissionTracker map stores the namespace containing ArgoCD instance as key and DeprecationEventEmissionStatus as value,
-// where DeprecationEventEmissionStatus tracks the events that have been emitted for the instance in the particular namespace.
-// This is temporary and can be removed in v0.0.6 when we remove the deprecated fields.
-var DeprecationEventEmissionTracker = make(map[string]DeprecationEventEmissionStatus)
-
 // IsTemplateAPIAvailable returns true if the template API is present.
 func IsTemplateAPIAvailable() bool {
 	return templateAPIFound
diff --git a/controllers/argocd/util.go b/controllers/argocd/util.go
index 3ad1b771..fc93596c 100644
--- a/controllers/argocd/util.go
+++ b/controllers/argocd/util.go
@@ -1160,6 +1160,20 @@ func containsString(arr []string, s string) bool {
 	return false
 }
 
+// DeprecationEventEmissionStatus is meant to track which deprecation events have been emitted already. This is temporary and can be removed in v0.0.6 once we have provided enough
+// deprecation notice
+type DeprecationEventEmissionStatus struct {
+	SSOSpecDeprecationWarningEmitted                bool
+	DexSpecDeprecationWarningEmitted                bool
+	DisableDexDeprecationWarningEmitted             bool
+	ResourceCustomizationsDeprecationWarningEmitted bool
+}
+
+// DeprecationEventEmissionTracker map stores the namespace containing ArgoCD instance as key and DeprecationEventEmissionStatus as value,
+// where DeprecationEventEmissionStatus tracks the events that have been emitted for the instance in the particular namespace.
+// This is temporary and can be removed in v0.0.6 when we remove the deprecated fields.
+var DeprecationEventEmissionTracker = make(map[string]DeprecationEventEmissionStatus)
+
 func namespaceFilterPredicate() predicate.Predicate {
 	return predicate.Funcs{
 		UpdateFunc: func(e event.UpdateEvent) bool {
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 59fb1b2a..e4532565 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
@@ -591,8 +591,15 @@ spec:
         x-descriptors:
         - urn:alm:descriptor:com.tectonic.ui:fieldGroup:Repo
         - urn:alm:descriptor:com.tectonic.ui:resourceRequirements
+      - description: ResourceActions customizes resource action behavior.
+        displayName: Resource Action Customizations'
+        path: resourceActions
+        x-descriptors:
+        - urn:alm:descriptor:com.tectonic.ui:text
+        - urn:alm:descriptor:com.tectonic.ui:advanced
       - description: 'ResourceCustomizations customizes resource behavior. Keys are
-          in the form: group/Kind.'
+          in the form: group/Kind. Please note that this is being deprecated in favor
+          of ResourceHealthChecks, ResourceIgnoreDifferences, and ResourceActions.'
         displayName: Resource Customizations'
         path: resourceCustomizations
         x-descriptors:
@@ -605,6 +612,19 @@ spec:
         x-descriptors:
         - urn:alm:descriptor:com.tectonic.ui:text
         - urn:alm:descriptor:com.tectonic.ui:advanced
+      - description: ResourceHealthChecks customizes resource health check behavior.
+        displayName: Resource Health Check Customizations'
+        path: resourceHealthChecks
+        x-descriptors:
+        - urn:alm:descriptor:com.tectonic.ui:text
+        - urn:alm:descriptor:com.tectonic.ui:advanced
+      - description: ResourceIgnoreDifferences customizes resource ignore difference
+          behavior.
+        displayName: Resource Ignore Difference Customizations'
+        path: resourceIgnoreDifferences
+        x-descriptors:
+        - urn:alm:descriptor:com.tectonic.ui:text
+        - urn:alm:descriptor:com.tectonic.ui:advanced
       - description: ResourceTrackingMethod defines how Argo CD should track resources
           that it manages
         displayName: Resource Tracking Method'
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 d0aab458..ac9429ea 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
@@ -5480,14 +5480,88 @@ spec:
                 description: RepositoryCredentials are the Git pull credentials to
                   configure Argo CD with upon creation of the cluster.
                 type: string
+              resourceActions:
+                description: ResourceActions customizes resource action behavior.
+                items:
+                  description: Resource Customization for custom action
+                  properties:
+                    action:
+                      type: string
+                    group:
+                      type: string
+                    kind:
+                      type: string
+                  type: object
+                type: array
               resourceCustomizations:
                 description: 'ResourceCustomizations customizes resource behavior.
-                  Keys are in the form: group/Kind.'
+                  Keys are in the form: group/Kind. Please note that this is being
+                  deprecated in favor of ResourceHealthChecks, ResourceIgnoreDifferences,
+                  and ResourceActions.'
                 type: string
               resourceExclusions:
                 description: ResourceExclusions is used to completely ignore entire
                   classes of resource group/kinds.
                 type: string
+              resourceHealthChecks:
+                description: ResourceHealthChecks customizes resource health check
+                  behavior.
+                items:
+                  description: Resource Customization for custom health check
+                  properties:
+                    check:
+                      type: string
+                    group:
+                      type: string
+                    kind:
+                      type: string
+                  type: object
+                type: array
+              resourceIgnoreDifferences:
+                description: ResourceIgnoreDifferences customizes resource ignore
+                  difference behavior.
+                properties:
+                  all:
+                    properties:
+                      jqPathExpressions:
+                        items:
+                          type: string
+                        type: array
+                      jsonPointers:
+                        items:
+                          type: string
+                        type: array
+                      managedFieldsManagers:
+                        items:
+                          type: string
+                        type: array
+                    type: object
+                  resourceIdentifiers:
+                    items:
+                      description: Resource Customization fields for ignore difference
+                      properties:
+                        customization:
+                          properties:
+                            jqPathExpressions:
+                              items:
+                                type: string
+                              type: array
+                            jsonPointers:
+                              items:
+                                type: string
+                              type: array
+                            managedFieldsManagers:
+                              items:
+                                type: string
+                              type: array
+                          type: object
+                        group:
+                          type: string
+                        kind:
+                          type: string
+                      type: object
+                    type: array
+                type: object
               resourceInclusions:
                 description: ResourceInclusions is used to only include specific group/kinds
                   in the reconciliation process.
diff --git a/docs/reference/argocd.md b/docs/reference/argocd.md
index e7dab5f0..b84bd910 100644
--- a/docs/reference/argocd.md
+++ b/docs/reference/argocd.md
@@ -957,10 +957,133 @@ spec:
 
 ## Resource Customizations
 
-The configuration to customize resource behavior. This property maps directly to the `resource.customizations` field in the `argocd-cm` ConfigMap.
+There are two ways to customize resource behavior- the first way, only available with release v0.5.0+, is with subkeys (`resourceHealthChecks`, `resourceIgnoreDifferences`, and `resourceActions`), the second is without subkeys (`resourceCustomizations`). `resourceCustomizations` maps directly to the `resource.customizations` field in the `argocd-cm` ConfigMap, while each of the subkeys maps directly to their own field in the `argocd-cm`. `resourceHealthChecks` will map to `resource.customizations.health`, `resourceIgnoreDifferences` to `resource.customizations.ignoreDifferences`, and `resourceActions` to `resource.customizations.actions`.
+
+!!! warning 
+    `resourceCustomizations` is being deprecated so is encouraged to use `resourceHealthChecks`, `resourceIgnoreDifferences`, and `resourceActions` instead. It is the user's responsibility to not provide conflicting resources if they choose to use both methods of resource customizations. 
+
+### Resource Customizations (with subkeys) Example
+
+Keys for `resourceHealthChecks`, `resourceIgnoreDifferences`, and `resourceActions` are in the form (respectively): `resource.customizations.health.<group_kind>`, `resource.customizations.ignoreDifferences.<group_kind>`, and `resource.customizations.actions.<group_kind>`. The following example defines a custom health check, custom action, and an ignoreDifferences config in the `argocd-cm` ConfigMap. 
+
+``` yaml
+apiVersion: argoproj.io/v1alpha1
+kind: ArgoCD
+metadata:
+  name: example-argocd
+  labels:
+    example: resource-customizations
+spec:
+  resourceHealthChecks:
+    - group: certmanager.k8s.io
+      kind: Certificate
+      check: |
+        hs = {}
+        if obj.status ~= nil then
+          if obj.status.conditions ~= nil then
+            for i, condition in ipairs(obj.status.conditions) do
+              if condition.type == "Ready" and condition.status == "False" then
+                hs.status = "Degraded"
+                hs.message = condition.message
+                return hs
+              end
+              if condition.type == "Ready" and condition.status == "True" then
+                hs.status = "Healthy"
+                hs.message = condition.message
+                return hs
+              end
+            end
+          end
+        end
+        hs.status = "Progressing"
+        hs.message = "Waiting for certificate"
+        return hs
+  resourceActions:
+  - group: apps
+    kind: Deployment
+    action: |
+      discovery.lua: |
+        actions = {}
+        actions["restart"] = {}
+        return actions
+      definitions:
+        - name: restart
+          # Lua Script to modify the obj
+          action.lua: |
+            local os = require("os")
+            if obj.spec.template.metadata == nil then
+                obj.spec.template.metadata = {}
+            end
+            if obj.spec.template.metadata.annotations == nil then
+                obj.spec.template.metadata.annotations = {}
+            end
+            obj.spec.template.metadata.annotations["kubectl.kubernetes.io/restartedAt"] = os.date("!%Y-%m-%dT%XZ")
+            return obj
+  resourceIgnoreDifferences:
+  - group: admissionregistration.k8s.io
+    kind: MutatingWebhookConfiguration
+    jqPathExpressions: |
+      jsonPointers: |
+      - /webhooks/0/clientConfig/caBundle
+```
+ After applying these changes your `argocd-cm` Configmap should contain the following fields: 
+
+```
+resource.customizations.actions.apps_Deployment:
+----
+discovery.lua: |
+  actions = {}
+  actions["restart"] = {}
+  return actions
+definitions:
+  - name: restart
+    # Lua Script to modify the obj
+    action.lua: |
+      local os = require("os")
+      if obj.spec.template.metadata == nil then
+          obj.spec.template.metadata = {}
+      end
+      if obj.spec.template.metadata.annotations == nil then
+          obj.spec.template.metadata.annotations = {}
+      end
+      obj.spec.template.metadata.annotations["kubectl.kubernetes.io/restartedAt"] = os.date("!%Y-%m-%dT%XZ")
+      return obj
+
+resource.customizations.ignoreDifferences.admissionregistration.k8s.io_MutatingWebhookConfiguration
+----
+jsonPointers: |
+- /webhooks/0/clientConfig/caBundle
+
+resource.customizations.health.certmanager.k8s.io_Certificate:
+----
+hs = {}
+if obj.status ~= nil then
+  if obj.status.conditions ~= nil then
+    for i, condition in ipairs(obj.status.conditions) do
+      if condition.type == "Ready" and condition.status == "False" then
+        hs.status = "Degraded"
+        hs.message = condition.message
+        return hs
+      end
+      if condition.type == "Ready" and condition.status == "True" then
+        hs.status = "Healthy"
+        hs.message = condition.message
+        return hs
+      end
+    end
+  end
+end
+hs.status = "Progressing"
+hs.message = "Waiting for certificate"
+return hs
+
+```
 
 ### Resource Customizations Example
 
+!!! warning 
+    `resourceCustomizations` is being deprecated in favor of `resourceHealthChecks`, `resourceIgnoreDifferences`, and `resourceActions`.
+
 The following example defines a custom PVC health check in the `argocd-cm` ConfigMap using the `ResourceCustomizations` property on the `ArgoCD` resource.
 
 ``` yaml
diff --git a/examples/argocd-resource-customizations.yaml b/examples/argocd-resource-customizations.yaml
new file mode 100644
index 00000000..e9eb96e8
--- /dev/null
+++ b/examples/argocd-resource-customizations.yaml
@@ -0,0 +1,86 @@
+apiVersion: argoproj.io/v1alpha1
+kind: ArgoCD
+metadata:
+  name: argocd
+spec:
+  resourceIgnoreDifferences:
+    all:
+      jqPathExpressions:
+          - xyz
+          - abc
+      jsonPointers:
+          - xyz
+          - abc
+      managedFieldsManagers:
+          - xyz
+          - abc
+    resourceIdentifiers:
+      - group: apps
+        kind: deployments
+        customization:
+          jqPathExpressions:
+            - xyz
+            - abc
+          jsonPointers:
+            - xyz
+            - abc
+          managedFieldManagers:
+            - xyz
+            - abc
+      - group: batch
+        kind: jobs
+        customization:
+          jqPathExpressions:
+            - xyz
+            - abc
+          jsonPointers:
+            - xyz
+            - abc
+          managedFieldsManagers:
+            - xyz
+            - abc
+  resourceHealthChecks:
+    - group: certmanager.k8s.io
+      kind: Certificate
+      check: |
+        hs = {}
+        if obj.status ~= nil then
+          if obj.status.conditions ~= nil then
+            for i, condition in ipairs(obj.status.conditions) do
+              if condition.type == "Ready" and condition.status == "False" then
+                hs.status = "Degraded"
+                hs.message = condition.message
+                return hs
+              end
+              if condition.type == "Ready" and condition.status == "True" then
+                hs.status = "Healthy"
+                hs.message = condition.message
+                return hs
+              end
+            end
+          end
+        end
+        hs.status = "Progressing"
+        hs.message = "Waiting for certificate"
+        return hs
+  resourceActions:
+    - group: apps
+      kind: Deployment
+      action: |
+        discovery.lua: |
+        actions = {}
+        actions["restart"] = {}
+        return actions
+        definitions:
+        - name: restart
+          # Lua Script to modify the obj
+          action.lua: |
+            local os = require("os")
+            if obj.spec.template.metadata == nil then
+                obj.spec.template.metadata = {}
+            end
+            if obj.spec.template.metadata.annotations == nil then
+                obj.spec.template.metadata.annotations = {}
+            end
+            obj.spec.template.metadata.annotations["kubectl.kubernetes.io/restartedAt"] = os.date("!%Y-%m-%dT%XZ")
+            return obj
\ No newline at end of file


Test patch:
diff --git a/controllers/argocd/configmap_test.go b/controllers/argocd/configmap_test.go
index 6d71b099..c53012fc 100644
--- a/controllers/argocd/configmap_test.go
+++ b/controllers/argocd/configmap_test.go
@@ -791,6 +791,132 @@ func TestReconcileArgoCD_reconcileArgoConfigMap_withResourceCustomizations(t *te
 	}
 }
 
+func TestReconcileArgoCD_reconcileArgoConfigMap_withNewResourceCustomizations(t *testing.T) {
+	logf.SetLogger(ZapLogger(true))
+
+	desiredIgnoreDifferenceCustomization :=
+		`jqpathexpressions:
+- a
+- b
+jsonpointers:
+- a
+- b
+managedfieldsmanagers:
+- a
+- b
+`
+
+	health := []argoprojv1alpha1.ResourceHealthCheck{
+		{
+			Group: "healthFoo",
+			Kind:  "healthFoo",
+			Check: "healthFoo",
+		},
+		{
+			Group: "healthBar",
+			Kind:  "healthBar",
+			Check: "healthBar",
+		},
+	}
+	actions := []argoprojv1alpha1.ResourceAction{
+		{
+			Group:  "actionsFoo",
+			Kind:   "actionsFoo",
+			Action: "actionsFoo",
+		},
+		{
+			Group:  "actionsBar",
+			Kind:   "actionsBar",
+			Action: "actionsBar",
+		},
+	}
+	ignoreDifferences := argoprojv1alpha1.ResourceIgnoreDifference{
+		All: &v1alpha1.IgnoreDifferenceCustomization{
+			JqPathExpressions:     []string{"a", "b"},
+			JsonPointers:          []string{"a", "b"},
+			ManagedFieldsManagers: []string{"a", "b"},
+		},
+		ResourceIdentifiers: []argoprojv1alpha1.ResourceIdentifiers{
+			{
+				Group: "ignoreDiffBar",
+				Kind:  "ignoreDiffBar",
+				Customization: v1alpha1.IgnoreDifferenceCustomization{
+					JqPathExpressions:     []string{"a", "b"},
+					JsonPointers:          []string{"a", "b"},
+					ManagedFieldsManagers: []string{"a", "b"},
+				},
+			},
+		},
+	}
+
+	a := makeTestArgoCD(func(a *argoprojv1alpha1.ArgoCD) {
+		a.Spec.ResourceHealthChecks = health
+		a.Spec.ResourceActions = actions
+		a.Spec.ResourceIgnoreDifferences = &ignoreDifferences
+	})
+	r := makeTestReconciler(t, a)
+
+	err := r.reconcileArgoConfigMap(a)
+	assert.NoError(t, err)
+
+	cm := &corev1.ConfigMap{}
+	err = r.Client.Get(context.TODO(), types.NamespacedName{
+		Name:      common.ArgoCDConfigMapName,
+		Namespace: testNamespace,
+	}, cm)
+	assert.NoError(t, err)
+
+	desiredCM := make(map[string]string)
+	desiredCM["resource.customizations.health.healthFoo_healthFoo"] = "healthFoo"
+	desiredCM["resource.customizations.health.healthBar_healthBar"] = "healthBar"
+	desiredCM["resource.customizations.actions.actionsFoo_actionsFoo"] = "actionsFoo"
+	desiredCM["resource.customizations.actions.actionsBar_actionsBar"] = "actionsBar"
+	desiredCM["resource.customizations.ignoreDifferences.all"] = desiredIgnoreDifferenceCustomization
+	desiredCM["resource.customizations.ignoreDifferences.ignoreDiffBar_ignoreDiffBar"] = desiredIgnoreDifferenceCustomization
+
+	for k, v := range desiredCM {
+		if value, ok := cm.Data[k]; !ok || value != v {
+			t.Fatalf("reconcileArgoConfigMap failed got %q, want %q", value, desiredCM[k])
+		}
+	}
+}
+
+func TestReconcile_emitEventOnDeprecatedResourceCustomizations(t *testing.T) {
+	logf.SetLogger(ZapLogger(true))
+
+	DeprecationEventEmissionTracker = make(map[string]DeprecationEventEmissionStatus)
+
+	resourceCustomizationsEvent := &corev1.Event{
+		Reason:  "DeprecationNotice",
+		Message: "ResourceCustomizations is deprecated, please use the new formats `ResourceHealthChecks`, `ResourceIgnoreDifferences`, and `ResourceActions` instead.",
+		Action:  "Deprecated",
+	}
+
+	tests := []struct {
+		name       string
+		argoCD     *argoprojv1alpha1.ArgoCD
+		wantEvents []*corev1.Event
+	}{
+		{
+			name: "ResourceCustomizations used",
+			argoCD: makeTestArgoCD(func(ac *argoprojv1alpha1.ArgoCD) {
+				ac.Spec.ResourceCustomizations = "testing: testing"
+			}),
+			wantEvents: []*corev1.Event{resourceCustomizationsEvent},
+		},
+	}
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			r := makeFakeReconciler(t, test.argoCD)
+			err := r.reconcileArgoConfigMap(test.argoCD)
+			assert.NoError(t, err)
+			gotEventList := &corev1.EventList{}
+			err = r.Client.List(context.TODO(), gotEventList)
+			assert.NoError(t, err)
+			assert.Equal(t, len(test.wantEvents), len(gotEventList.Items))
+		})
+	}
+}
 func TestReconcileArgoCD_reconcileArgoConfigMap_withExtraConfig(t *testing.T) {
 	a := makeTestArgoCD()
 	r := makeTestReconciler(t, a)
diff --git a/tests/k8s/1-024_validate_resource_health_checks/01-argocd-with-resource-health-check.yaml b/tests/k8s/1-024_validate_resource_health_checks/01-argocd-with-resource-health-check.yaml
new file mode 100644
index 00000000..2e797c1e
--- /dev/null
+++ b/tests/k8s/1-024_validate_resource_health_checks/01-argocd-with-resource-health-check.yaml
@@ -0,0 +1,29 @@
+apiVersion: argoproj.io/v1alpha1
+kind: ArgoCD
+metadata:
+  name: example-argocd
+spec:
+  resourceHealthChecks:
+  - group: certmanager.k8s.io
+    kind: Certificate
+    check: |
+      hs = {}
+      if obj.status ~= nil then
+        if obj.status.conditions ~= nil then
+          for i, condition in ipairs(obj.status.conditions) do
+            if condition.type == "Ready" and condition.status == "False" then
+              hs.status = "Degraded"
+              hs.message = condition.message
+              return hs
+            end
+            if condition.type == "Ready" and condition.status == "True" then
+              hs.status = "Healthy"
+              hs.message = condition.message
+              return hs
+            end
+          end
+        end
+      end
+      hs.status = "Progressing"
+      hs.message = "Waiting for certificate"
+      return hs
\ No newline at end of file
diff --git a/tests/k8s/1-024_validate_resource_health_checks/01-assert.yaml b/tests/k8s/1-024_validate_resource_health_checks/01-assert.yaml
new file mode 100644
index 00000000..37edf42b
--- /dev/null
+++ b/tests/k8s/1-024_validate_resource_health_checks/01-assert.yaml
@@ -0,0 +1,37 @@
+apiVersion: kuttl.dev/v1beta1
+kind: TestAssert
+timeout: 120
+---
+apiVersion: argoproj.io/v1alpha1
+kind: ArgoCD
+metadata:
+  name: example-argocd
+status:
+  phase: Available
+---
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: argocd-cm
+data:
+  resource.customizations.health.certmanager.k8s.io_Certificate: |
+    hs = {}
+    if obj.status ~= nil then
+      if obj.status.conditions ~= nil then
+        for i, condition in ipairs(obj.status.conditions) do
+          if condition.type == "Ready" and condition.status == "False" then
+            hs.status = "Degraded"
+            hs.message = condition.message
+            return hs
+          end
+          if condition.type == "Ready" and condition.status == "True" then
+            hs.status = "Healthy"
+            hs.message = condition.message
+            return hs
+          end
+        end
+      end
+    end
+    hs.status = "Progressing"
+    hs.message = "Waiting for certificate"
+    return hs
\ No newline at end of file
diff --git a/tests/k8s/1-025_validate_resource_ignore_differences/01-argocd-with-resource-ignore-difference.yaml b/tests/k8s/1-025_validate_resource_ignore_differences/01-argocd-with-resource-ignore-difference.yaml
new file mode 100644
index 00000000..f15ef2f7
--- /dev/null
+++ b/tests/k8s/1-025_validate_resource_ignore_differences/01-argocd-with-resource-ignore-difference.yaml
@@ -0,0 +1,41 @@
+apiVersion: argoproj.io/v1alpha1
+kind: ArgoCD
+metadata:
+  name: example-argocd
+spec:
+  resourceIgnoreDifferences:
+    all:
+      jqPathExpressions:
+          - xyz
+          - abc
+      jsonPointers:
+          - xyz
+          - abc
+      managedFieldsManagers:
+          - xyz
+          - abc
+    resourceIdentifiers:
+      - group: apps
+        kind: deployments
+        customization:
+          jqPathExpressions:
+            - xyz
+            - abc
+          jsonPointers:
+            - xyz
+            - abc
+          managedFieldManagers:
+            - xyz
+            - abc
+      - group: batch
+        kind: jobs
+        customization:
+          jqPathExpressions:
+            - xyz
+            - abc
+          jsonPointers:
+            - xyz
+            - abc
+          managedFieldsManagers:
+            - xyz
+            - abc
\ No newline at end of file
diff --git a/tests/k8s/1-025_validate_resource_ignore_differences/01-assert.yaml b/tests/k8s/1-025_validate_resource_ignore_differences/01-assert.yaml
new file mode 100644
index 00000000..1eedf003
--- /dev/null
+++ b/tests/k8s/1-025_validate_resource_ignore_differences/01-assert.yaml
@@ -0,0 +1,44 @@
+apiVersion: kuttl.dev/v1beta1
+kind: TestAssert
+timeout: 120
+---
+apiVersion: argoproj.io/v1alpha1
+kind: ArgoCD
+metadata:
+  name: example-argocd
+status:
+  phase: Available
+---
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: argocd-cm
+data:
+  resource.customizations.ignoreDifferences.all: |
+    jqpathexpressions:
+    - xyz
+    - abc
+    jsonpointers:
+    - xyz
+    - abc
+    managedfieldsmanagers:
+    - xyz
+    - abc
+  resource.customizations.ignoreDifferences.apps_deployments: |
+    jqpathexpressions:
+    - xyz
+    - abc
+    jsonpointers:
+    - xyz
+    - abc
+    managedfieldsmanagers: []
+  resource.customizations.ignoreDifferences.batch_jobs: |
+    jqpathexpressions:
+    - xyz
+    - abc
+    jsonpointers:
+    - xyz
+    - abc
+    managedfieldsmanagers:
+    - xyz
+    - abc
\ No newline at end of file
diff --git a/tests/k8s/1-026_validate_resource_action/01-argocd-with-resource-action.yaml b/tests/k8s/1-026_validate_resource_action/01-argocd-with-resource-action.yaml
new file mode 100644
index 00000000..9e9ea49f
--- /dev/null
+++ b/tests/k8s/1-026_validate_resource_action/01-argocd-with-resource-action.yaml
@@ -0,0 +1,26 @@
+apiVersion: argoproj.io/v1alpha1
+kind: ArgoCD
+metadata:
+  name: example-argocd
+spec:
+  resourceActions:
+  - group: apps
+    kind: Deployment
+    action: |
+      discovery.lua: |
+        actions = {}
+        actions["restart"] = {}
+        return actions
+      definitions:
+        - name: restart
+          # Lua Script to modify the obj
+          action.lua: |
+            local os = require("os")
+            if obj.spec.template.metadata == nil then
+                obj.spec.template.metadata = {}
+            end
+            if obj.spec.template.metadata.annotations == nil then
+                obj.spec.template.metadata.annotations = {}
+            end
+            obj.spec.template.metadata.annotations["kubectl.kubernetes.io/restartedAt"] = os.date("!%Y-%m-%dT%XZ")
+            return obj
\ No newline at end of file
diff --git a/tests/k8s/1-026_validate_resource_action/01-assert.yaml b/tests/k8s/1-026_validate_resource_action/01-assert.yaml
new file mode 100644
index 00000000..fd54b866
--- /dev/null
+++ b/tests/k8s/1-026_validate_resource_action/01-assert.yaml
@@ -0,0 +1,34 @@
+apiVersion: kuttl.dev/v1beta1
+kind: TestAssert
+timeout: 120
+---
+apiVersion: argoproj.io/v1alpha1
+kind: ArgoCD
+metadata:
+  name: example-argocd
+status:
+  phase: Available
+---
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: argocd-cm
+data:
+  resource.customizations.actions.apps_Deployment: |
+    discovery.lua: |
+      actions = {}
+      actions["restart"] = {}
+      return actions
+    definitions:
+      - name: restart
+        # Lua Script to modify the obj
+        action.lua: |
+          local os = require("os")
+          if obj.spec.template.metadata == nil then
+              obj.spec.template.metadata = {}
+          end
+          if obj.spec.template.metadata.annotations == nil then
+              obj.spec.template.metadata.annotations = {}
+          end
+          obj.spec.template.metadata.annotations["kubectl.kubernetes.io/restartedAt"] = os.date("!%Y-%m-%dT%XZ")
+          return obj
\ No newline at end of file