From 7756d7cdd2a2b1fd0a196921203f8a4e00c897c8 Mon Sep 17 00:00:00 2001 From: Shyamsundar Ranganathan Date: Wed, 22 Feb 2023 09:12:07 -0500 Subject: [PATCH 1/5] Update downstream main to contain DS artifacts Add odr and idr bundle build kustomize options Signed-off-by: Shyamsundar Ranganathan --- .../manifests/idr/kustomization.yaml | 55 +++++++++++++++++++ .../manager_openshift_trusted_cabundle.yaml | 21 +++++++ .../manifests/odr/kustomization.yaml | 51 +++++++++++++++++ .../manager_openshift_trusted_cabundle.yaml | 21 +++++++ config/hub/manifests/idr/kustomization.yaml | 55 +++++++++++++++++++ .../manager_openshift_trusted_cabundle.yaml | 21 +++++++ .../idr/ramen_manager_config_append.yaml | 9 +++ config/hub/manifests/odr/kustomization.yaml | 51 +++++++++++++++++ .../manager_openshift_trusted_cabundle.yaml | 21 +++++++ .../odr/ramen_manager_config_append.yaml | 9 +++ 10 files changed, 314 insertions(+) create mode 100644 config/dr-cluster/manifests/idr/kustomization.yaml create mode 100644 config/dr-cluster/manifests/idr/manager_openshift_trusted_cabundle.yaml create mode 100644 config/dr-cluster/manifests/odr/kustomization.yaml create mode 100644 config/dr-cluster/manifests/odr/manager_openshift_trusted_cabundle.yaml create mode 100644 config/hub/manifests/idr/kustomization.yaml create mode 100644 config/hub/manifests/idr/manager_openshift_trusted_cabundle.yaml create mode 100644 config/hub/manifests/idr/ramen_manager_config_append.yaml create mode 100644 config/hub/manifests/odr/kustomization.yaml create mode 100644 config/hub/manifests/odr/manager_openshift_trusted_cabundle.yaml create mode 100644 config/hub/manifests/odr/ramen_manager_config_append.yaml diff --git a/config/dr-cluster/manifests/idr/kustomization.yaml b/config/dr-cluster/manifests/idr/kustomization.yaml new file mode 100644 index 000000000..111776757 --- /dev/null +++ b/config/dr-cluster/manifests/idr/kustomization.yaml @@ -0,0 +1,55 @@ +resources: +- ../bases/ramen_dr_cluster.clusterserviceversion.yaml +- ../../default +- ../../samples +- ../../../scorecard + +configMapGenerator: +- name: openshift-trusted-cabundle + options: + disableNameSuffixHash: true + labels: + config.openshift.io/inject-trusted-cabundle: "true" + +patchesStrategicMerge: +- manager_openshift_trusted_cabundle.yaml + +patches: +- patch: |- + - op: add + path: /metadata/annotations/operatorframework.io~1suggested-namespace + value: openshift-dr-system + - op: replace + path: /spec/icon + value: + - base64data: >- + PHN2ZyBpZD0iU3BlY3RydW1GdXNpb24iIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHZpZXdCb3g9IjAgMCAzMiAzMiI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSI5ZjVmbzEweDdiIiB4MT0iNS45MjUiIHkxPSIxNi41NDkiIHgyPSIyNC4xNjUiIHkyPSI2LjAxOCIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPjxzdG9wIG9mZnNldD0iMCIgc3RvcC1jb2xvcj0iI2ZmZiIgc3RvcC1vcGFjaXR5PSIwIi8+PHN0b3Agb2Zmc2V0PSIuNDUiIHN0b3AtY29sb3I9IiNmZmYiLz48L2xpbmVhckdyYWRpZW50PjxsaW5lYXJHcmFkaWVudCBpZD0ic2F1bmxlajA2YSIgeDE9IjIwLjQ5MyIgeTE9IjI4IiB4Mj0iMjAuNDkzIiB5Mj0iNyIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPjxzdG9wIG9mZnNldD0iLjU1IiBzdG9wLWNvbG9yPSIjZmZmIi8+PHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjZmZmIiBzdG9wLW9wYWNpdHk9IjAiLz48L2xpbmVhckdyYWRpZW50PjxsaW5lYXJHcmFkaWVudCBpZD0iZ284Mms5Mm4zYyIgeDE9IjMuNDE5IiB5MT0iMTQuMDA3IiB4Mj0iMjEuNjA1IiB5Mj0iMjQuNTA3IiB4bGluazpocmVmPSIjc2F1bmxlajA2YSIvPjxsaW5lYXJHcmFkaWVudCBpZD0iam01MDRta2c0ZSIgeDE9Ii0yOTQ2IiB5MT0iLTQ5ODYiIHgyPSItMjkxNCIgeTI9Ii01MDE4IiBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDEgMCAwIC0xIDI5NDYgLTQ5ODYpIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHN0b3Agb2Zmc2V0PSIuMSIgc3RvcC1jb2xvcj0iIzhhM2ZmYyIvPjxzdG9wIG9mZnNldD0iLjkiIHN0b3AtY29sb3I9IiNlZTUzOTYiLz48L2xpbmVhckdyYWRpZW50PjxtYXNrIGlkPSI5bHhiamJ0dTZkIiB4PSIwIiB5PSIwIiB3aWR0aD0iMzIiIGhlaWdodD0iMzIiIG1hc2tVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoIGQ9Ik0yNCAxNmgtMlY2LjU4bC02LTMuNDI3LTEzLjM1NiA3LjcxMy0xLTEuNzMyIDEzLjg1Ni04YTEgMSAwIDAgMSAxIDBsNyA0QTEgMSAwIDAgMSAyNCA2eiIgc3R5bGU9ImZpbGw6dXJsKCM5ZjVmbzEweDdiKSIvPjxwYXRoIGQ9Ik0yMSAyOGEuOTkyLjk5MiAwIDAgMS0uNS0uMTM0bC04LjUxMy00LjkxNSAxLTEuNzMyTDIxIDI1Ljg0N2w2LTMuNDI3VjdoMnYxNmExIDEgMCAwIDEtLjUuODY4bC03IDRBMSAxIDAgMCAxIDIxIDI4eiIgc3R5bGU9ImZpbGw6dXJsKCNzYXVubGVqMDZhKSIvPjxwYXRoIGQ9Im0xNy4zNTYgMzEuODY2LTEzLjg1Ni04QTEgMSAwIDAgMSAzIDIzdi04YTEgMSAwIDAgMSAuNS0uODY2bDguNTY3LTQuOTQ2IDEgMS43MzJMNSAxNS41Nzd2Ni44NDZsMTMuMzU2IDcuNzExeiIgc3R5bGU9ImZpbGw6dXJsKCNnbzgyazkybjNjKSIvPjwvbWFzaz48L2RlZnM+PGcgc3R5bGU9Im1hc2s6dXJsKCM5bHhiamJ0dTZkKSI+PHBhdGggdHJhbnNmb3JtPSJyb3RhdGUoLTkwIDE2IDE2KSIgc3R5bGU9ImZpbGw6dXJsKCNqbTUwNG1rZzRlKSIgZD0iTTAgMGgzMnYzMkgweiIvPjwvZz48cGF0aCBkPSJNMTYgMjAuNDY0YTEgMSAwIDAgMS0uNS0uMTM0bC0zLTEuNzMyYTEgMSAwIDAgMS0uNS0uODY2di0zLjQ2NGExIDEgMCAwIDEgLjUtLjg2NmwzLTEuNzMyYTEgMSAwIDAgMSAxIDBsMyAxLjczMmExIDEgMCAwIDEgLjUuODY2djMuNDY0YTEgMSAwIDAgMS0uNS44NjZsLTMgMS43MzJhMSAxIDAgMCAxLS41LjEzNHptLTItMy4zMDkgMiAxLjE1NCAyLTEuMTU0di0yLjMxbC0yLTEuMTU0LTIgMS4xNTR6IiBzdHlsZT0iZmlsbDojMDAxZDZjIi8+PC9zdmc+ + mediatype: image/svg+xml + - op: replace + path: /spec/maintainers + value: + - email: mysphelp@us.ibm.com + name: IBM Support + - op: replace + path: /spec/provider/name + value: IBM + - op: replace + path: /spec/links + value: + - name: Source Code + url: https://github.com/red-hat-storage/ramen + - op: replace + path: /metadata/name + value: odr-cluster-operator.v0.0.0 + - op: replace + path: /spec/displayName + value: Fusion DR Cluster Operator + - op: replace + path: /spec/description + value: Fusion DR Cluster is a disaster-recovery orchestrator for stateful applications, + that operates from an Advanced Cluster Management (ACM) managed cluster and is controlled + by Fusion DR Hub operator to orchestrate the life-cycle of an application, and its state + on the managed cluster. + target: + kind: ClusterServiceVersion + name: ramen-dr-cluster-operator.v0.0.0 diff --git a/config/dr-cluster/manifests/idr/manager_openshift_trusted_cabundle.yaml b/config/dr-cluster/manifests/idr/manager_openshift_trusted_cabundle.yaml new file mode 100644 index 000000000..8a9ccba22 --- /dev/null +++ b/config/dr-cluster/manifests/idr/manager_openshift_trusted_cabundle.yaml @@ -0,0 +1,21 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: operator + namespace: system +spec: + template: + spec: + containers: + - name: manager + volumeMounts: + - name: ramen-manager-trustedca-vol + mountPath: /etc/pki/ca-trust/extracted/pem + readOnly: true + volumes: + - name: ramen-manager-trustedca-vol + configMap: + name: openshift-trusted-cabundle + items: + - key: ca-bundle.crt + path: tls-ca-bundle.pem diff --git a/config/dr-cluster/manifests/odr/kustomization.yaml b/config/dr-cluster/manifests/odr/kustomization.yaml new file mode 100644 index 000000000..326db3331 --- /dev/null +++ b/config/dr-cluster/manifests/odr/kustomization.yaml @@ -0,0 +1,51 @@ +resources: +- ../bases/ramen_dr_cluster.clusterserviceversion.yaml +- ../../default +- ../../samples +- ../../../scorecard + +configMapGenerator: +- name: openshift-trusted-cabundle + options: + disableNameSuffixHash: true + labels: + config.openshift.io/inject-trusted-cabundle: "true" + +patchesStrategicMerge: +- manager_openshift_trusted_cabundle.yaml + +patches: +- patch: |- + - op: add + path: /metadata/annotations/operatorframework.io~1suggested-namespace + value: openshift-dr-system + - op: replace + path: /spec/icon + value: + - base64data: PHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllciAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxOTIgMTQ1Ij48ZGVmcz48c3R5bGU+LmNscy0xe2ZpbGw6I2UwMDt9PC9zdHlsZT48L2RlZnM+PHRpdGxlPlJlZEhhdC1Mb2dvLUhhdC1Db2xvcjwvdGl0bGU+PHBhdGggZD0iTTE1Ny43Nyw2Mi42MWExNCwxNCwwLDAsMSwuMzEsMy40MmMwLDE0Ljg4LTE4LjEsMTcuNDYtMzAuNjEsMTcuNDZDNzguODMsODMuNDksNDIuNTMsNTMuMjYsNDIuNTMsNDRhNi40Myw2LjQzLDAsMCwxLC4yMi0xLjk0bC0zLjY2LDkuMDZhMTguNDUsMTguNDUsMCwwLDAtMS41MSw3LjMzYzAsMTguMTEsNDEsNDUuNDgsODcuNzQsNDUuNDgsMjAuNjksMCwzNi40My03Ljc2LDM2LjQzLTIxLjc3LDAtMS4wOCwwLTEuOTQtMS43My0xMC4xM1oiLz48cGF0aCBjbGFzcz0iY2xzLTEiIGQ9Ik0xMjcuNDcsODMuNDljMTIuNTEsMCwzMC42MS0yLjU4LDMwLjYxLTE3LjQ2YTE0LDE0LDAsMCwwLS4zMS0zLjQybC03LjQ1LTMyLjM2Yy0xLjcyLTcuMTItMy4yMy0xMC4zNS0xNS43My0xNi42QzEyNC44OSw4LjY5LDEwMy43Ni41LDk3LjUxLjUsOTEuNjkuNSw5MCw4LDgzLjA2LDhjLTYuNjgsMC0xMS42NC01LjYtMTcuODktNS42LTYsMC05LjkxLDQuMDktMTIuOTMsMTIuNSwwLDAtOC40MSwyMy43Mi05LjQ5LDI3LjE2QTYuNDMsNi40MywwLDAsMCw0Mi41Myw0NGMwLDkuMjIsMzYuMywzOS40NSw4NC45NCwzOS40NU0xNjAsNzIuMDdjMS43Myw4LjE5LDEuNzMsOS4wNSwxLjczLDEwLjEzLDAsMTQtMTUuNzQsMjEuNzctMzYuNDMsMjEuNzdDNzguNTQsMTA0LDM3LjU4LDc2LjYsMzcuNTgsNTguNDlhMTguNDUsMTguNDUsMCwwLDEsMS41MS03LjMzQzIyLjI3LDUyLC41LDU1LC41LDc0LjIyYzAsMzEuNDgsNzQuNTksNzAuMjgsMTMzLjY1LDcwLjI4LDQ1LjI4LDAsNTYuNy0yMC40OCw1Ni43LTM2LjY1LDAtMTIuNzItMTEtMjcuMTYtMzAuODMtMzUuNzgiLz48L3N2Zz4= + mediatype: image/svg+xml + - op: replace + path: /spec/maintainers + value: + - email: ocs-support@redhat.com + name: Red Hat Support + - op: replace + path: /spec/links + value: + - name: Source Code + url: https://github.com/red-hat-storage/ramen + - op: replace + path: /metadata/name + value: odr-cluster-operator.v0.0.0 + - op: replace + path: /spec/displayName + value: Openshift DR Cluster Operator + - op: replace + path: /spec/description + value: OpenShift DR Cluster is a disaster-recovery orchestrator for stateful applications, + that operates from an Advanced Cluster Management (ACM) managed cluster and is controlled + by Openshift DR Hub operator to orchestrate the life-cycle of an application, and its state + on the managed cluster. + target: + kind: ClusterServiceVersion + name: ramen-dr-cluster-operator.v0.0.0 diff --git a/config/dr-cluster/manifests/odr/manager_openshift_trusted_cabundle.yaml b/config/dr-cluster/manifests/odr/manager_openshift_trusted_cabundle.yaml new file mode 100644 index 000000000..8a9ccba22 --- /dev/null +++ b/config/dr-cluster/manifests/odr/manager_openshift_trusted_cabundle.yaml @@ -0,0 +1,21 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: operator + namespace: system +spec: + template: + spec: + containers: + - name: manager + volumeMounts: + - name: ramen-manager-trustedca-vol + mountPath: /etc/pki/ca-trust/extracted/pem + readOnly: true + volumes: + - name: ramen-manager-trustedca-vol + configMap: + name: openshift-trusted-cabundle + items: + - key: ca-bundle.crt + path: tls-ca-bundle.pem diff --git a/config/hub/manifests/idr/kustomization.yaml b/config/hub/manifests/idr/kustomization.yaml new file mode 100644 index 000000000..9c6a00be7 --- /dev/null +++ b/config/hub/manifests/idr/kustomization.yaml @@ -0,0 +1,55 @@ +resources: +- ../bases/ramen_hub.clusterserviceversion.yaml +- ../../default/ocp +- ../../samples +- ../../../scorecard + +configMapGenerator: +- name: openshift-trusted-cabundle + options: + disableNameSuffixHash: true + labels: + config.openshift.io/inject-trusted-cabundle: "true" + +patchesStrategicMerge: +- manager_openshift_trusted_cabundle.yaml + +patches: +- patch: |- + - op: add + path: /metadata/annotations/operatorframework.io~1suggested-namespace + value: openshift-dr-system + - op: replace + path: /spec/icon + value: + - base64data: >- + PHN2ZyBpZD0iU3BlY3RydW1GdXNpb24iIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHZpZXdCb3g9IjAgMCAzMiAzMiI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSI5ZjVmbzEweDdiIiB4MT0iNS45MjUiIHkxPSIxNi41NDkiIHgyPSIyNC4xNjUiIHkyPSI2LjAxOCIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPjxzdG9wIG9mZnNldD0iMCIgc3RvcC1jb2xvcj0iI2ZmZiIgc3RvcC1vcGFjaXR5PSIwIi8+PHN0b3Agb2Zmc2V0PSIuNDUiIHN0b3AtY29sb3I9IiNmZmYiLz48L2xpbmVhckdyYWRpZW50PjxsaW5lYXJHcmFkaWVudCBpZD0ic2F1bmxlajA2YSIgeDE9IjIwLjQ5MyIgeTE9IjI4IiB4Mj0iMjAuNDkzIiB5Mj0iNyIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPjxzdG9wIG9mZnNldD0iLjU1IiBzdG9wLWNvbG9yPSIjZmZmIi8+PHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjZmZmIiBzdG9wLW9wYWNpdHk9IjAiLz48L2xpbmVhckdyYWRpZW50PjxsaW5lYXJHcmFkaWVudCBpZD0iZ284Mms5Mm4zYyIgeDE9IjMuNDE5IiB5MT0iMTQuMDA3IiB4Mj0iMjEuNjA1IiB5Mj0iMjQuNTA3IiB4bGluazpocmVmPSIjc2F1bmxlajA2YSIvPjxsaW5lYXJHcmFkaWVudCBpZD0iam01MDRta2c0ZSIgeDE9Ii0yOTQ2IiB5MT0iLTQ5ODYiIHgyPSItMjkxNCIgeTI9Ii01MDE4IiBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDEgMCAwIC0xIDI5NDYgLTQ5ODYpIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHN0b3Agb2Zmc2V0PSIuMSIgc3RvcC1jb2xvcj0iIzhhM2ZmYyIvPjxzdG9wIG9mZnNldD0iLjkiIHN0b3AtY29sb3I9IiNlZTUzOTYiLz48L2xpbmVhckdyYWRpZW50PjxtYXNrIGlkPSI5bHhiamJ0dTZkIiB4PSIwIiB5PSIwIiB3aWR0aD0iMzIiIGhlaWdodD0iMzIiIG1hc2tVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoIGQ9Ik0yNCAxNmgtMlY2LjU4bC02LTMuNDI3LTEzLjM1NiA3LjcxMy0xLTEuNzMyIDEzLjg1Ni04YTEgMSAwIDAgMSAxIDBsNyA0QTEgMSAwIDAgMSAyNCA2eiIgc3R5bGU9ImZpbGw6dXJsKCM5ZjVmbzEweDdiKSIvPjxwYXRoIGQ9Ik0yMSAyOGEuOTkyLjk5MiAwIDAgMS0uNS0uMTM0bC04LjUxMy00LjkxNSAxLTEuNzMyTDIxIDI1Ljg0N2w2LTMuNDI3VjdoMnYxNmExIDEgMCAwIDEtLjUuODY4bC03IDRBMSAxIDAgMCAxIDIxIDI4eiIgc3R5bGU9ImZpbGw6dXJsKCNzYXVubGVqMDZhKSIvPjxwYXRoIGQ9Im0xNy4zNTYgMzEuODY2LTEzLjg1Ni04QTEgMSAwIDAgMSAzIDIzdi04YTEgMSAwIDAgMSAuNS0uODY2bDguNTY3LTQuOTQ2IDEgMS43MzJMNSAxNS41Nzd2Ni44NDZsMTMuMzU2IDcuNzExeiIgc3R5bGU9ImZpbGw6dXJsKCNnbzgyazkybjNjKSIvPjwvbWFzaz48L2RlZnM+PGcgc3R5bGU9Im1hc2s6dXJsKCM5bHhiamJ0dTZkKSI+PHBhdGggdHJhbnNmb3JtPSJyb3RhdGUoLTkwIDE2IDE2KSIgc3R5bGU9ImZpbGw6dXJsKCNqbTUwNG1rZzRlKSIgZD0iTTAgMGgzMnYzMkgweiIvPjwvZz48cGF0aCBkPSJNMTYgMjAuNDY0YTEgMSAwIDAgMS0uNS0uMTM0bC0zLTEuNzMyYTEgMSAwIDAgMS0uNS0uODY2di0zLjQ2NGExIDEgMCAwIDEgLjUtLjg2NmwzLTEuNzMyYTEgMSAwIDAgMSAxIDBsMyAxLjczMmExIDEgMCAwIDEgLjUuODY2djMuNDY0YTEgMSAwIDAgMS0uNS44NjZsLTMgMS43MzJhMSAxIDAgMCAxLS41LjEzNHptLTItMy4zMDkgMiAxLjE1NCAyLTEuMTU0di0yLjMxbC0yLTEuMTU0LTIgMS4xNTR6IiBzdHlsZT0iZmlsbDojMDAxZDZjIi8+PC9zdmc+ + mediatype: image/svg+xml + - op: replace + path: /spec/maintainers + value: + - email: mysphelp@us.ibm.com + name: IBM Support + - op: replace + path: /spec/provider/name + value: IBM + - op: replace + path: /spec/links + value: + - name: Source Code + url: https://github.com/red-hat-storage/ramen + - op: replace + path: /metadata/name + value: odr-hub-operator.v0.0.0 + - op: replace + path: /spec/displayName + value: Fusion DR Hub Operator + - op: replace + path: /spec/description + value: Fusion DR Hub is a disaster-recovery orchestrator for stateful applications. + It operates from an Advanced Cluster Management (ACM) hub cluster to orchestrate + the recovery of application state, and scheduling of ACM PlacementRule for disaster + recovery operations. + target: + kind: ClusterServiceVersion + name: ramen-hub-operator.v0.0.0 diff --git a/config/hub/manifests/idr/manager_openshift_trusted_cabundle.yaml b/config/hub/manifests/idr/manager_openshift_trusted_cabundle.yaml new file mode 100644 index 000000000..8a9ccba22 --- /dev/null +++ b/config/hub/manifests/idr/manager_openshift_trusted_cabundle.yaml @@ -0,0 +1,21 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: operator + namespace: system +spec: + template: + spec: + containers: + - name: manager + volumeMounts: + - name: ramen-manager-trustedca-vol + mountPath: /etc/pki/ca-trust/extracted/pem + readOnly: true + volumes: + - name: ramen-manager-trustedca-vol + configMap: + name: openshift-trusted-cabundle + items: + - key: ca-bundle.crt + path: tls-ca-bundle.pem diff --git a/config/hub/manifests/idr/ramen_manager_config_append.yaml b/config/hub/manifests/idr/ramen_manager_config_append.yaml new file mode 100644 index 000000000..c1231082e --- /dev/null +++ b/config/hub/manifests/idr/ramen_manager_config_append.yaml @@ -0,0 +1,9 @@ +drClusterOperator: + deploymentAutomationEnabled: true + s3SecretDistributionEnabled: true + channelName: alpha + packageName: ramen-dr-cluster-operator + namespaceName: ramen-system + catalogSourceName: ibm-catalogsource + catalogSourceNamespaceName: openshift-marketplace + clusterServiceVersionName: ramen-dr-cluster-operator.v0.0.1 diff --git a/config/hub/manifests/odr/kustomization.yaml b/config/hub/manifests/odr/kustomization.yaml new file mode 100644 index 000000000..bf6f27ea0 --- /dev/null +++ b/config/hub/manifests/odr/kustomization.yaml @@ -0,0 +1,51 @@ +resources: +- ../bases/ramen_hub.clusterserviceversion.yaml +- ../../default/ocp +- ../../samples +- ../../../scorecard + +configMapGenerator: +- name: openshift-trusted-cabundle + options: + disableNameSuffixHash: true + labels: + config.openshift.io/inject-trusted-cabundle: "true" + +patchesStrategicMerge: +- manager_openshift_trusted_cabundle.yaml + +patches: +- patch: |- + - op: add + path: /metadata/annotations/operatorframework.io~1suggested-namespace + value: openshift-dr-system + - op: replace + path: /spec/icon + value: + - base64data: PHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllciAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxOTIgMTQ1Ij48ZGVmcz48c3R5bGU+LmNscy0xe2ZpbGw6I2UwMDt9PC9zdHlsZT48L2RlZnM+PHRpdGxlPlJlZEhhdC1Mb2dvLUhhdC1Db2xvcjwvdGl0bGU+PHBhdGggZD0iTTE1Ny43Nyw2Mi42MWExNCwxNCwwLDAsMSwuMzEsMy40MmMwLDE0Ljg4LTE4LjEsMTcuNDYtMzAuNjEsMTcuNDZDNzguODMsODMuNDksNDIuNTMsNTMuMjYsNDIuNTMsNDRhNi40Myw2LjQzLDAsMCwxLC4yMi0xLjk0bC0zLjY2LDkuMDZhMTguNDUsMTguNDUsMCwwLDAtMS41MSw3LjMzYzAsMTguMTEsNDEsNDUuNDgsODcuNzQsNDUuNDgsMjAuNjksMCwzNi40My03Ljc2LDM2LjQzLTIxLjc3LDAtMS4wOCwwLTEuOTQtMS43My0xMC4xM1oiLz48cGF0aCBjbGFzcz0iY2xzLTEiIGQ9Ik0xMjcuNDcsODMuNDljMTIuNTEsMCwzMC42MS0yLjU4LDMwLjYxLTE3LjQ2YTE0LDE0LDAsMCwwLS4zMS0zLjQybC03LjQ1LTMyLjM2Yy0xLjcyLTcuMTItMy4yMy0xMC4zNS0xNS43My0xNi42QzEyNC44OSw4LjY5LDEwMy43Ni41LDk3LjUxLjUsOTEuNjkuNSw5MCw4LDgzLjA2LDhjLTYuNjgsMC0xMS42NC01LjYtMTcuODktNS42LTYsMC05LjkxLDQuMDktMTIuOTMsMTIuNSwwLDAtOC40MSwyMy43Mi05LjQ5LDI3LjE2QTYuNDMsNi40MywwLDAsMCw0Mi41Myw0NGMwLDkuMjIsMzYuMywzOS40NSw4NC45NCwzOS40NU0xNjAsNzIuMDdjMS43Myw4LjE5LDEuNzMsOS4wNSwxLjczLDEwLjEzLDAsMTQtMTUuNzQsMjEuNzctMzYuNDMsMjEuNzdDNzguNTQsMTA0LDM3LjU4LDc2LjYsMzcuNTgsNTguNDlhMTguNDUsMTguNDUsMCwwLDEsMS41MS03LjMzQzIyLjI3LDUyLC41LDU1LC41LDc0LjIyYzAsMzEuNDgsNzQuNTksNzAuMjgsMTMzLjY1LDcwLjI4LDQ1LjI4LDAsNTYuNy0yMC40OCw1Ni43LTM2LjY1LDAtMTIuNzItMTEtMjcuMTYtMzAuODMtMzUuNzgiLz48L3N2Zz4= + mediatype: image/svg+xml + - op: replace + path: /spec/maintainers + value: + - email: ocs-support@redhat.com + name: Red Hat Support + - op: replace + path: /spec/links + value: + - name: Source Code + url: https://github.com/red-hat-storage/ramen + - op: replace + path: /metadata/name + value: odr-hub-operator.v0.0.0 + - op: replace + path: /spec/displayName + value: Openshift DR Hub Operator + - op: replace + path: /spec/description + value: OpenShift DR Hub is a disaster-recovery orchestrator for stateful applications. + It operates from an Advanced Cluster Management (ACM) hub cluster to orchestrate + the recovery of application state, and scheduling of ACM PlacementRule for disaster + recovery operations. + target: + kind: ClusterServiceVersion + name: ramen-hub-operator.v0.0.0 diff --git a/config/hub/manifests/odr/manager_openshift_trusted_cabundle.yaml b/config/hub/manifests/odr/manager_openshift_trusted_cabundle.yaml new file mode 100644 index 000000000..8a9ccba22 --- /dev/null +++ b/config/hub/manifests/odr/manager_openshift_trusted_cabundle.yaml @@ -0,0 +1,21 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: operator + namespace: system +spec: + template: + spec: + containers: + - name: manager + volumeMounts: + - name: ramen-manager-trustedca-vol + mountPath: /etc/pki/ca-trust/extracted/pem + readOnly: true + volumes: + - name: ramen-manager-trustedca-vol + configMap: + name: openshift-trusted-cabundle + items: + - key: ca-bundle.crt + path: tls-ca-bundle.pem diff --git a/config/hub/manifests/odr/ramen_manager_config_append.yaml b/config/hub/manifests/odr/ramen_manager_config_append.yaml new file mode 100644 index 000000000..58a624c32 --- /dev/null +++ b/config/hub/manifests/odr/ramen_manager_config_append.yaml @@ -0,0 +1,9 @@ +drClusterOperator: + deploymentAutomationEnabled: true + s3SecretDistributionEnabled: true + channelName: alpha + packageName: ramen-dr-cluster-operator + namespaceName: ramen-system + catalogSourceName: redhat-operators + catalogSourceNamespaceName: openshift-marketplace + clusterServiceVersionName: ramen-dr-cluster-operator.v0.0.1 From 5cb63d3bc86719032de9fa9e7096e97c0863b30f Mon Sep 17 00:00:00 2001 From: rakeshgm Date: Tue, 14 May 2024 17:42:27 +0530 Subject: [PATCH 2/5] add missing label to configMapGenerator Signed-off-by: rakeshgm --- config/dr-cluster/manifests/idr/kustomization.yaml | 1 + config/dr-cluster/manifests/odr/kustomization.yaml | 1 + config/hub/manifests/idr/kustomization.yaml | 1 + config/hub/manifests/odr/kustomization.yaml | 1 + 4 files changed, 4 insertions(+) diff --git a/config/dr-cluster/manifests/idr/kustomization.yaml b/config/dr-cluster/manifests/idr/kustomization.yaml index 111776757..60b24e475 100644 --- a/config/dr-cluster/manifests/idr/kustomization.yaml +++ b/config/dr-cluster/manifests/idr/kustomization.yaml @@ -10,6 +10,7 @@ configMapGenerator: disableNameSuffixHash: true labels: config.openshift.io/inject-trusted-cabundle: "true" + app: ramen-dr-cluster patchesStrategicMerge: - manager_openshift_trusted_cabundle.yaml diff --git a/config/dr-cluster/manifests/odr/kustomization.yaml b/config/dr-cluster/manifests/odr/kustomization.yaml index 326db3331..3ae6def34 100644 --- a/config/dr-cluster/manifests/odr/kustomization.yaml +++ b/config/dr-cluster/manifests/odr/kustomization.yaml @@ -10,6 +10,7 @@ configMapGenerator: disableNameSuffixHash: true labels: config.openshift.io/inject-trusted-cabundle: "true" + app: ramen-dr-cluster patchesStrategicMerge: - manager_openshift_trusted_cabundle.yaml diff --git a/config/hub/manifests/idr/kustomization.yaml b/config/hub/manifests/idr/kustomization.yaml index 9c6a00be7..880720477 100644 --- a/config/hub/manifests/idr/kustomization.yaml +++ b/config/hub/manifests/idr/kustomization.yaml @@ -10,6 +10,7 @@ configMapGenerator: disableNameSuffixHash: true labels: config.openshift.io/inject-trusted-cabundle: "true" + app: ramen-hub patchesStrategicMerge: - manager_openshift_trusted_cabundle.yaml diff --git a/config/hub/manifests/odr/kustomization.yaml b/config/hub/manifests/odr/kustomization.yaml index bf6f27ea0..d1e0e1e26 100644 --- a/config/hub/manifests/odr/kustomization.yaml +++ b/config/hub/manifests/odr/kustomization.yaml @@ -10,6 +10,7 @@ configMapGenerator: disableNameSuffixHash: true labels: config.openshift.io/inject-trusted-cabundle: "true" + app: ramen-hub patchesStrategicMerge: - manager_openshift_trusted_cabundle.yaml From ac393e24cc2c232c08ffa8c2f526a6632f556fa5 Mon Sep 17 00:00:00 2001 From: Shyamsundar Ranganathan Date: Mon, 11 Nov 2024 09:22:01 -0500 Subject: [PATCH 3/5] Initial blueprint changes for preserving VRG as Secondary always - Start by not needing to delete VRG as secondary from DRPC reconciler - For VR based VRG reconciliation ensure PVC is released when requested state is Secondary - Some trivial rename of functions to handle as secondary than as secondary for volsync - Adjust test cases to expect a secondary manifest work to be always present There is more work to do in terms of cleanup and refactoring, but the bulk of changes to address the need should be present with this commit. NOTE: Posted for reviews, refactor of the commit into more logical units is possible as work progresses Signed-off-by: Shyamsundar Ranganathan --- internal/controller/drplacementcontrol.go | 214 ++---------------- .../drplacementcontrol_controller_test.go | 70 +++--- .../controller/drplacementcontrolvolsync.go | 58 ++--- .../volumereplicationgroup_controller.go | 2 + internal/controller/vrg_volrep.go | 24 +- 5 files changed, 94 insertions(+), 274 deletions(-) diff --git a/internal/controller/drplacementcontrol.go b/internal/controller/drplacementcontrol.go index a7d4bbe85..df8486ec9 100644 --- a/internal/controller/drplacementcontrol.go +++ b/internal/controller/drplacementcontrol.go @@ -174,7 +174,7 @@ func (d *DRPCInstance) RunInitialDeployment() (bool, error) { } // If we get here, the deployment is successful - err = d.EnsureVolSyncReplicationSetup(homeCluster) + err = d.EnsureSecondaryReplicationSetup(homeCluster) if err != nil { return !done, err } @@ -386,7 +386,7 @@ func (d *DRPCInstance) RunFailover() (bool, error) { } // isValidFailoverTarget determines if the passed in cluster is a valid target to failover to. A valid failover target -// may already be Primary, if it is Secondary then it has to be protecting PVCs with VolSync. +// may already be Primary // NOTE: Currently there is a gap where, right after DR protection when a Secondary VRG is not yet created for VolSync // workloads, a failover if initiated will pass these checks. When we fix to retain VRG for VR as well, a more // deterministic check for VRG as Secondary can be performed. @@ -397,13 +397,6 @@ func (d *DRPCInstance) isValidFailoverTarget(cluster string) bool { vrg, err := d.reconciler.MCVGetter.GetVRGFromManagedCluster(d.instance.Name, d.vrgNamespace, cluster, annotations) if err != nil { - if errors.IsNotFound(err) { - d.log.Info(fmt.Sprintf("VRG not found on %q", cluster)) - - // Valid target as there would be no VRG for VR and Sync cases - return true - } - return false } @@ -413,12 +406,14 @@ func (d *DRPCInstance) isValidFailoverTarget(cluster string) bool { } // Valid target only if VRG is protecting PVCs with VS and its status is also Secondary - if d.drType == DRTypeAsync && vrg.Status.State == rmn.SecondaryState && - !vrg.Spec.VolSync.Disabled && len(vrg.Spec.VolSync.RDSpec) != 0 { - return true + if vrg.Status.State != rmn.SecondaryState || vrg.Status.ObservedGeneration != vrg.Generation { + d.log.Info(fmt.Sprintf("VRG on %s has not transitioned to secondary yet. Spec-State/Status-State %s/%s", + cluster, vrg.Spec.ReplicationState, vrg.Status.State)) + + return false } - return false + return true } func (d *DRPCInstance) checkClusterFenced(cluster string, drClusters []rmn.DRCluster) (bool, error) { @@ -933,7 +928,7 @@ func (d *DRPCInstance) ensureActionCompleted(srcCluster string) (bool, error) { } // Cleanup and setup VolSync if enabled - err = d.ensureCleanupAndVolSyncReplicationSetup(srcCluster) + err = d.ensureCleanupAndSecondaryReplicationSetup(srcCluster) if err != nil { return !done, err } @@ -945,7 +940,7 @@ func (d *DRPCInstance) ensureActionCompleted(srcCluster string) (bool, error) { return done, nil } -func (d *DRPCInstance) ensureCleanupAndVolSyncReplicationSetup(srcCluster string) error { +func (d *DRPCInstance) ensureCleanupAndSecondaryReplicationSetup(srcCluster string) error { // If we have VolSync replication, this is the perfect time to reset the RDSpec // on the primary. This will cause the RD to be cleared on the primary err := d.ResetVolSyncRDOnPrimary(srcCluster) @@ -968,7 +963,7 @@ func (d *DRPCInstance) ensureCleanupAndVolSyncReplicationSetup(srcCluster string // After we ensured peers are clean, The VolSync ReplicationSource (RS) will automatically get // created, but for the ReplicationDestination, we need to explicitly tell the VRG to create it. - err = d.EnsureVolSyncReplicationSetup(srcCluster) + err = d.EnsureSecondaryReplicationSetup(srcCluster) if err != nil { return err } @@ -1449,79 +1444,6 @@ func (d *DRPCInstance) moveVRGToSecondaryEverywhere() bool { return true } -func (d *DRPCInstance) cleanupSecondaries(skipCluster string) (bool, error) { - d.log.Info("Cleaning up secondaries.") - - for _, clusterName := range rmnutil.DRPolicyClusterNames(d.drPolicy) { - if skipCluster == clusterName { - continue - } - - // If VRG hasn't been deleted, then make sure that the MW for it is deleted and - // return and wait, but first make sure that the cluster is accessible - if err := checkAccessToVRGOnCluster(d.reconciler.MCVGetter, d.instance.GetName(), d.instance.GetNamespace(), - d.vrgNamespace, clusterName); err != nil { - return false, err - } - - mwDeleted, err := d.ensureVRGManifestWorkOnClusterDeleted(clusterName) - if err != nil { - return false, err - } - - if !mwDeleted { - return false, nil - } - - d.log.Info("MW has been deleted. Check the VRG") - - if !d.ensureVRGDeleted(clusterName) { - d.log.Info("VRG has not been deleted yet", "cluster", clusterName) - - return false, nil - } - - err = d.reconciler.MCVGetter.DeleteVRGManagedClusterView(d.instance.Name, d.vrgNamespace, clusterName, - rmnutil.MWTypeVRG) - // MW is deleted, VRG is deleted, so we no longer need MCV for the VRG - if err != nil { - d.log.Info("Deletion of VRG MCV failed") - - return false, fmt.Errorf("deletion of VRG MCV failed %w", err) - } - - err = d.reconciler.MCVGetter.DeleteNamespaceManagedClusterView(d.instance.Name, d.vrgNamespace, clusterName, - rmnutil.MWTypeNS) - // MCV for Namespace is no longer needed - if err != nil { - d.log.Info("Deletion of Namespace MCV failed") - - return false, fmt.Errorf("deletion of namespace MCV failed %w", err) - } - } - - return true, nil -} - -func checkAccessToVRGOnCluster(mcvGetter rmnutil.ManagedClusterViewGetter, - name, drpcNamespace, vrgNamespace, clusterName string, -) error { - annotations := make(map[string]string) - - annotations[DRPCNameAnnotation] = name - annotations[DRPCNamespaceAnnotation] = drpcNamespace - - _, err := mcvGetter.GetVRGFromManagedCluster(name, - vrgNamespace, clusterName, annotations) - if err != nil { - if !errors.IsNotFound(err) { - return err - } - } - - return nil -} - func (d *DRPCInstance) updateUserPlacementRule(homeCluster, reason string) error { d.log.Info(fmt.Sprintf("Updating user Placement %s homeCluster %s", d.userPlacement.GetName(), homeCluster)) @@ -1954,6 +1876,7 @@ func (d *DRPCInstance) EnsureCleanup(clusterToSkip string) error { condition := findCondition(d.instance.Status.Conditions, rmn.ConditionPeerReady) + // Because we init conditions we will always find the condition and not move it to ReasonProgressing? if condition == nil { msg := "Starting cleanup check" d.log.Info(msg) @@ -1973,43 +1896,12 @@ func (d *DRPCInstance) EnsureCleanup(clusterToSkip string) error { d.log.Info(fmt.Sprintf("PeerReady Condition is %s, msg: %s", condition.Status, condition.Message)) - // IFF we have VolSync PVCs, then no need to clean up - homeCluster := clusterToSkip - - repReq, err := d.IsVolSyncReplicationRequired(homeCluster) - if err != nil { - return fmt.Errorf("failed to check if VolSync replication is required (%w)", err) - } - - if repReq { - return d.cleanupForVolSync(clusterToSkip) - } - - clean, err := d.cleanupSecondaries(clusterToSkip) - if err != nil { - addOrUpdateCondition(&d.instance.Status.Conditions, rmn.ConditionPeerReady, d.instance.Generation, - metav1.ConditionFalse, rmn.ReasonCleaning, err.Error()) - - return err - } - - if !clean { - msg := "cleaning up secondaries" - addOrUpdateCondition(&d.instance.Status.Conditions, rmn.ConditionPeerReady, d.instance.Generation, - metav1.ConditionFalse, rmn.ReasonCleaning, msg) - - return fmt.Errorf("waiting to clean secondaries") - } - - addOrUpdateCondition(&d.instance.Status.Conditions, rmn.ConditionPeerReady, d.instance.Generation, - metav1.ConditionTrue, rmn.ReasonSuccess, "Cleaned") - - return nil + return d.cleanupSecondaries(clusterToSkip) } //nolint:gocognit -func (d *DRPCInstance) cleanupForVolSync(clusterToSkip string) error { - d.log.Info("VolSync needs both VRGs. Ensure secondary setup on peer") +func (d *DRPCInstance) cleanupSecondaries(clusterToSkip string) error { + d.log.Info("Ensure secondary setup on peer") peersReady := true @@ -2018,6 +1910,7 @@ func (d *DRPCInstance) cleanupForVolSync(clusterToSkip string) error { continue } + // Update PeerReady condition to appropriate reasons in here! justUpdated, err := d.updateVRGState(clusterName, rmn.Secondary) if err != nil { d.log.Info(fmt.Sprintf("Failed to update VRG state for cluster %s. Err (%v)", clusterName, err)) @@ -2025,8 +1918,11 @@ func (d *DRPCInstance) cleanupForVolSync(clusterToSkip string) error { peersReady = false // Recreate the VRG ManifestWork for the secondary. This typically happens during Hub Recovery. + // Ideally this will never be called due to adoption of VRG in place, in the case of upgrades from older + // scheme were VRG was not preserved for VR workloads, this can be hit IFF the upgrade happened when some + // workload was not in peerReady state. if errors.IsNotFound(err) { - err := d.ensureVolSyncSetup(clusterToSkip) + err := d.EnsureSecondaryReplicationSetup(clusterToSkip) if err != nil { return err } @@ -2055,48 +1951,6 @@ func (d *DRPCInstance) cleanupForVolSync(clusterToSkip string) error { return nil } -func (d *DRPCInstance) ensureVRGManifestWorkOnClusterDeleted(clusterName string) (bool, error) { - d.log.Info("Ensuring MW for the VRG is deleted", "cluster", clusterName) - - const done = true - - mw, err := d.mwu.FindManifestWorkByType(rmnutil.MWTypeVRG, clusterName) - if err != nil { - if errors.IsNotFound(err) { - return done, nil - } - - return !done, fmt.Errorf("failed to retrieve ManifestWork (%w)", err) - } - - if rmnutil.ResourceIsDeleted(mw) { - d.log.Info("Waiting for VRG MW to be fully deleted", "cluster", clusterName) - // As long as the Manifestwork still exist, then we are not done - return !done, nil - } - - // If .spec.ReplicateSpec has not already been updated to secondary, then update it. - // If we do update it to secondary, then we have to wait for the MW to be applied - updated, err := d.updateVRGState(clusterName, rmn.Secondary) - if err != nil || updated { - return !done, err - } - - if d.ensureVRGIsSecondaryOnCluster(clusterName) { - // delete VRG manifest work - err = d.mwu.DeleteManifestWork(d.mwu.BuildManifestWorkName(rmnutil.MWTypeVRG), clusterName) - if err != nil { - return !done, fmt.Errorf("%w", err) - } - } - - d.log.Info("Request not complete yet", "cluster", clusterName) - - // IF we get here, either the VRG has not transitioned to secondary (yet) or delete didn't succeed. In either cases, - // we need to make sure that the VRG object is deleted. IOW, we still have to wait - return !done, nil -} - // ensureVRGIsSecondaryEverywhere iterates through all the clusters in the DRCluster set, // and for each cluster, it checks whether the VRG (if exists) is secondary. It will skip // a cluster if provided. It returns true if all clusters report secondary for the VRG, @@ -2227,34 +2081,6 @@ func (d *DRPCInstance) ensureDataProtectedOnCluster(clusterName string) bool { return true } -func (d *DRPCInstance) ensureVRGDeleted(clusterName string) bool { - d.mcvRequestInProgress = false - - annotations := make(map[string]string) - - annotations[DRPCNameAnnotation] = d.instance.Name - annotations[DRPCNamespaceAnnotation] = d.instance.Namespace - - vrg, err := d.reconciler.MCVGetter.GetVRGFromManagedCluster(d.instance.Name, - d.vrgNamespace, clusterName, annotations) - if err != nil { - // Only NotFound error is accepted - if errors.IsNotFound(err) { - return true // ensured - } - - d.log.Info("Failed to get VRG", "error", err) - - d.mcvRequestInProgress = true - // Retry again - return false - } - - d.log.Info(fmt.Sprintf("VRG not deleted(%s)", vrg.Name)) - - return false -} - func (d *DRPCInstance) updateVRGState(clusterName string, state rmn.ReplicationState) (bool, error) { d.log.Info(fmt.Sprintf("Updating VRG ReplicationState to %s for cluster %s", state, clusterName)) diff --git a/internal/controller/drplacementcontrol_controller_test.go b/internal/controller/drplacementcontrol_controller_test.go index 823cb9f37..edd910641 100644 --- a/internal/controller/drplacementcontrol_controller_test.go +++ b/internal/controller/drplacementcontrol_controller_test.go @@ -426,9 +426,9 @@ func resetToggleUIDChecks() { var fakeSecondaryFor string -func setFakeSecondary(clusterName string) { +/*func setFakeSecondary(clusterName string) { fakeSecondaryFor = clusterName -} +}*/ //nolint:cyclop func (f FakeMCVGetter) GetVRGFromManagedCluster(resourceName, resourceNamespace, managedCluster string, @@ -487,7 +487,7 @@ func fakeVRGConditionally(resourceNamespace, managedCluster string, err error) ( return nil, err } - if getFunctionNameAtIndex(3) == "isValidFailoverTarget" && + if getFunctionNameAtIndex(3) == "isValidFailoverTarget" && // TODO: Only this needs handling fakeSecondaryFor == managedCluster { vrg := getDefaultVRG(resourceNamespace) vrg.Spec.ReplicationState = rmn.Secondary @@ -574,7 +574,7 @@ func GetFakeVRGFromMCVUsingMW(managedCluster, resourceNamespace string, Type: controllers.VRGConditionTypeDataReady, Reason: controllers.VRGConditionReasonReplicating, Status: metav1.ConditionTrue, - Message: "Data Read", + Message: "Data Ready", LastTransitionTime: metav1.Now(), ObservedGeneration: vrg.Generation, }) @@ -1096,20 +1096,6 @@ func updateManifestWorkStatus(clusterNamespace, vrgNamespace, mwType, workType s }, timeout, interval).Should(BeTrue(), "failed to wait for PV manifest condition type to change to 'Applied'") } -func waitForVRGMWDeletion(clusterNamespace, vrgNamespace string) { - manifestLookupKey := types.NamespacedName{ - Name: rmnutil.ManifestWorkName(DRPCCommonName, getVRGNamespace(vrgNamespace), "vrg"), - Namespace: clusterNamespace, - } - createdManifest := &ocmworkv1.ManifestWork{} - - Eventually(func() bool { - err := k8sClient.Get(context.TODO(), manifestLookupKey, createdManifest) - - return errors.IsNotFound(err) - }, timeout, interval).Should(BeTrue(), "failed to wait for manifest deletion for type vrg") -} - func ensureDRPolicyIsNotDeleted(drpc *rmn.DRPlacementControl) { Consistently(func() bool { drpolicy := &rmn.DRPolicy{} @@ -1527,7 +1513,7 @@ func runFailoverAction(placementObj client.Object, fromCluster, toCluster string fenceCluster(fromCluster, manualFence) } - recoverToFailoverCluster(placementObj, fromCluster, toCluster, false) + recoverToFailoverCluster(placementObj, fromCluster, toCluster) // TODO: DRCluster as part of Unfence operation, first unfences // the NetworkFence CR and then deletes it. Hence, by the // time this test is made, depending upon whether NetworkFence @@ -1542,7 +1528,7 @@ func runFailoverAction(placementObj client.Object, fromCluster, toCluster string } } - Expect(getManifestWorkCount(fromCluster)).Should(Equal(2)) // DRCluster + NS MW + Expect(getManifestWorkCount(fromCluster)).Should(Equal(3)) // DRCluster + NS MW + VRG MW drpc := getLatestDRPC(placementObj.GetNamespace()) // At this point expect the DRPC status condition to have 2 types @@ -1580,7 +1566,7 @@ func runRelocateAction(placementObj client.Object, fromCluster string, isSyncDR resetdrCluster(toCluster1) } - relocateToPreferredCluster(placementObj, fromCluster, false) + relocateToPreferredCluster(placementObj, fromCluster) // TODO: DRCluster as part of Unfence operation, first unfences // the NetworkFence CR and then deletes it. Hence, by the // time this test is made, depending upon whether NetworkFence @@ -1588,7 +1574,7 @@ func runRelocateAction(placementObj client.Object, fromCluster string, isSyncDR // Expect(getManifestWorkCount(toCluster1)).Should(Equal(2)) // MWs for VRG+ROLES if !isSyncDR { - Expect(getManifestWorkCount(fromCluster)).Should(Equal(2)) // DRClusters + NS MW + Expect(getManifestWorkCount(fromCluster)).Should(Equal(3)) // DRClusters + NS MW + VRG MW } else { // By the time this check is made, the NetworkFence CR in the // cluster from where the application is migrated might not have @@ -1630,7 +1616,7 @@ func clearDRActionAfterRelocate(userPlacementRule *plrv1.PlacementRule, preferre Expect(decision.ClusterName).To(Equal(preferredCluster)) } -func relocateToPreferredCluster(placementObj client.Object, fromCluster string, skipWaitForWMDeletion bool) { +func relocateToPreferredCluster(placementObj client.Object, fromCluster string) { toCluster1 := "east1-cluster" setDRPCSpecExpectationTo(placementObj.GetNamespace(), toCluster1, fromCluster, rmn.ActionRelocate) @@ -1641,14 +1627,10 @@ func relocateToPreferredCluster(placementObj client.Object, fromCluster string, verifyDRPCStatusPreferredClusterExpectation(placementObj.GetNamespace(), rmn.Relocated) verifyVRGManifestWorkCreatedAsPrimary(placementObj.GetNamespace(), toCluster1) - if !skipWaitForWMDeletion { - waitForVRGMWDeletion(West1ManagedCluster, placementObj.GetNamespace()) - } - waitForCompletion(string(rmn.Relocated)) } -func recoverToFailoverCluster(placementObj client.Object, fromCluster, toCluster string, skipWaitForWMDeletion bool) { +func recoverToFailoverCluster(placementObj client.Object, fromCluster, toCluster string) { setDRPCSpecExpectationTo(placementObj.GetNamespace(), fromCluster, toCluster, rmn.ActionFailover) updateManifestWorkStatus(toCluster, placementObj.GetNamespace(), "vrg", ocmworkv1.WorkApplied) @@ -1657,10 +1639,6 @@ func recoverToFailoverCluster(placementObj client.Object, fromCluster, toCluster verifyDRPCStatusPreferredClusterExpectation(placementObj.GetNamespace(), rmn.FailedOver) verifyVRGManifestWorkCreatedAsPrimary(placementObj.GetNamespace(), toCluster) - if !skipWaitForWMDeletion { - waitForVRGMWDeletion(fromCluster, placementObj.GetNamespace()) - } - waitForCompletion(string(rmn.FailedOver)) } @@ -1789,7 +1767,7 @@ func verifyInitialDRPCDeployment(userPlacement client.Object, preferredCluster s func verifyFailoverToSecondary(placementObj client.Object, toCluster string, isSyncDR bool, ) { - recoverToFailoverCluster(placementObj, East1ManagedCluster, toCluster, false) + recoverToFailoverCluster(placementObj, East1ManagedCluster, toCluster) // TODO: DRCluster as part of Unfence operation, first unfences // the NetworkFence CR and then deletes it. Hence, by the @@ -1802,7 +1780,7 @@ func verifyFailoverToSecondary(placementObj client.Object, toCluster string, Expect(getManifestWorkCount(toCluster)).Should(BeElementOf(3, 4)) // MW for VRG+NS+DRCluster+NF } - Expect(getManifestWorkCount(East1ManagedCluster)).Should(Equal(2)) // DRClustern+NS + Expect(getManifestWorkCount(East1ManagedCluster)).Should(Equal(3)) // DRClustern + NS + VRG-MW drpc := getLatestDRPC(placementObj.GetNamespace()) // At this point expect the DRPC status condition to have 2 types @@ -2472,8 +2450,10 @@ var _ = Describe("DRPlacementControl Reconciler", func() { setClusterDown(West1ManagedCluster) clearFakeUserPlacementRuleStatus(UserPlacementRuleName, DefaultDRPCNamespace) clearDRPCStatus() - setDRPCSpecExpectationTo(DefaultDRPCNamespace, East1ManagedCluster, West1ManagedCluster, "") - expectedAction := rmn.DRAction("") + // TODO: Why did we shift the failover to deploy action here? It fails as VRG exists as Secondary now + // on the cluster to deploy to + setDRPCSpecExpectationTo(DefaultDRPCNamespace, East1ManagedCluster, West1ManagedCluster, rmn.ActionFailover) + expectedAction := rmn.ActionFailover expectedPhase := rmn.WaitForUser exptectedPorgression := rmn.ProgressionActionPaused verifyDRPCStateAndProgression(expectedAction, expectedPhase, exptectedPorgression) @@ -2647,6 +2627,8 @@ var _ = Describe("DRPlacementControl Reconciler", func() { }) }) + /* TODO: This was added to prevent failover in case there is a Secondary VRG still in the cluster, needs to adapt + to changes in isValidFailoverTarget function now Context("Test DRPlacementControl Failover stalls if peer has a Secondary (Placement/Subscription)", func() { var placement *clrapiv1beta1.Placement var drpc *rmn.DRPlacementControl @@ -2667,7 +2649,7 @@ var _ = Describe("DRPlacementControl Reconciler", func() { }) }) When("DRAction changes to Failover", func() { - It("Should not start failover if there is a secondary VRG on the failoverCluster", func() { + It("Should not start failover if there is a secondary VRG on the failoverCluster", func() { // TODO setFakeSecondary(West1ManagedCluster) setDRPCSpecExpectationTo(DefaultDRPCNamespace, East1ManagedCluster, West1ManagedCluster, rmn.ActionFailover) verifyUserPlacementRuleDecisionUnchanged(placement.Name, placement.Namespace, East1ManagedCluster) @@ -2688,7 +2670,7 @@ var _ = Describe("DRPlacementControl Reconciler", func() { deleteDRClustersAsync() Expect(getManifestWorkCount(East1ManagedCluster)).Should(Equal(0)) }) - }) + })*/ Context("Test DRPlacementControl With VolSync Setup", func() { var userPlacementRule *plrv1.PlacementRule @@ -2711,14 +2693,14 @@ var _ = Describe("DRPlacementControl Reconciler", func() { }) When("DRAction is changed to Failover", func() { It("Should failover to Secondary (West1ManagedCluster)", func() { - recoverToFailoverCluster(userPlacementRule, East1ManagedCluster, West1ManagedCluster, true) + recoverToFailoverCluster(userPlacementRule, East1ManagedCluster, West1ManagedCluster) Expect(getVRGManifestWorkCount()).Should(Equal(2)) verifyRDSpecAfterActionSwitch(West1ManagedCluster, East1ManagedCluster, 2) }) }) When("DRAction is set to Relocate", func() { It("Should relocate to Primary (East1ManagedCluster)", func() { - relocateToPreferredCluster(userPlacementRule, West1ManagedCluster, true) + relocateToPreferredCluster(userPlacementRule, West1ManagedCluster) Expect(getVRGManifestWorkCount()).Should(Equal(2)) verifyRDSpecAfterActionSwitch(East1ManagedCluster, West1ManagedCluster, 2) }) @@ -2726,7 +2708,7 @@ var _ = Describe("DRPlacementControl Reconciler", func() { When("DRAction is changed back to Failover using only 1 protectedPVC", func() { It("Should failover to secondary (West1ManagedCluster)", func() { ProtectedPVCCount = 1 - recoverToFailoverCluster(userPlacementRule, East1ManagedCluster, West1ManagedCluster, true) + recoverToFailoverCluster(userPlacementRule, East1ManagedCluster, West1ManagedCluster) Expect(getVRGManifestWorkCount()).Should(Equal(2)) verifyRDSpecAfterActionSwitch(West1ManagedCluster, East1ManagedCluster, 1) ProtectedPVCCount = 2 @@ -2735,7 +2717,7 @@ var _ = Describe("DRPlacementControl Reconciler", func() { When("DRAction is set back to Relocate using only 1 protectedPVC", func() { It("Should relocate to Primary (East1ManagedCluster)", func() { ProtectedPVCCount = 1 - relocateToPreferredCluster(userPlacementRule, West1ManagedCluster, true) + relocateToPreferredCluster(userPlacementRule, West1ManagedCluster) Expect(getVRGManifestWorkCount()).Should(Equal(2)) verifyRDSpecAfterActionSwitch(East1ManagedCluster, West1ManagedCluster, 1) ProtectedPVCCount = 2 @@ -2744,7 +2726,7 @@ var _ = Describe("DRPlacementControl Reconciler", func() { When("DRAction is changed back to Failover using only 10 protectedPVC", func() { It("Should failover to secondary (West1ManagedCluster)", func() { ProtectedPVCCount = 10 - recoverToFailoverCluster(userPlacementRule, East1ManagedCluster, West1ManagedCluster, true) + recoverToFailoverCluster(userPlacementRule, East1ManagedCluster, West1ManagedCluster) Expect(getVRGManifestWorkCount()).Should(Equal(2)) verifyRDSpecAfterActionSwitch(West1ManagedCluster, East1ManagedCluster, 10) ProtectedPVCCount = 2 @@ -2753,7 +2735,7 @@ var _ = Describe("DRPlacementControl Reconciler", func() { When("DRAction is set back to Relocate using only 10 protectedPVC", func() { It("Should relocate to Primary (East1ManagedCluster)", func() { ProtectedPVCCount = 10 - relocateToPreferredCluster(userPlacementRule, West1ManagedCluster, true) + relocateToPreferredCluster(userPlacementRule, West1ManagedCluster) Expect(getVRGManifestWorkCount()).Should(Equal(2)) verifyRDSpecAfterActionSwitch(East1ManagedCluster, West1ManagedCluster, 10) ProtectedPVCCount = 2 diff --git a/internal/controller/drplacementcontrolvolsync.go b/internal/controller/drplacementcontrolvolsync.go index 73bc27ba5..efd05ed65 100644 --- a/internal/controller/drplacementcontrolvolsync.go +++ b/internal/controller/drplacementcontrolvolsync.go @@ -13,44 +13,32 @@ import ( ctrlutil "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" ) -func (d *DRPCInstance) EnsureVolSyncReplicationSetup(homeCluster string) error { - d.log.Info(fmt.Sprintf("Ensure VolSync replication has been setup for cluster %s", homeCluster)) +func (d *DRPCInstance) EnsureSecondaryReplicationSetup(srcCluster string) error { + d.setProgression(rmn.ProgressionEnsuringVolSyncSetup) // TODO: Update progression string - if d.volSyncDisabled { - d.log.Info("VolSync is disabled") - - return nil - } - - vsRepNeeded, err := d.IsVolSyncReplicationRequired(homeCluster) + // Create or update the destination VRG + opResult, err := d.createOrUpdateSecondaryManifestWork(srcCluster) if err != nil { return err } - if !vsRepNeeded { - d.log.Info("No PVCs found that require VolSync replication") - - return nil + if opResult == ctrlutil.OperationResultCreated { + return WaitForVolSyncManifestWorkCreation } - return d.ensureVolSyncSetup(homeCluster) -} - -func (d *DRPCInstance) ensureVolSyncSetup(srcCluster string) error { - d.setProgression(rmn.ProgressionEnsuringVolSyncSetup) + if _, found := d.vrgs[srcCluster]; !found { + return fmt.Errorf("failed to find source VRG in cluster %s. VRGs %v", srcCluster, d.vrgs) + } - // Create or update the destination VRG - opResult, err := d.createOrUpdateVolSyncDestManifestWork(srcCluster) + vsRepNeeded, err := d.IsVolSyncReplicationRequired(srcCluster) if err != nil { return err } - if opResult == ctrlutil.OperationResultCreated { - return WaitForVolSyncManifestWorkCreation - } + if !vsRepNeeded { + d.log.Info("No PVCs found that require VolSync replication") - if _, found := d.vrgs[srcCluster]; !found { - return fmt.Errorf("failed to find source VolSync VRG in cluster %s. VRGs %v", srcCluster, d.vrgs) + return nil } // Now we should have a source and destination VRG created @@ -119,9 +107,9 @@ func (d *DRPCInstance) IsVolSyncReplicationRequired(homeCluster string) (bool, e return !required, nil } -// createOrUpdateVolSyncDestManifestWork creates or updates volsync Secondaries skipping the cluster srcCluster. +// createOrUpdateSecondaryManifestWork creates or updates volsync Secondaries skipping the cluster srcCluster. // The srcCluster is primary cluster. -func (d *DRPCInstance) createOrUpdateVolSyncDestManifestWork(srcCluster string) (ctrlutil.OperationResult, error) { +func (d *DRPCInstance) createOrUpdateSecondaryManifestWork(srcCluster string) (ctrlutil.OperationResult, error) { // create VRG ManifestWork d.log.Info("Creating or updating VRG ManifestWork for destination clusters", "Last State:", d.getLastDRState(), "homeCluster", srcCluster) @@ -184,13 +172,17 @@ func (d *DRPCInstance) refreshVRGSecondarySpec(srcCluster, dstCluster string) (* dstVRG := d.newVRG(dstCluster, rmn.Secondary, nil) - if len(srcVRGView.Status.ProtectedPVCs) != 0 { - d.resetRDSpec(srcVRGView, &dstVRG) - } + if d.drType == DRTypeAsync { + if len(srcVRGView.Status.ProtectedPVCs) != 0 { + d.resetRDSpec(srcVRGView, &dstVRG) + } - // Update destination VRG peerClasses with the source classes, such that when secondary is promoted to primary - // on actions, it uses the same peerClasses as the primary - dstVRG.Spec.Async.PeerClasses = srcVRG.Spec.Async.PeerClasses + // Update destination VRG peerClasses with the source classes, such that when secondary is promoted to primary + // on actions, it uses the same peerClasses as the primary + dstVRG.Spec.Async.PeerClasses = srcVRG.Spec.Async.PeerClasses + } else { + dstVRG.Spec.Sync.PeerClasses = srcVRG.Spec.Sync.PeerClasses + } return &dstVRG, nil } diff --git a/internal/controller/volumereplicationgroup_controller.go b/internal/controller/volumereplicationgroup_controller.go index f43a7c2cb..54c533fc1 100644 --- a/internal/controller/volumereplicationgroup_controller.go +++ b/internal/controller/volumereplicationgroup_controller.go @@ -1380,6 +1380,8 @@ func (v *VRGInstance) errorConditionLogAndSet(err error, msg string, } func (v *VRGInstance) updateVRGConditionsAndStatus(result ctrl.Result) ctrl.Result { + // Check if as Secondary things would be updated accordingly, should protectedPVC be cleared? + // cleanupProtectedPVCs v.updateVRGConditions() return v.updateVRGStatus(result) diff --git a/internal/controller/vrg_volrep.go b/internal/controller/vrg_volrep.go index 1c5bb3ce6..ef1110e37 100644 --- a/internal/controller/vrg_volrep.go +++ b/internal/controller/vrg_volrep.go @@ -113,6 +113,8 @@ func (v *VRGInstance) reconcileVolRepsAsPrimary() { } // reconcileVolRepsAsSecondary reconciles VolumeReplication resources for the VRG as secondary +// +//nolint:gocognit,cyclop func (v *VRGInstance) reconcileVolRepsAsSecondary() bool { requeue := false @@ -120,6 +122,13 @@ func (v *VRGInstance) reconcileVolRepsAsSecondary() bool { pvc := &v.volRepPVCs[idx] log := logWithPvcName(v.log, pvc) + // Potentially for PVCs that are not deleted + if !containsString(pvc.Finalizers, PvcVRFinalizerProtected) { + log.Info("pvc does not contain VR protection finalizer. Skipping it") + + continue + } + if err := v.updateProtectedPVCs(pvc); err != nil { requeue = true @@ -137,20 +146,29 @@ func (v *VRGInstance) reconcileVolRepsAsSecondary() bool { continue } + vrMissing, requeueResult := v.reconcileMissingVR(pvc, log) + if vrMissing || requeueResult { + v.requeue() + + continue + } + // If VR is not ready as Secondary, we can ignore it here, either a future VR change or the requeue would // reconcile it to the desired state. - requeueResult, _, skip = v.reconcileVRAsSecondary(pvc, log) + requeueResult, ready, skip := v.reconcileVRAsSecondary(pvc, log) if requeueResult { requeue = true continue } - if skip { + if skip || !ready { continue } - log.Info("Successfully processed VolumeReplication for PersistentVolumeClaim") + // Not removed from protectedPVC list + // cleanupProtectedPVCs + return v.undoPVCFinalizersAndPVRetention(pvc, log) } return requeue From d27528dbbf7896f21603f1cbc5ad19aaed4d9f87 Mon Sep 17 00:00:00 2001 From: Shyamsundar Ranganathan Date: Fri, 15 Nov 2024 12:07:02 -0500 Subject: [PATCH 4/5] Split volsync related Secondary updates into its own function Signed-off-by: Shyamsundar Ranganathan --- internal/controller/drplacementcontrolvolsync.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/internal/controller/drplacementcontrolvolsync.go b/internal/controller/drplacementcontrolvolsync.go index efd05ed65..df6b4eeb8 100644 --- a/internal/controller/drplacementcontrolvolsync.go +++ b/internal/controller/drplacementcontrolvolsync.go @@ -30,6 +30,10 @@ func (d *DRPCInstance) EnsureSecondaryReplicationSetup(srcCluster string) error return fmt.Errorf("failed to find source VRG in cluster %s. VRGs %v", srcCluster, d.vrgs) } + return d.EnsureVolSyncReplicationSetup(srcCluster) +} + +func (d *DRPCInstance) EnsureVolSyncReplicationSetup(srcCluster string) error { vsRepNeeded, err := d.IsVolSyncReplicationRequired(srcCluster) if err != nil { return err From c25d5b47e44f7f45c3b08586add999ecc42f7925 Mon Sep 17 00:00:00 2001 From: Shyamsundar Ranganathan Date: Fri, 15 Nov 2024 12:07:40 -0500 Subject: [PATCH 5/5] Update unused messages for Volrep and remove PVCs from status once secondary Signed-off-by: Shyamsundar Ranganathan --- .../volumereplicationgroup_controller.go | 15 +++++---- internal/controller/vrg_volrep.go | 33 +++++++++++++++---- 2 files changed, 35 insertions(+), 13 deletions(-) diff --git a/internal/controller/volumereplicationgroup_controller.go b/internal/controller/volumereplicationgroup_controller.go index 54c533fc1..fd6c32200 100644 --- a/internal/controller/volumereplicationgroup_controller.go +++ b/internal/controller/volumereplicationgroup_controller.go @@ -1541,15 +1541,13 @@ func (v *VRGInstance) updateVRGConditions() { func (v *VRGInstance) vrgReadyStatus(reason string) *metav1.Condition { v.log.Info("Marking VRG ready with replicating reason", "reason", reason) - unusedMsg := "No PVCs are protected using VolumeReplication scheme" - if v.instance.Spec.Sync != nil { - unusedMsg = "No PVCs are protected, no PVCs found matching the selector" - } - if v.instance.Spec.ReplicationState == ramendrv1alpha1.Secondary { msg := "PVCs in the VolumeReplicationGroup group are replicating" if reason == VRGConditionReasonUnused { - msg = unusedMsg + msg = "PVC protection as secondary is complete, or no PVCs needed protection using VolumeReplication scheme" + if v.instance.Spec.Sync != nil { + msg = "PVC protection as secondary is complete, or no PVCs needed protection" + } } else { reason = VRGConditionReasonReplicating } @@ -1560,7 +1558,10 @@ func (v *VRGInstance) vrgReadyStatus(reason string) *metav1.Condition { // VRG as primary msg := "PVCs in the VolumeReplicationGroup are ready for use" if reason == VRGConditionReasonUnused { - msg = unusedMsg + msg = "No PVCs are protected using VolumeReplication scheme" + if v.instance.Spec.Sync != nil { + msg = "No PVCs are protected, no PVCs found matching the selector" + } } return newVRGAsPrimaryReadyCondition(v.instance.Generation, reason, msg) diff --git a/internal/controller/vrg_volrep.go b/internal/controller/vrg_volrep.go index ef1110e37..c7d3a189d 100644 --- a/internal/controller/vrg_volrep.go +++ b/internal/controller/vrg_volrep.go @@ -114,7 +114,7 @@ func (v *VRGInstance) reconcileVolRepsAsPrimary() { // reconcileVolRepsAsSecondary reconciles VolumeReplication resources for the VRG as secondary // -//nolint:gocognit,cyclop +//nolint:gocognit,cyclop,funlen func (v *VRGInstance) reconcileVolRepsAsSecondary() bool { requeue := false @@ -122,10 +122,12 @@ func (v *VRGInstance) reconcileVolRepsAsSecondary() bool { pvc := &v.volRepPVCs[idx] log := logWithPvcName(v.log, pvc) - // Potentially for PVCs that are not deleted + // Potentially for PVCs that are not deleted, e.g Failover of STS without required auto delete options if !containsString(pvc.Finalizers, PvcVRFinalizerProtected) { log.Info("pvc does not contain VR protection finalizer. Skipping it") + v.pvcStatusDeleteIfPresent(pvc.Namespace, pvc.Name, log) + continue } @@ -148,7 +150,7 @@ func (v *VRGInstance) reconcileVolRepsAsSecondary() bool { vrMissing, requeueResult := v.reconcileMissingVR(pvc, log) if vrMissing || requeueResult { - v.requeue() + requeue = true continue } @@ -166,9 +168,13 @@ func (v *VRGInstance) reconcileVolRepsAsSecondary() bool { continue } - // Not removed from protectedPVC list - // cleanupProtectedPVCs - return v.undoPVCFinalizersAndPVRetention(pvc, log) + if v.undoPVCFinalizersAndPVRetention(pvc, log) { + requeue = true + + continue + } + + v.pvcStatusDeleteIfPresent(pvc.Namespace, pvc.Name, log) } return requeue @@ -2567,6 +2573,16 @@ func (v *VRGInstance) aggregateVolRepDataReadyCondition() *metav1.Condition { //nolint:funlen,gocognit,cyclop func (v *VRGInstance) aggregateVolRepDataProtectedCondition() *metav1.Condition { if len(v.volRepPVCs) == 0 { + if v.instance.Spec.ReplicationState == ramendrv1alpha1.Secondary { + if v.instance.Spec.Sync != nil { + return newVRGAsDataProtectedUnusedCondition(v.instance.Generation, + "PVC protection as secondary is complete, or no PVCs needed protection") + } + + return newVRGAsDataProtectedUnusedCondition(v.instance.Generation, + "PVC protection as secondary is complete, or no PVCs needed protection using VolumeReplication scheme") + } + if v.instance.Spec.Sync != nil { return newVRGAsDataProtectedUnusedCondition(v.instance.Generation, "No PVCs are protected, no PVCs found matching the selector") @@ -2649,6 +2665,11 @@ func (v *VRGInstance) aggregateVolRepDataProtectedCondition() *metav1.Condition // protecting condition, set the VRG level condition to protecting. If not, set // the VRG level condition to true. func (v *VRGInstance) aggregateVolRepClusterDataProtectedCondition() *metav1.Condition { + if v.instance.Spec.ReplicationState == ramendrv1alpha1.Secondary { + return newVRGClusterDataProtectedUnusedCondition(v.instance.Generation, + "Cluster data is not protected as Secondary") + } + if len(v.volRepPVCs) == 0 { if v.instance.Spec.Sync != nil { return newVRGAsDataProtectedUnusedCondition(v.instance.Generation,