Skip to content

Commit

Permalink
Merge pull request #1097 from TimothyAsirJeyasing/brownfiled-migratio…
Browse files Browse the repository at this point in the history
…n-status-alert

Provide osd migration status alert for dr brownfield
  • Loading branch information
openshift-merge-bot[bot] authored Nov 30, 2023
2 parents 5646fc8 + 50e0947 commit 9b55fef
Show file tree
Hide file tree
Showing 17 changed files with 332 additions and 56 deletions.
8 changes: 7 additions & 1 deletion locales/en/plugin__odf-console.json
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,6 @@
"Review and assign": "Review and assign",
"In use: {{targetClusters}}": "In use: {{targetClusters}}",
"Used: {{targetClusters}}": "Used: {{targetClusters}}",
"View documentation": "View documentation",
"StorageSystems": "StorageSystems",
"StorageSystem details": "StorageSystem details",
"Edit BlockPool": "Edit BlockPool",
Expand Down Expand Up @@ -455,6 +454,12 @@
"This card shows the requested capacity for different Kubernetes resources. The figures shown represent the usable storage, meaning that data replication is not taken into consideration.": "This card shows the requested capacity for different Kubernetes resources. The figures shown represent the usable storage, meaning that data replication is not taken into consideration.",
"Internal": "Internal",
"Raw capacity is the absolute total disk space available to the array subsystem.": "Raw capacity is the absolute total disk space available to the array subsystem.",
"Cluster ready for Regional-DR setup.": "Cluster ready for Regional-DR setup.",
"Setting up disaster recovery": "Setting up disaster recovery",
"Cluster OSDs are being migrated": "Cluster OSDs are being migrated",
"{{ percentageComplete }}% completed ({{ migratedDevices }}/{{ totalOsd }} remaining)": "{{ percentageComplete }}% completed ({{ migratedDevices }}/{{ totalOsd }} remaining)",
"Could not migrate cluster OSDs.": "Could not migrate cluster OSDs.",
"Check documentation": "Check documentation",
"Troubleshoot": "Troubleshoot",
"Active health checks": "Active health checks",
"Progressing": "Progressing",
Expand Down Expand Up @@ -1145,6 +1150,7 @@
"No conditions found": "No conditions found",
"Copied": "Copied",
"Copy to clipboard": "Copy to clipboard",
"View documentation": "View documentation",
"Oh no! Something went wrong.": "Oh no! Something went wrong.",
"Copied to clipboard": "Copied to clipboard",
"Drag to reorder": "Drag to reorder",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import * as React from 'react';
import { DOC_LINKS } from '@odf/mco/constants/doc';
import { ViewDocumentation } from '@odf/shared/utils';
import { TFunction } from 'i18next';
import { Trans } from 'react-i18next';
import { AlertVariant } from '@patternfly/react-core';
import { ViewDocumentation, DOC_LINKS } from '../../../utils';

export enum ErrorMessageType {
// Priority wise error messages
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import * as React from 'react';
import { ViewDocumentation } from '@odf/shared/utils';
import { TFunction } from 'i18next';
import { Trans } from 'react-i18next';
import { AlertVariant } from '@patternfly/react-core';
import { ViewDocumentation, DOC_LINKS } from '../../../../utils/doc-utils';
import { DOC_LINKS } from '../../../../constants/doc';

export enum ErrorMessageType {
// Priority wise error messages
Expand Down
13 changes: 13 additions & 0 deletions packages/mco/constants/doc.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { ODF_DOC_BASE_PATH, ODF_DOC_VERSION } from '@odf/shared/constants/doc';

export const ACM_DOC_VERSION = '2.9';
export const ACM_DOC_HOME = `https://access.redhat.com/documentation/en-us/red_hat_advanced_cluster_management_for_kubernetes/${ACM_DOC_VERSION}`;
export const ACM_DOC_BASE_PATH = `${ACM_DOC_HOME}/html-single`;

export const DOC_LINKS = {
APPLY_POLICY: `${ODF_DOC_BASE_PATH}/configuring_openshift_data_foundation_disaster_recovery_for_openshift_workloads/index#apply-drpolicy-to-sample-application_manage-dr`,
MDR_FAILOVER: `${ODF_DOC_BASE_PATH}/configuring_openshift_data_foundation_disaster_recovery_for_openshift_workloads/index#application-failover-between-managed-clusters_manage-dr`,
MDR_RELOCATE: `${ODF_DOC_BASE_PATH}/configuring_openshift_data_foundation_disaster_recovery_for_openshift_workloads/index#relocating-application-between-managed-clusters_manage-dr`,
DR_RELEASE_NOTES: `${ODF_DOC_BASE_PATH}/${ODF_DOC_VERSION}_release_notes/index#disaster_recovery`,
ACM_OFFLINE_CLUSTER: `${ACM_DOC_BASE_PATH}/troubleshooting/index#troubleshooting-an-offline-cluster`,
};
48 changes: 0 additions & 48 deletions packages/mco/utils/doc-utils.tsx

This file was deleted.

1 change: 0 additions & 1 deletion packages/mco/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
export * from './disaster-recovery';
export * from './common';
export * from './doc-utils';
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import React from 'react';
import { BLUESTORE, BLUESTORE_RDR } from '@odf/core/constants';
import { cleanup, render, screen, waitFor } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import { MemoryRouter } from 'react-router-dom';
import { getOSDMigrationStatus } from '../../../../utils/osd-migration';
import { OSDMigrationProgress } from './osd-migration-progress';

jest.mock('@odf/shared/status/icons', () => ({
RedExclamationCircleIcon: 'div',
}));

jest.mock('@openshift-console/dynamic-plugin-sdk-internal', () => ({
HealthBody: 'div',
HealthItem: ({ title }) => <div>{title}</div>,
ViewDocumentation: ({ text, doclink }) => <a href={doclink}>{text}</a>,
HealthState: {
NOT_AVAILABLE: 'NOT_AVAILABLE',
OK: 'OK',
},
}));

jest.mock('../../../../utils/osd-migration');
afterEach(cleanup);

describe('OSDMigrationStatus', () => {
test('renders the component with COMPLETED status', async () => {
const cephData = {
status: {
storage: {
osd: {
storeType: {
[BLUESTORE_RDR]: 5,
},
},
},
},
};

getOSDMigrationStatus.mockReturnValue('Completed');

render(
<MemoryRouter>
<OSDMigrationProgress cephData={cephData} />
</MemoryRouter>
);

await waitFor(() => {
expect(
screen.getByText('Cluster ready for Regional-DR setup.')
).toBeInTheDocument();
});
});

test('renders the component with PENDING status', async () => {
const cephData = {
status: {
storage: {
osd: {
storeType: {
[BLUESTORE]: 10,
[BLUESTORE_RDR]: 5,
},
},
},
},
};

getOSDMigrationStatus.mockReturnValue('In Progress');

render(
<MemoryRouter>
<OSDMigrationProgress cephData={cephData} />
</MemoryRouter>
);

await waitFor(() => {
expect(
screen.getByText('Cluster OSDs are being migrated')
).toBeInTheDocument();
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import * as React from 'react';
import {
OSDMigrationStatus,
BLUESTORE,
BLUESTORE_RDR,
} from '@odf/core/constants';
import { ODF_DR_DOC_HOME } from '@odf/shared/constants/doc';
import { RedExclamationCircleIcon } from '@odf/shared/status/icons';
import { CephClusterKind } from '@odf/shared/types';
import { useCustomTranslation } from '@odf/shared/useCustomTranslationHook';
import { ViewDocumentation } from '@odf/shared/utils';
import { HealthState } from '@openshift-console/dynamic-plugin-sdk';
import {
HealthBody,
HealthItem,
} from '@openshift-console/dynamic-plugin-sdk-internal';
import { Divider, Flex, FlexItem } from '@patternfly/react-core';
import { InProgressIcon } from '@patternfly/react-icons';
import {
getCephStoreType,
getOSDMigrationStatus,
} from '../../../../utils/osd-migration';

const calculateOSDMigration = (
cephData: CephClusterKind
): [number, number, number] => {
const migratedDevices = getCephStoreType(cephData)?.[BLUESTORE_RDR] || 0;
const totalOsd =
(getCephStoreType(cephData)?.[BLUESTORE] || 0) + migratedDevices;
const percentageComplete =
totalOsd !== 0 ? Math.round((migratedDevices / totalOsd) * 100) : 0;

return [migratedDevices, totalOsd, percentageComplete];
};

export const OSDMigrationProgress: React.FC<OSDMigrationProgressProps> = ({
cephData,
}) => {
const { t } = useCustomTranslation();
const [migratedDevices, totalOsd, percentageComplete] =
calculateOSDMigration(cephData);
const migrationStatus: string = getOSDMigrationStatus(cephData);

return (
<>
{migrationStatus !== OSDMigrationStatus.PENDING && <Divider />}
<HealthBody>
<Flex alignItems={{ default: 'alignItemsCenter' }}>
{migrationStatus === OSDMigrationStatus.COMPLETED && (
<>
<FlexItem>
<HealthItem
title={t('Cluster ready for Regional-DR setup.')}
state={HealthState.OK}
/>
</FlexItem>
<FlexItem>
<ViewDocumentation
text={t('Setting up disaster recovery')}
doclink={ODF_DR_DOC_HOME}
/>
</FlexItem>
</>
)}

{migrationStatus === OSDMigrationStatus.IN_PROGRESS && (
<>
<FlexItem className="pf-u-mt-xl">
<HealthItem
icon={<InProgressIcon className="co-dashboard-icon" />}
state={HealthState.OK}
title={t('Cluster OSDs are being migrated')}
/>
</FlexItem>
<FlexItem className="pf-u-mt-xl">
{t(
'{{ percentageComplete }}% completed ({{ migratedDevices }}/{{ totalOsd }} remaining)',
{
percentageComplete,
migratedDevices,
totalOsd,
}
)}
</FlexItem>
</>
)}

{migrationStatus === OSDMigrationStatus.FAILED && (
<>
<FlexItem>
<HealthItem
state={HealthState.OK}
icon={
<RedExclamationCircleIcon className="co-dashboard-icon" />
}
title={t('Could not migrate cluster OSDs.')}
/>
</FlexItem>
<FlexItem>
<ViewDocumentation
text={t('Check documentation')}
doclink={ODF_DR_DOC_HOME}
/>
</FlexItem>
<FlexItem align={{ default: 'alignRight' }}>
{t(
'{{ percentageComplete }}% completed ({{ migratedDevices }}/{{ totalOsd }} remaining)',
{
percentageComplete,
migratedDevices,
totalOsd,
}
)}
</FlexItem>
</>
)}
</Flex>
</HealthBody>
</>
);
};

type OSDMigrationProgressProps = {
cephData: CephClusterKind;
};
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import {
} from '@patternfly/react-core';
import { CephClusterModel } from '../../../models';
import { DATA_RESILIENCY_QUERY, StorageDashboardQuery } from '../../../queries';
import { OSDMigrationProgress } from './osd-migration/osd-migration-progress';
import { getCephHealthState, getDataResiliencyState } from './utils';
import { whitelistedHealthChecksRef } from './whitelisted-health-checks';
import './healthchecks.scss';
Expand Down Expand Up @@ -183,6 +184,7 @@ export const StatusCard: React.FC = () => {
</GalleryItem>
</Gallery>
</HealthBody>
<OSDMigrationProgress cephData={data?.[0]} />
<CephAlerts />
</Card>
);
Expand Down
39 changes: 39 additions & 0 deletions packages/ocs/utils/osd-migration.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import {
BLUESTORE,
BLUESTORE_RDR,
OSDMigrationStatus,
} from '@odf/core/constants';
import { CephClusterKind } from '@odf/shared/types';

export function getCephStoreType(ceph: CephClusterKind) {
return ceph?.status?.storage?.osd?.storeType;
}

export const getBluestoreCount = (ceph: CephClusterKind): number => {
return getCephStoreType(ceph)?.[BLUESTORE] || 0;
};

export const getBluestoreRdrCount = (ceph: CephClusterKind): number => {
return getCephStoreType(ceph)?.[BLUESTORE_RDR] || 0;
};

export const getOSDMigrationStatus = (ceph: CephClusterKind) => {
if (!!ceph) {
const bluestoreCount = getBluestoreCount(ceph);
const bluestoreRdrCount = getBluestoreRdrCount(ceph);

if (bluestoreCount > 0) {
if (bluestoreRdrCount > 0) {
return OSDMigrationStatus.IN_PROGRESS;
} else {
return OSDMigrationStatus.PENDING;
}
} else if (bluestoreRdrCount > 0) {
return OSDMigrationStatus.COMPLETED;
}
} else {
return OSDMigrationStatus.FAILED;
} // TODO Add condition for migration failure

return '';
};
12 changes: 12 additions & 0 deletions packages/odf/constants/data-protection.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export const DISASTER_RECOVERY_TARGET_ANNOTATION =
'ocs.openshift.io/clusterIsDisasterRecoveryTarget';

export enum OSDMigrationStatus {
IN_PROGRESS = 'In Progress',
PENDING = 'Pending',
COMPLETED = 'Completed',
FAILED = 'Failed',
}

export const BLUESTORE_RDR = 'bluestore-rdr';
export const BLUESTORE = 'bluestore';
2 changes: 0 additions & 2 deletions packages/odf/constants/dataProtection.ts

This file was deleted.

Loading

0 comments on commit 9b55fef

Please sign in to comment.