Skip to content

Commit

Permalink
Merge pull request #1444 from GowthamShanmugam/RHSTOR-5962
Browse files Browse the repository at this point in the history
RHSTOR-5962: Disable disaster recovery for discovered applications
  • Loading branch information
openshift-merge-bot[bot] authored Jun 19, 2024
2 parents 666714b + 70efa91 commit f87daa4
Show file tree
Hide file tree
Showing 4 changed files with 191 additions and 1 deletion.
5 changes: 4 additions & 1 deletion locales/en/plugin__odf-console.json
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,9 @@
"Follow the below steps to enroll your managed applications to disaster recovery:": "Follow the below steps to enroll your managed applications to disaster recovery:",
"<0><0><0></0></0> Navigate to <4>Applications</4> section and locate your application.</0><1><0><0></0></0> Select <4>Manage disaster recovery</4> from inline actions.</1><2><0><0></0></0> In the Manage disaster recovery modal, click on <4>Enroll application</4> to start the wizard process.</2>": "<0><0><0></0></0> Navigate to <4>Applications</4> section and locate your application.</0><1><0><0></0></0> Select <4>Manage disaster recovery</4> from inline actions.</1><2><0><0></0></0> In the Manage disaster recovery modal, click on <4>Enroll application</4> to start the wizard process.</2>",
"Continue to Applications page": "Continue to Applications page",
"Remove disaster recovery?": "Remove disaster recovery?",
"Your application <2>{{resourceName}}</2> will lose disaster recovery protection, reventing volume synchronization (replication) between clusters.": "Your application <2>{{resourceName}}</2> will lose disaster recovery protection, reventing volume synchronization (replication) between clusters.",
"Remove": "Remove",
"Application types and their enrollment processes": "Application types and their enrollment processes",
"<0>ACM discovered applications:</0><1>Based on modular and microservices architecture, uses operators for dynamically created kubernetes objects. Eg: <2>CloudPak, Custom-created applications</2></1><2><0>Enrollment process:</0> Discovered applications are enrolled under disaster recovery through enabling protection for their namespaces and further defining the scope of this protection within namespace through recipe selection or resource label.</2><3>ACM managed applications:</3><4>Based on subscribing to one or more Kubernetes resource repositories (channel resource) that contains resources that are deployed on managed clusters. Eg: <2>ApplicationSet, Subscriptions</2></4><5><0>Enrollment process:</0> Individually protect managed application with flexibility for distinct configurations for different sub-categories of managed application based on specific requirements.</5>": "<0>ACM discovered applications:</0><1>Based on modular and microservices architecture, uses operators for dynamically created kubernetes objects. Eg: <2>CloudPak, Custom-created applications</2></1><2><0>Enrollment process:</0> Discovered applications are enrolled under disaster recovery through enabling protection for their namespaces and further defining the scope of this protection within namespace through recipe selection or resource label.</2><3>ACM managed applications:</3><4>Based on subscribing to one or more Kubernetes resource repositories (channel resource) that contains resources that are deployed on managed clusters. Eg: <2>ApplicationSet, Subscriptions</2></4><5><0>Enrollment process:</0> Individually protect managed application with flexibility for distinct configurations for different sub-categories of managed application based on specific requirements.</5>",
"No protected discovered applications found": "No protected discovered applications found",
Expand All @@ -395,6 +398,7 @@
"Move workloads to target cluster": "Move workloads to target cluster",
"Relocate": "Relocate",
"Failback workloads to primary cluster": "Failback workloads to primary cluster",
"Remove disaster recovery": "Remove disaster recovery",
"Choose a type:": "Choose a type:",
"ACM discovered applications": "ACM discovered applications",
"ACM managed applications": "ACM managed applications",
Expand Down Expand Up @@ -1392,7 +1396,6 @@
"Oh no! Something went wrong.": "Oh no! Something went wrong.",
"Copied to clipboard": "Copied to clipboard",
"Drag to reorder": "Drag to reorder",
"Remove": "Remove",
"Key": "Key",
"Value": "Value",
"Add more": "Add more",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ export const getDRPCKindObj = (
},
});

// ToDo(Gowtham): https://github.com/red-hat-storage/odf-console/issues/1449
export const doNotDeletePVCAnnotationPromises = (
drpcs: DRPlacementControlType[]
) => {
Expand Down Expand Up @@ -92,6 +93,7 @@ export const doNotDeletePVCAnnotationPromises = (
return promises;
};

// ToDo(Gowtham): https://github.com/red-hat-storage/odf-console/issues/1449
export const unAssignPromises = (drpcs: DRPlacementControlType[]) => {
const promises: Promise<K8sResourceKind>[] = [];
drpcs.forEach((drpc) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
import * as React from 'react';
import { DO_NOT_DELETE_PVC_ANNOTATION_WO_SLASH } from '@odf/mco/constants';
import { ACMPlacementModel, DRPlacementControlModel } from '@odf/mco/models';
import {
ModalBody,
ModalFooter,
ModalHeader,
CommonModalProps,
} from '@odf/shared/modals';
import { getName, getNamespace } from '@odf/shared/selectors';
import { useCustomTranslation } from '@odf/shared/useCustomTranslationHook';
import { getErrorMessage } from '@odf/shared/utils';
import {
K8sResourceKind,
k8sDelete,
k8sPatch,
} from '@openshift-console/dynamic-plugin-sdk';
import { DRPlacementControlKind } from 'packages/mco/types';
import { Trans } from 'react-i18next';
import {
Alert,
AlertVariant,
Button,
ButtonVariant,
Modal,
ModalVariant,
} from '@patternfly/react-core';
import { ExclamationTriangleIcon } from '@patternfly/react-icons';

// ToDo(Gowtham): https://github.com/red-hat-storage/odf-console/issues/1449
const pvcAnnotationPatchPromise = (application: DRPlacementControlKind) => {
const patch = [
{
op: 'add',
path: `/metadata/annotations/${DO_NOT_DELETE_PVC_ANNOTATION_WO_SLASH}`,
value: 'true',
},
];

return k8sPatch({
model: DRPlacementControlModel,
resource: {
metadata: {
name: getName(application),
namespace: getNamespace(application),
},
},
data: patch,
});
};

// ToDo(Gowtham): https://github.com/red-hat-storage/odf-console/issues/1449
const deleteApplicationResourcePromise = (
application: DRPlacementControlKind
) => {
// Delete DRPC and dummy placement after updating the annotation
const promises: Promise<K8sResourceKind>[] = [];
const { name, namespace } = application?.spec?.placementRef;

promises.push(
k8sDelete({
resource: application,
model: DRPlacementControlModel,
json: null,
requestInit: null,
})
);

promises.push(
k8sDelete({
resource: {
metadata: {
name: name,
namespace: namespace,
},
},
model: ACMPlacementModel,
json: null,
requestInit: null,
})
);

return promises;
};

const RemoveDisasterRecoveryModal: React.FC<
CommonModalProps<RemoveDisasterRecoveryProps>
> = ({ closeModal, isOpen, extraProps: { application } }) => {
const { t } = useCustomTranslation();

const [isInprogress, setInProgress] = React.useState(false);
const [error, setError] = React.useState();

const onRemove = (event) => {
event.preventDefault();
setInProgress(true);

pvcAnnotationPatchPromise(application)
.then(() => {
Promise.all(deleteApplicationResourcePromise(application))
.then(() => {
closeModal();
})
.catch((err) => {
setError(err);
setInProgress(false);
});
})
.catch((err) => {
setError(err);
setInProgress(false);
});
};

return (
<Modal
variant={ModalVariant.small}
header={
<ModalHeader>
<ExclamationTriangleIcon
color="var(--pf-v5-global--warning-color--100)"
className="icon--spacer"
/>
{t('Remove disaster recovery?')}
</ModalHeader>
}
isOpen={isOpen}
onClose={closeModal}
showClose={false}
hasNoBodyWrapper={true}
>
<ModalBody>
<Trans t={t}>
Your application{' '}
<strong>{{ resourceName: getName(application) }}</strong> will lose
disaster recovery protection, reventing volume synchronization
(replication) between clusters.
</Trans>
{!!error && (
<Alert
isInline
variant={AlertVariant.danger}
title={t('An error occurred')}
>
{getErrorMessage(error) || error}
</Alert>
)}
</ModalBody>
<ModalFooter>
<Button
key="cancel"
variant={ButtonVariant.secondary}
onClick={closeModal}
data-test="cancel-action"
>
{t('Cancel')}
</Button>
<Button
key="remove"
variant={ButtonVariant.danger}
onClick={onRemove}
data-test="remove-action"
isLoading={isInprogress}
>
{t('Remove')}
</Button>
</ModalFooter>
</Modal>
);
};

type RemoveDisasterRecoveryProps = {
application: DRPlacementControlKind;
};

export default RemoveDisasterRecoveryModal;
9 changes: 9 additions & 0 deletions packages/mco/components/protected-applications/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import {
isPeerReady,
} from '../../utils';
import { DiscoveredApplicationParser as DiscoveredApplicationModal } from '../modals/app-failover-relocate/parser/discovered-application-parser';
import RemoveDisasterRecoveryModal from '../modals/remove-disaster-recovery/remove-disaster-recovery';

export const drpcDetailsPageRoute = (drpc: DRPlacementControlKind) =>
`/k8s/ns/${getNamespace(drpc)}/${referenceForModel(
Expand Down Expand Up @@ -245,6 +246,14 @@ export const getRowActions = (
extraProps: { application: rowItem, action: DRActionType.RELOCATE },
}),
},
{
title: t('Remove disaster recovery'),
onClick: () =>
launcher(RemoveDisasterRecoveryModal, {
isOpen: true,
extraProps: { application: rowItem },
}),
},
];

export const enum EnrollApplicationTypes {
Expand Down

0 comments on commit f87daa4

Please sign in to comment.