Skip to content

Commit

Permalink
Changes to support multiple ODF cluster from the same OCP cluster
Browse files Browse the repository at this point in the history
Signed-off-by: Gowtham Shanmugasundaram <[email protected]>
  • Loading branch information
GowthamShanmugam committed Nov 23, 2023
1 parent 5117053 commit 8d1a203
Show file tree
Hide file tree
Showing 4 changed files with 366 additions and 17 deletions.
12 changes: 7 additions & 5 deletions packages/mco/components/mco-dashboard/queries.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ODF_OPERATOR } from '@odf/shared/constants';
import {
TOTAL_CAPACITY_FILE_BLOCK_METRIC,
USED_CAPACITY_FILE_BLOCK_METRIC,
Expand Down Expand Up @@ -28,8 +29,9 @@ export const getLastSyncPerClusterQuery = () =>

// ToDo (epic 4422): Need to update as per updates in the metrics
export const CAPACITY_QUERIES = {
[StorageDashboard.TOTAL_CAPACITY_FILE_BLOCK]: `(label_replace(odf_system_map{target_namespace="openshift-storage"} , "managedBy", "$1", "target_name", "(.*)")) * on (namespace, managedBy, cluster) group_right(storage_system, target_kind) ${TOTAL_CAPACITY_FILE_BLOCK_METRIC}`,
[StorageDashboard.USED_CAPACITY_FILE_BLOCK]: `(label_replace(odf_system_map{target_namespace="openshift-storage"} , "managedBy", "$1", "target_name", "(.*)")) * on (namespace, managedBy, cluster) group_right(storage_system, target_kind) ${USED_CAPACITY_FILE_BLOCK_METRIC}`,
// ToDo: For 4.15, Assuming managedBy is unique for each StorageSystem. Need to add targer_namesapce as an another key.
[StorageDashboard.TOTAL_CAPACITY_FILE_BLOCK]: `(label_replace(odf_system_map, "managedBy", "$1", "target_name", "(.*)")) * on (namespace, managedBy, cluster) group_right(storage_system, target_kind) ${TOTAL_CAPACITY_FILE_BLOCK_METRIC}`,
[StorageDashboard.USED_CAPACITY_FILE_BLOCK]: `(label_replace(odf_system_map, "managedBy", "$1", "target_name", "(.*)")) * on (namespace, managedBy, cluster) group_right(storage_system, target_kind) ${USED_CAPACITY_FILE_BLOCK_METRIC}`,
};

export const getRBDSnapshotUtilizationQuery = (
Expand All @@ -46,9 +48,9 @@ export const getRBDSnapshotUtilizationQuery = (

// ToDo (epic 4422): Need to update as per updates in the metrics
export const STATUS_QUERIES = {
[StorageDashboard.SYSTEM_HEALTH]: `(label_replace(odf_system_map{target_namespace="openshift-storage"} , "managedBy", "$1", "target_name", "(.*)")) * on (namespace, managedBy, cluster) group_right(storage_system, target_kind) ${SYSTEM_HEALTH_METRIC}`,
// ToDo: For 4.15, Assuming managedBy is unique for each StorageSystem. Need to add targer_namesapce as an another key.
[StorageDashboard.SYSTEM_HEALTH]: `(label_replace(odf_system_map, "managedBy", "$1", "target_name", "(.*)")) * on (namespace, managedBy, cluster) group_right(storage_system, target_kind) ${SYSTEM_HEALTH_METRIC}`,
[StorageDashboard.HEALTH]: SYSTEM_HEALTH_METRIC,
[StorageDashboard.CSV_STATUS]:
'csv_succeeded{exported_namespace="openshift-storage"}',
[StorageDashboard.CSV_STATUS]: `csv_succeeded{name=~"${ODF_OPERATOR}.*"}`,
[StorageDashboard.CSV_STATUS_ALL_WHITELISTED]: 'csv_succeeded',
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,333 @@
import * as React from 'react';
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { STATUS_QUERIES, StorageDashboard } from '../../queries';
import { StatusCard } from './status-card';

let testCaseId = 1;

const healthStatus = {
status: 'success',
data: {
resultType: 'vector',
result: [
{
metric: {
__name__: `${STATUS_QUERIES[StorageDashboard.HEALTH]}`,
cluster: 'cluster-1',
clusterID: '23b41e13-5668-4fe9-83ab-ce109efb0634',
container: 'core',
endpoint: 'mgmt',
instance: '10.131.0.32:8080',
job: 'noobaa-mgmt',
namespace: 'namespace-1',
pod: 'noobaa-core-0',
receive: 'true',
service: 'noobaa-mgmt',
system_type: 'OCS',
system_vendor: 'Red Hat',
tenant_id: '0a4c8828-9b16-42fc-9195-056d96cbe66f',
},
value: [1700478807.019, '0'],
},
{
metric: {
__name__: `${STATUS_QUERIES[StorageDashboard.HEALTH]}`,
cluster: 'cluster-1',
clusterID: '23b41e13-5668-4fe9-83ab-ce109efb0634',
container: 'mgr',
endpoint: 'http-metrics',
instance: '10.131.0.27:9283',
job: 'rook-ceph-mgr',
managedBy: 'ocs-storagecluster',
namespace: 'namespace-1',
pod: 'rook-ceph-mgr-a-d4d78778d-2zxmh',
receive: 'true',
service: 'rook-ceph-mgr',
system_type: 'OCS',
system_vendor: 'Red Hat',
tenant_id: '0a4c8828-9b16-42fc-9195-056d96cbe66f',
},
value: [1700478807.019, '0'],
},
{
metric: {
__name__: `${STATUS_QUERIES[StorageDashboard.HEALTH]}`,
cluster: 'cluster-2',
clusterID: 'b3e8ac99-3ebf-4c39-b3af-7902b14669fe',
container: 'core',
endpoint: 'mgmt',
instance: '10.133.2.39:8080',
job: 'noobaa-mgmt',
namespace: 'namespace-2',
pod: 'noobaa-core-0',
receive: 'true',
service: 'noobaa-mgmt',
system_type: 'OCS',
system_vendor: 'Red Hat',
tenant_id: '0a4c8828-9b16-42fc-9195-056d96cbe66f',
},
value: [1700478807.019, '0'],
},
{
metric: {
__name__: `${STATUS_QUERIES[StorageDashboard.HEALTH]}`,
cluster: 'cluster-2',
clusterID: 'b3e8ac99-3ebf-4c39-b3af-7902b14669fe',
container: 'mgr',
endpoint: 'http-metrics',
instance: '10.132.2.22:9283',
job: 'rook-ceph-mgr',
managedBy: 'ocs-storagecluster',
namespace: 'namespace-2',
pod: 'rook-ceph-mgr-a-7488547d8d-9dx8f',
receive: 'true',
service: 'rook-ceph-mgr',
system_type: 'OCS',
system_vendor: 'Red Hat',
tenant_id: '0a4c8828-9b16-42fc-9195-056d96cbe66f',
},
value: [1700478807.019, '0'],
},
],
},
};

const storageSystemStatus = {
status: 'success',
data: {
resultType: 'vector',
result: [
{
metric: {
cluster: 'cluster-1',
clusterID: '23b41e13-5668-4fe9-83ab-ce109efb0634',
container: 'mgr',
endpoint: 'http-metrics',
instance: '10.131.0.27:9283',
job: 'rook-ceph-mgr',
managedBy: 'ocs-storagecluster',
namespace: 'namespace-1',
pod: 'rook-ceph-mgr-a-d4d78778d-2zxmh',
receive: 'true',
service: 'rook-ceph-mgr',
system_type: 'OCS',
system_vendor: 'Red Hat',
tenant_id: '0a4c8828-9b16-42fc-9195-056d96cbe66f',
storage_system: 'storagesystem-1',
target_kind: 'storagecluster.ocs.openshift.io/v1',
},
value: [1700478807.019, '0'],
},
{
metric: {
cluster: 'cluster-2',
clusterID: 'b3e8ac99-3ebf-4c39-b3af-7902b14669fe',
container: 'mgr',
endpoint: 'http-metrics',
instance: '10.132.2.22:9283',
job: 'rook-ceph-mgr',
managedBy: 'ocs-storagecluster',
namespace: 'namespace-2',
pod: 'rook-ceph-mgr-a-7488547d8d-9dx8f',
receive: 'true',
service: 'rook-ceph-mgr',
system_type: 'OCS',
system_vendor: 'Red Hat',
tenant_id: '0a4c8828-9b16-42fc-9195-056d96cbe66f',
storage_system: 'storagesystem-2',
target_kind: 'storagecluster.ocs.openshift.io/v1',
},
value: [1700478807.019, '0'],
},
],
},
};

const csvStatus = {
status: 'success',
data: {
resultType: 'vector',
result: [
{
metric: {
__name__: 'csv_succeeded',
cluster: 'cluster-1',
clusterID: '23b41e13-5668-4fe9-83ab-ce109efb0634',
container: 'olm-operator',
endpoint: 'https-metrics',
exported_namespace: 'namespace-1',
instance: '10.130.0.33:8443',
job: 'olm-operator-metrics',
name: 'odf-operator.v4.14.0-rhodf',
namespace: 'openshift-operator-lifecycle-manager',
pod: 'olm-operator-56d5ff6b6b-lhkdv',
receive: 'true',
service: 'olm-operator-metrics',
tenant_id: '0a4c8828-9b16-42fc-9195-056d96cbe66f',
version: '4.14.0-rhodf',
},
value: [1700482361.796, '1'],
},
{
metric: {
__name__: 'csv_succeeded',
cluster: 'cluster-2',
clusterID: 'b3e8ac99-3ebf-4c39-b3af-7902b14669fe',
container: 'olm-operator',
endpoint: 'https-metrics',
exported_namespace: 'namespace-2',
instance: '10.134.0.31:8443',
job: 'olm-operator-metrics',
name: 'odf-operator.v4.14.0-rhodf',
namespace: 'openshift-operator-lifecycle-manager',
pod: 'olm-operator-56d5ff6b6b-vmw7c',
receive: 'true',
service: 'olm-operator-metrics',
tenant_id: '0a4c8828-9b16-42fc-9195-056d96cbe66f',
version: '4.14.0-rhodf',
},
value: [1700482361.796, '1'],
},
],
},
};

const MockHealthBody: React.FC = ({ children }) => (
<div className="co-status-card__health-body">{children}</div>
);

jest.mock(
'@odf/shared/hooks/custom-prometheus-poll/custom-prometheus-poll-hook',
() => ({
useCustomPrometheusPoll: jest.fn((props: { query: string }) => {
if (props.query === STATUS_QUERIES[StorageDashboard.SYSTEM_HEALTH]) {
return [storageSystemStatus, undefined, false];
} else if (props.query === STATUS_QUERIES[StorageDashboard.HEALTH]) {
if (testCaseId === 2) {
healthStatus.data.result[0].value[1] = '1';
}
return [healthStatus, undefined, false];
} else if (props.query === STATUS_QUERIES[StorageDashboard.CSV_STATUS]) {
if (testCaseId === 2) {
csvStatus.data.result[0].value[1] = '0';
}
return [csvStatus, undefined, false];
}
}),
})
);

jest.mock('@openshift-console/dynamic-plugin-sdk-internal', () => ({
// HealthBody import is causing error
HealthBody: (props) => <MockHealthBody {...props} />,
}));

describe('Test ODF cluster status from different clusters and namesapces', () => {
test('All healthy case testing', async () => {
testCaseId = 1;
render(<StatusCard />);
// Title
expect(screen.getByText('Status')).toBeInTheDocument();
expect(screen.getAllByText('Healthy').length === 2).toBeTruthy();

// Operator health
expect(screen.getByText('Data Foundation')).toBeInTheDocument();
await waitFor(() => {
fireEvent.click(screen.getByText('Data Foundation'));
// Popover
expect(screen.getByText('Data Foundation status')).toBeInTheDocument();
expect(
screen.getByText(
'The Data Foundation operator is the primary operator of Data Foundation'
)
).toBeInTheDocument();
expect(screen.getByText('Operator status')).toBeInTheDocument();
expect(screen.getByText('Running')).toBeInTheDocument();
expect(screen.getByText('Degraded')).toBeInTheDocument();
// Running operator count
expect(screen.getByText('2')).toBeInTheDocument();
// Degraded operator count
expect(screen.getByText('0')).toBeInTheDocument();

// Close popover
fireEvent.click(screen.getByLabelText('Close'));
});

expect(screen.getByText('Systems')).toBeInTheDocument();
fireEvent.click(screen.getByText('Systems'));
// Storage system health
await waitFor(() => {
// Popover
expect(screen.getByText('Storage System status')).toBeInTheDocument();
expect(
screen.getByText(
'StorageSystem is responsible for ensuring different types of file and block storage availability, storage capacity management and generic operations on storage.'
)
).toBeInTheDocument();
expect(screen.getByText('Storage System (2)')).toBeInTheDocument();
// Operator status
expect(screen.getAllByText('Warning').length === 2).toBeTruthy();
expect(screen.getByText('Critical')).toBeInTheDocument();
expect(screen.getByText('Error')).toBeInTheDocument();
expect(screen.getByText('Critical')).toBeInTheDocument();
expect(screen.getAllByText('Healthy').length === 3).toBeTruthy();
expect(screen.getByText('Normal')).toBeInTheDocument();
expect(screen.getAllByText(`(0)`).length === 2).toBeTruthy();
expect(screen.getByText(`(2)`)).toBeInTheDocument();
});
});

test('Partially healthy case testing', async () => {
testCaseId = 2;
render(<StatusCard />);
// Title
expect(screen.getByText('Status')).toBeInTheDocument();
expect(screen.getByText('Error')).toBeInTheDocument();
expect(screen.getByText('Warning')).toBeInTheDocument();
expect(screen.getAllByText('Degraded').length === 2).toBeTruthy();

// Operator health
expect(screen.getByText('Data Foundation')).toBeInTheDocument();
await waitFor(() => {
fireEvent.click(screen.getByText('Data Foundation'));
// Popover
expect(screen.getByText('Data Foundation status')).toBeInTheDocument();
expect(
screen.getByText(
'The Data Foundation operator is the primary operator of Data Foundation'
)
).toBeInTheDocument();
expect(screen.getByText('Operator status')).toBeInTheDocument();
expect(screen.getByText('Running')).toBeInTheDocument();
expect(screen.getAllByText('Degraded').length === 3).toBeTruthy();
// Running and degraded operator count
expect(screen.getAllByText('1').length === 2).toBeTruthy();

// Close popover
fireEvent.click(screen.getByLabelText('Close'));
});

expect(screen.getByText('Systems')).toBeInTheDocument();
fireEvent.click(screen.getByText('Systems'));
// Storage system health
await waitFor(() => {
// Popover
expect(screen.getByText('Storage System status')).toBeInTheDocument();
expect(
screen.getByText(
'StorageSystem is responsible for ensuring different types of file and block storage availability, storage capacity management and generic operations on storage.'
)
).toBeInTheDocument();
expect(screen.getByText('Storage System (2)')).toBeInTheDocument();
// Operator status
expect(screen.getAllByText('Warning').length === 3).toBeTruthy();
expect(screen.getByText('Critical')).toBeInTheDocument();
expect(screen.getAllByText('Error').length === 2).toBeTruthy();
expect(screen.getByText('Critical')).toBeInTheDocument();
expect(screen.getByText('Healthy')).toBeInTheDocument();
expect(screen.getByText('Normal')).toBeInTheDocument();
expect(screen.getAllByText(`(1)`).length === 2).toBeTruthy();
expect(screen.getByText(`(0)`)).toBeInTheDocument();
});
});
});
Loading

0 comments on commit 8d1a203

Please sign in to comment.