Skip to content

Commit

Permalink
Merge pull request #1043 from openshift-cherrypick-robot/cherry-pick-…
Browse files Browse the repository at this point in the history
…950-to-release-4.14

Bug 2196177: [release-4.14] Add proper error message when MDR policy creation failure
  • Loading branch information
openshift-merge-robot authored Sep 11, 2023
2 parents 430b428 + 263925c commit 9ee039b
Show file tree
Hide file tree
Showing 12 changed files with 206 additions and 84 deletions.
10 changes: 8 additions & 2 deletions locales/en/plugin__odf-console.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"Policy name": "Policy name",
"Connect clusters": "Connect clusters",
"Enables mirroring/replication between two selected clusters, ensuring failover or relocation between the two clusters in the event of an outage or planned maintenance.": "Enables mirroring/replication between two selected clusters, ensuring failover or relocation between the two clusters in the event of an outage or planned maintenance.",
"Note: If your cluster isn't visible on this list, verify its import status and refer to the steps outlined in the ACM documentation.": "Note: If your cluster isn't visible on this list, verify its import status and refer to the steps outlined in the ACM documentation.",
"Data Foundation {{ version }} or above must be installed on the managed clusters to setup connection for enabling replication/mirroring.": "Data Foundation {{ version }} or above must be installed on the managed clusters to setup connection for enabling replication/mirroring.",
"Selected clusters": "Selected clusters",
"An error occurred": "An error occurred",
Expand All @@ -37,10 +38,15 @@
"Select cluster list": "Select cluster list",
"Checkbox to select cluster": "Checkbox to select cluster",
"Select schedule time format in minutes, hours or days": "Select schedule time format in minutes, hours or days",
"1 or more managed clusters are offline": "1 or more managed clusters are offline",
"The status for both the managed clusters must be available for creating a DR policy. To restore a cluster to an available state, refer to the instructions in the ACM documentation.": "The status for both the managed clusters must be available for creating a DR policy. To restore a cluster to an available state, refer to the instructions in the ACM documentation.",
"Cannot proceed with one or more selected clusters": "Cannot proceed with one or more selected clusters",
"We could not retrieve any information about the managed cluster {{names}}. Check the documentation for potential causes and follow the steps mentioned and try again.": "We could not retrieve any information about the managed cluster {{names}}. Check the documentation for potential causes and follow the steps mentioned and try again.",
"{{ names }} has either an unsupported ODF version or the ODF operator is missing, install or update to ODF {{ version }} or the latest version to enable DR protection.": "{{ names }} has either an unsupported ODF version or the ODF operator is missing, install or update to ODF {{ version }} or the latest version to enable DR protection.",
"{{ names }} is not connected to RHCS": "{{ names }} is not connected to RHCS",
"Replication policy": "Replication policy",
"Sync schedule": "Sync schedule",
"{{ name }} has either an unsupported ODF version or the ODF operator is missing, install or update to ODF {{ version }} or latest version to enable DR protection.": "{{ name }} has either an unsupported ODF version or the ODF operator is missing, install or update to ODF {{ version }} or latest version to enable DR protection.",
"{{ name }} is not connected to RHCS": "{{ name }} is not connected to RHCS",
"Information unavailable": "Information unavailable",
"Validated": "Validated",
"Not Validated": "Not Validated",
"Application": "Application",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,11 @@ export const CreateDRPolicy: React.FC<ReRouteResourceProps> = ({
dispatch={dispatch}
/>
</FormGroup>
<FormGroup
helperText={t(
"Note: If your cluster isn't visible on this list, verify its import status and refer to the steps outlined in the ACM documentation."
)}
/>
{!!odfMCOVersion && (
<FormGroup fieldId="policy-name">
<Alert
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export type ODFInfo = Partial<{
cephFSID: string;
odfVersion: string;
isValidODFVersion: boolean;
isManagedClusterAvailable: boolean;
}>;

export type Cluster = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import * as React from 'react';
import { getMajorVersion, isMinimumSupportedODFVersion } from '@odf/mco/utils';
import {
getMajorVersion,
getManagedClusterCondition,
isMinimumSupportedODFVersion,
} from '@odf/mco/utils';
import { StatusBox } from '@odf/shared/generic/status-box';
import { useCustomTranslation } from '@odf/shared/useCustomTranslationHook';
import { referenceForModel } from '@odf/shared/utils';
Expand Down Expand Up @@ -27,6 +31,8 @@ import {
MANAGED_CLUSTER_REGION_CLAIM,
HUB_CLUSTER_NAME,
ClusterClaimTypes,
MANAGED_CLUSTER_JOINED,
MANAGED_CLUSTER_CONDITION_AVAILABLE,
} from '../../../constants';
import { ACMManagedClusterModel } from '../../../models';
import { ACMManagedClusterKind } from '../../../types';
Expand Down Expand Up @@ -81,6 +87,10 @@ const fetchODFInfo = (
storageSystemName: storageSystemNameClaim?.value || '',
storageClusterName: storageClusterNameClaim?.value || '',
cephFSID: cephFsidClaim?.value || '',
isManagedClusterAvailable: !!getManagedClusterCondition(
cluster,
MANAGED_CLUSTER_CONDITION_AVAILABLE
),
isValidODFVersion: isMinimumSupportedODFVersion(
getMajorVersion(odfVersionClaim?.value),
requiredODFVersion
Expand Down Expand Up @@ -140,15 +150,15 @@ export const SelectClusterList: React.FC<SelectClusterListProps> = ({
!!requiredODFVersion &&
!acmManagedClustersLoadError
) {
setClusters(
acmManagedClusters?.reduce(
(obj, acmManagedCluster) => [
...obj,
getManagedClusterInfo(acmManagedCluster, requiredODFVersion),
],
[]
)
const managedClusterInfoList = acmManagedClusters?.reduce(
(acc, cluster) =>
!!getManagedClusterCondition(cluster, MANAGED_CLUSTER_JOINED)
? [...acc, getManagedClusterInfo(cluster, requiredODFVersion)]
: acc,
[]
);

setClusters(managedClusterInfoList);
}
}, [
acmManagedClusters,
Expand All @@ -163,29 +173,13 @@ export const SelectClusterList: React.FC<SelectClusterListProps> = ({
);

const onSelect: DataListCheckProps['onChange'] = (checked, event) => {
const {
name,
region: clusterRegion,
odfVersion,
storageClusterName,
storageSystemName,
cephFSID,
isValidODFVersion,
} = filteredClusters?.[Number(event.currentTarget.id)];
const selectedClusterInfo =
filteredClusters?.[Number(event.currentTarget.id)];
const selectedClusterList = checked
? [
...selectedClusters,
{
name,
region: clusterRegion,
cephFSID,
storageSystemName,
storageClusterName,
odfVersion,
isValidODFVersion,
},
]
: selectedClusters.filter((cluster) => cluster?.name !== name);
? [...selectedClusters, selectedClusterInfo]
: selectedClusters.filter(
(cluster) => cluster?.name !== selectedClusterInfo.name
);
dispatch({
type: DRPolicyActionType.SET_SELECTED_CLUSTERS,
payload: selectedClusterList,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,12 @@ import {
TIME_UNITS,
SYNC_SCHEDULE_DISPLAY_TEXT,
} from '../../../constants';
import { DRPolicyState, DRPolicyAction, DRPolicyActionType } from './reducer';
import {
DRPolicyState,
DRPolicyAction,
DRPolicyActionType,
Cluster,
} from './reducer';
import '../../../style.scss';

type SyncScheduleProps = {
Expand Down Expand Up @@ -118,13 +123,95 @@ type DRReplicationTypeProps = {
dispatch: React.Dispatch<DRPolicyAction>;
};

type ErrorMessageType = {
message: string;
description?: string;
};

type ClusterErrorType = {
unAvailableClusters: string[];
clustersWithUnSupportedODF: string[];
clustersWithoutODF: string[];
clustersWithUnSuccessfulODF: string[];
};

const getClusterErrorInfo = (selectedClusters: Cluster[]): ClusterErrorType =>
selectedClusters.reduce(
(acc, cluster) => {
if (!cluster.isManagedClusterAvailable) {
acc.unAvailableClusters.push(cluster.name);
}
if (!cluster.storageSystemName) {
acc.clustersWithUnSupportedODF.push(cluster.name);
}
if (!cluster.isValidODFVersion) {
acc.clustersWithoutODF.push(cluster.name);
}
if (cluster.cephFSID === '') {
acc.clustersWithUnSuccessfulODF.push(cluster.name);
}
return acc;
},
{
unAvailableClusters: [],
clustersWithUnSupportedODF: [],
clustersWithoutODF: [],
clustersWithUnSuccessfulODF: [],
}
);

const getErrorMessage = (
selectedClusters: Cluster[],
requiredODFVersion: string,
t
): ErrorMessageType => {
const clusterErrorInfo = getClusterErrorInfo(selectedClusters);
if (!!clusterErrorInfo.unAvailableClusters.length) {
return {
message: t('1 or more managed clusters are offline'),
description: t(
'The status for both the managed clusters must be available for creating a DR policy. To restore a cluster to an available state, refer to the instructions in the ACM documentation.'
),
};
} else if (!!clusterErrorInfo.clustersWithUnSupportedODF.length) {
return {
message: t('Cannot proceed with one or more selected clusters'),
description: t(
'We could not retrieve any information about the managed cluster {{names}}. Check the documentation for potential causes and follow the steps mentioned and try again.',
{ names: clusterErrorInfo.clustersWithUnSupportedODF.join(' & ') }
),
};
} else if (!!clusterErrorInfo.clustersWithoutODF.length) {
return {
message: t(
'{{ names }} has either an unsupported ODF version or the ODF operator is missing, install or update to ODF {{ version }} or the latest version to enable DR protection.',
{
names: clusterErrorInfo.clustersWithoutODF.join(' & '),
version: requiredODFVersion,
}
),
};
} else if (!!clusterErrorInfo.clustersWithUnSuccessfulODF.length) {
return {
message: t('{{ names }} is not connected to RHCS', {
names: clusterErrorInfo.clustersWithUnSuccessfulODF.join(' & '),
}),
};
}
return null;
};

export const DRReplicationType: React.FC<DRReplicationTypeProps> = ({
state,
requiredODFVersion,
dispatch,
}) => {
const { t } = useCustomTranslation();
const [isReplicationOpen, setReplicationOpen] = React.useState(false);
const errorMessage = React.useMemo(
() => getErrorMessage(state.selectedClusters, requiredODFVersion, t),
[state.selectedClusters, requiredODFVersion, t]
);

const replicationDropdownItems = React.useMemo(
() =>
Expand All @@ -148,19 +235,19 @@ export const DRReplicationType: React.FC<DRReplicationTypeProps> = ({
[state.isReplicationInputManual, dispatch, t]
);

const errorMessage = (message: string) => (
<Alert
data-test="odf-not-found-alert"
className="odf-alert mco-create-data-policy__alert"
title={message}
variant={AlertVariant.danger}
isInline
/>
);

return (
<>
{state.isODFDetected ? (
{!!errorMessage ? (
<Alert
data-test="odf-not-found-alert"
className="odf-alert mco-create-data-policy__alert"
title={errorMessage.message}
variant={AlertVariant.danger}
isInline
>
{errorMessage?.description}
</Alert>
) : (
<>
{state.replication && (
<FormGroup
Expand Down Expand Up @@ -194,23 +281,6 @@ export const DRReplicationType: React.FC<DRReplicationTypeProps> = ({
</FormGroup>
)}
</>
) : (
!state.errorMessage &&
state.selectedClusters?.map((c) =>
!c.isValidODFVersion
? errorMessage(
t(
'{{ name }} has either an unsupported ODF version or the ODF operator is missing, install or update to ODF {{ version }} or latest version to enable DR protection.',
{ name: c?.name, version: requiredODFVersion }
)
)
: c.cephFSID === '' &&
errorMessage(
t('{{ name }} is not connected to RHCS', {
name: c?.name,
})
)
)
)}
</>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import * as React from 'react';
import { useCustomTranslation } from '@odf/shared/useCustomTranslationHook';
import { RedExclamationCircleIcon } from '@openshift-console/dynamic-plugin-sdk';
import {
Text,
Badge,
Expand All @@ -21,7 +23,20 @@ export const SelectedCluster: React.FC<SelectedClusterProps> = ({
cluster,
dispatch, // eslint-disable-line @typescript-eslint/no-unused-vars
}) => {
const { name, region, storageSystemName } = cluster;
const {
name,
region,
storageSystemName,
isManagedClusterAvailable,
isValidODFVersion,
cephFSID,
} = cluster;
const { t } = useCustomTranslation();
const anyError =
!isManagedClusterAvailable ||
!isValidODFVersion ||
!storageSystemName ||
!cephFSID;
return (
<Flex
display={{ default: 'inlineFlex' }}
Expand All @@ -34,9 +49,20 @@ export const SelectedCluster: React.FC<SelectedClusterProps> = ({
</FlexItem>
<FlexItem>
<TextContent>
<Text component={TextVariants.p}>{name}</Text>
<Text component={TextVariants.small}>{region}</Text>
<Text component={TextVariants.small}>{storageSystemName}</Text>
<Text component={TextVariants.p}>
<span> {name} </span> &nbsp;
{!!anyError && <RedExclamationCircleIcon />}
</Text>
{!!storageSystemName ? (
<>
<Text component={TextVariants.small}>{region}</Text>
<Text component={TextVariants.small}>{storageSystemName}</Text>
</>
) : (
<Text component={TextVariants.small}>
{t('Information unavailable')}
</Text>
)}
</TextContent>
</FlexItem>
</Flex>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
VOLUME_REPLICATION_HEALTH,
OBJECT_NAMESPACE,
OBJECT_NAME,
MANAGED_CLUSTER_CONDITION_AVAILABLE,
} from '@odf/mco/constants';
import {
DrClusterAppsMap,
Expand All @@ -24,7 +25,7 @@ import {
} from '@odf/mco/types';
import {
getVolumeReplicationHealth,
getManagedClusterAvailableCondition,
getManagedClusterCondition,
} from '@odf/mco/utils';
import { getMax, getMin } from '@odf/shared/charts';
import HealthItem from '@odf/shared/dashboards/status-card/HealthItem';
Expand Down Expand Up @@ -129,8 +130,9 @@ export const HealthSection: React.FC<HealthSectionProps> = ({
<HealthItem
title={t('Cluster health')}
state={
!!getManagedClusterAvailableCondition(
clusterResources[clusterName]?.managedCluster
!!getManagedClusterCondition(
clusterResources[clusterName]?.managedCluster,
MANAGED_CLUSTER_CONDITION_AVAILABLE
)
? HealthState.OK
: HealthState.ERROR
Expand Down
Loading

0 comments on commit 9ee039b

Please sign in to comment.