diff --git a/.eslintrc.js b/.eslintrc.js index 4110238e9..a68be04bf 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -66,6 +66,7 @@ module.exports = { 'react/jsx-curly-newline': 'off', 'react/jsx-indent': 'off', 'react/jsx-no-useless-fragment': ['error', { allowExpressions: true }], + 'react/jsx-pascal-case': 'error', 'react/no-unused-prop-types': 'off', 'consistent-return': 'off', 'default-case': 'off', @@ -102,6 +103,44 @@ module.exports = { 'jsx-a11y/no-static-element-interactions': 'off', 'max-classes-per-file': 'off', 'max-len': 'off', + '@typescript-eslint/naming-convention': [ + 'error', + { + selector: 'enumMember', + format: ['PascalCase', 'UPPER_CASE'], + }, + { + selector: 'import', + format: ['camelCase', 'PascalCase'], + leadingUnderscore: 'allow', + }, + { + selector: 'objectLiteralMethod', + format: ['camelCase', 'PascalCase'], + }, + { + selector: 'parameter', + format: ['camelCase', 'PascalCase'], + leadingUnderscore: 'allow', + }, + { + selector: 'property', + format: null, + }, + { + selector: 'variable', + // React Components, regular variables, constants. + format: ['PascalCase', 'camelCase', 'UPPER_CASE'], + }, + { + selector: 'typeLike', + format: ['PascalCase'], + }, + { + selector: 'default', + format: ['camelCase'], + }, + ], 'no-empty-function': 'off', '@typescript-eslint/no-empty-function': 'error', 'no-empty-pattern': 'off', diff --git a/cypress/constants/storage-pool-const.ts b/cypress/constants/storage-pool-const.ts index c453774d7..00673123f 100644 --- a/cypress/constants/storage-pool-const.ts +++ b/cypress/constants/storage-pool-const.ts @@ -1,10 +1,10 @@ -export enum POOL_STATE { +export enum PoolState { READY = 'Ready', RECONCILE_FAILED = 'ReconcileFailed', FAILURE = 'Failure', } -export enum POOL_PROGRESS { +export enum PoolProgress { CREATED = 'created', FAILED = 'failed', PROGRESS = 'progress', @@ -15,13 +15,15 @@ export enum POOL_PROGRESS { BOUNDED = 'bounded', } -export enum POOL_TYPE { +export enum PoolType { BLOCK = 'Block', FILESYSTEM = 'Filesystem', } export const COMPRESSION_ON = 'aggressive'; export const ROOK_MODEL = 'cephblockpools.ceph.rook.io'; +export const CEPH_BUILTIN_MGR_POOL = 'builtin-mgr'; +export const CEPH_BUILTIN_NFS_POOL = 'ocs-storagecluster-cephnfs-builtin-pool'; export const CEPH_DEFAULT_BLOCK_POOL_NAME = 'ocs-storagecluster-cephblockpool'; export const CEPH_DEFAULT_FS_POOL_PREFIX = 'ocs-storagecluster-cephfilesystem'; export const CEPH_DEFAULT_FS_POOL_NAME = `${CEPH_DEFAULT_FS_POOL_PREFIX}-data0`; diff --git a/cypress/consts.ts b/cypress/consts.ts index 617af4096..9548a0536 100644 --- a/cypress/consts.ts +++ b/cypress/consts.ts @@ -19,7 +19,7 @@ const STORAGECLUSTER_PHASE = `"$(oc get storageclusters -n openshift-storage -o= )}')"`; export const OCS_SC_STATE = `until [ ${STORAGECLUSTER_PHASE} = "Ready" ]; do sleep 1; done;`; -export enum CLUSTER_STATUS { +export enum ClusterStatus { READY = 'Ready', PROGRESSING = 'Progressing', HEALTH_ERROR = 'HEALTH_ERR', diff --git a/cypress/support.ts b/cypress/support.ts index 2d45a6bc9..9f1f85e0b 100644 --- a/cypress/support.ts +++ b/cypress/support.ts @@ -60,6 +60,10 @@ Cypress.Commands.add('install', () => { cy.contains('Create StorageSystem', { timeout: 15 * SECOND }).should( 'be.visible' ); + + // Uncomment next line only if the cluster has enough resources. + // cy.get('label[for="enable-nfs"]').click(); + cy.get('button').contains('Next').click(); // @TODO: Do we still want to uncheck the already unchecked 'Taint nodes' checkbox? // If yes, we should scroll down (needed after adding the performance profile selection) diff --git a/cypress/tests/add-capacity.spec.ts b/cypress/tests/add-capacity.spec.ts index fdea50fa7..6f1ec6900 100644 --- a/cypress/tests/add-capacity.spec.ts +++ b/cypress/tests/add-capacity.spec.ts @@ -1,6 +1,6 @@ import * as _ from 'lodash-es'; import { - CLUSTER_STATUS, + ClusterStatus, STORAGE_SYSTEM_NAME, STORAGE_CLUSTER_NAME, CLUSTER_NAMESPACE, @@ -51,7 +51,7 @@ describe('OCS Operator Expansion of Storage Class Test', () => { cy.log('Check if ceph cluster is healthy before expansion'); expect(cephCluster.status.ceph.health).not.to.equal( - CLUSTER_STATUS.HEALTH_ERROR + ClusterStatus.HEALTH_ERROR ); }); cy.exec( @@ -128,7 +128,7 @@ describe('OCS Operator Expansion of Storage Class Test', () => { cy.log('Check if ceph cluster is healthy after expansion'); expect(cephCluster.status.ceph.health).to.not.equal( - CLUSTER_STATUS.HEALTH_ERROR + ClusterStatus.HEALTH_ERROR ); }); cy.exec(`oc get po -n ${CLUSTER_NAMESPACE} -o json`).then((res) => { diff --git a/cypress/tests/storage-pool-in-storageclass-form.spec.ts b/cypress/tests/storage-pool-in-storageclass-form.spec.ts index 6abe7e204..6a2a8e1f8 100644 --- a/cypress/tests/storage-pool-in-storageclass-form.spec.ts +++ b/cypress/tests/storage-pool-in-storageclass-form.spec.ts @@ -1,6 +1,8 @@ import { + CEPH_BUILTIN_MGR_POOL, + CEPH_BUILTIN_NFS_POOL, CEPH_DEFAULT_FS_POOL_PREFIX, - POOL_TYPE, + PoolType, } from '../constants/storage-pool-const'; import { deleteBlockPoolFromCLI, @@ -9,45 +11,49 @@ import { createStoragePoolInSCForm, fillPoolModalForm, checkStoragePoolIsSelectableInSCForm, + showAvailablePoolsInSCForm, } from '../views/storage-pool'; describe('Test storage pool creation when creating a new StorageClass', () => { - it(`Creates a new ${POOL_TYPE.BLOCK} pool`, () => { - const poolName = 'sc-block-name'; - + beforeEach(() => { cy.clickNavLink(['Storage', 'StorageClasses']); cy.byTestID('item-create').click(); + }); + + it(`does not show hidden pools`, () => { + showAvailablePoolsInSCForm(PoolType.BLOCK); + cy.byTestID(CEPH_BUILTIN_MGR_POOL).should('not.exist'); + cy.byTestID(CEPH_BUILTIN_NFS_POOL).should('not.exist'); + }); + + it(`Creates a new ${PoolType.BLOCK} pool`, () => { + const poolName = 'sc-block-name'; - cy.log(`Create a new ${POOL_TYPE.BLOCK} pool`); - createStoragePoolInSCForm(POOL_TYPE.BLOCK, poolName); + cy.log(`Create a new ${PoolType.BLOCK} pool`); + createStoragePoolInSCForm(PoolType.BLOCK, poolName); checkStoragePoolIsSelectableInSCForm(poolName); verifyBlockPoolJSON(poolName); - cy.log( - `Try to create a new ${POOL_TYPE.BLOCK} pool using an existing name` - ); - fillPoolModalForm(POOL_TYPE.BLOCK, poolName); + cy.log(`Try to create a new ${PoolType.BLOCK} pool using an existing name`); + fillPoolModalForm(PoolType.BLOCK, poolName); cy.byLegacyTestID('confirm-action').should('be.disabled'); cy.byLegacyTestID('modal-cancel-action').click(); deleteBlockPoolFromCLI(poolName); }); - it(`Creates a new ${POOL_TYPE.FILESYSTEM} pool`, () => { + it(`Creates a new ${PoolType.FILESYSTEM} pool`, () => { const poolName = 'sc-fs-name'; const poolFullName = `${CEPH_DEFAULT_FS_POOL_PREFIX}-${poolName}`; - cy.clickNavLink(['Storage', 'StorageClasses']); - cy.byTestID('item-create').click(); - - cy.log(`Create a new ${POOL_TYPE.FILESYSTEM} pool`); - createStoragePoolInSCForm(POOL_TYPE.FILESYSTEM, poolName); + cy.log(`Create a new ${PoolType.FILESYSTEM} pool`); + createStoragePoolInSCForm(PoolType.FILESYSTEM, poolName); checkStoragePoolIsSelectableInSCForm(poolFullName); cy.log( - `Try to create a new ${POOL_TYPE.FILESYSTEM} pool using an existing name` + `Try to create a new ${PoolType.FILESYSTEM} pool using an existing name` ); - fillPoolModalForm(POOL_TYPE.FILESYSTEM, poolName); + fillPoolModalForm(PoolType.FILESYSTEM, poolName); cy.byLegacyTestID('confirm-action').should('be.disabled'); cy.byLegacyTestID('modal-cancel-action').click(); diff --git a/cypress/tests/storage-pool.spec.ts b/cypress/tests/storage-pool.spec.ts index 8d1527bfa..6224be7a9 100644 --- a/cypress/tests/storage-pool.spec.ts +++ b/cypress/tests/storage-pool.spec.ts @@ -1,7 +1,7 @@ import { - POOL_PROGRESS, + PoolProgress, CEPH_DEFAULT_BLOCK_POOL_NAME, - POOL_TYPE, + PoolType, CEPH_DEFAULT_FS_POOL_NAME, CEPH_DEFAULT_FS_POOL_PREFIX, } from '../constants/storage-pool-const'; @@ -30,9 +30,9 @@ describe('Block pool on ODF UI', () => { }); it('Check for a new pool creation', () => { - createStoragePool(POOL_TYPE.BLOCK, poolName); + createStoragePool(PoolType.BLOCK, poolName); app.waitForLoad(); - cy.log(`Verify ${POOL_TYPE.BLOCK} pool creation`); + cy.log(`Verify ${PoolType.BLOCK} pool creation`); cy.byTestID('status-text').should('contain', 'Ready', { timeout: 2 * 60000, }); @@ -61,7 +61,7 @@ describe('Block pool on ODF UI', () => { it('Test updating/deleting a default block pool is not allowed', () => { cy.log('Kebab action should be disabled'); openStoragePoolKebab(CEPH_DEFAULT_BLOCK_POOL_NAME, true); - cy.log(poolMessage(poolName, POOL_PROGRESS.NOTALLOWED)); + cy.log(poolMessage(poolName, PoolProgress.NOTALLOWED)); }); it('deletion of a non-default pool deletion pool is successful', () => { @@ -80,10 +80,10 @@ describe('Block pool on ODF UI', () => { cy.contains('Delete Storage Pool'); cy.byTestID('pool-bound-message').contains( - poolMessage(poolName, POOL_PROGRESS.BOUNDED) + poolMessage(poolName, PoolProgress.BOUNDED) ); cy.byTestID('pool-storage-classes').contains(scName); - triggerPoolFormFooterAction(POOL_PROGRESS.BOUNDED); + triggerPoolFormFooterAction(PoolProgress.BOUNDED); cy.log('Delete pvc and storage class, then try pool deletion'); cy.exec(`oc delete pvc ${pvcName} -n default`, { @@ -106,7 +106,7 @@ describe('Tests form validations on block pool', () => { }); fieldValidationOnWizardFormsTests(nameFieldTestId, 'Create', () => - fillStoragePoolForm(POOL_TYPE.BLOCK, 'test-name') + fillStoragePoolForm(PoolType.BLOCK, 'test-name') ); }); @@ -119,15 +119,15 @@ describe('Filesystem pool on ODF UI', () => { }); it('creates a new pool', () => { - createStoragePool(POOL_TYPE.FILESYSTEM, poolName); + createStoragePool(PoolType.FILESYSTEM, poolName); - cy.log(`Verify ${POOL_TYPE.FILESYSTEM} pool creation`); + cy.log(`Verify ${PoolType.FILESYSTEM} pool creation`); cy.byTestID(`${poolFullName}-replicas`).contains('2'); cy.byTestID(`${poolFullName}-compression`).contains('Enabled'); }); it(`updates a non-default pool`, () => { - cy.log(`Updating a newly created ${POOL_TYPE.FILESYSTEM} pool`); + cy.log(`Updating a newly created ${PoolType.FILESYSTEM} pool`); openStoragePoolKebab(poolFullName); cy.byTestActionID('Edit Pool').click(); cy.contains('Edit Storage Pool'); @@ -152,6 +152,6 @@ describe('Filesystem pool on ODF UI', () => { it('actions on the default pool are not allowed', () => { cy.log('Kebab action should be disabled'); openStoragePoolKebab(CEPH_DEFAULT_FS_POOL_NAME, true); - cy.log(poolMessage[POOL_PROGRESS.NOTALLOWED]); + cy.log(poolMessage[PoolProgress.NOTALLOWED]); }); }); diff --git a/cypress/views/block-pool.ts b/cypress/views/block-pool.ts index 519a38283..94ff221fe 100644 --- a/cypress/views/block-pool.ts +++ b/cypress/views/block-pool.ts @@ -1,11 +1,12 @@ import { CEPH_DEFAULT_BLOCK_POOL_NAME, - POOL_PROGRESS, + PoolProgress, } from '../constants/storage-pool-const'; import { STORAGE_SYSTEM_NAME } from '../consts'; import { app } from '../support/pages/app'; import { NS } from '../utils/consts'; import { ODFCommon } from '../views/odf-common'; +import { triggerPoolFormFooterAction } from './storage-pool'; // Pool var export const poolName: string = 'example.pool'; @@ -13,13 +14,13 @@ export const replicaCount: string = '2'; export const scName: string = 'testing-sc'; export const poolMessage: { - [key in POOL_PROGRESS]?: string; + [key in PoolProgress]?: string; } = { - [POOL_PROGRESS.FAILED]: `Pool "${poolName}" already exists`, - [POOL_PROGRESS.CREATED]: `Pool ${poolName} was successfully created`, - [POOL_PROGRESS.NOTALLOWED]: + [PoolProgress.FAILED]: `Pool "${poolName}" already exists`, + [PoolProgress.CREATED]: `Pool ${poolName} was successfully created`, + [PoolProgress.NOTALLOWED]: "Pool management tasks are not supported for default pool and ODF's external mode.", - [POOL_PROGRESS.BOUNDED]: `${poolName} cannot be deleted. When a pool is bounded to PVC it cannot be deleted. Please detach all the resources from StorageClass(es):`, + [PoolProgress.BOUNDED]: `${poolName} cannot be deleted. When a pool is bounded to PVC it cannot be deleted. Please detach all the resources from StorageClass(es):`, }; export const navigateToBlockPool = () => { @@ -40,40 +41,6 @@ export const populateBlockPoolForm = () => { cy.byTestID('compression-checkbox').check(); }; -export enum Actions { - created = 'created', - failed = 'failed', - notAllowed = 'notAllowed', - bound = 'bounded', -} - -export const verifyFooterActions = (action: string) => { - switch (action) { - case Actions.failed: - cy.log('Check try-again-action and finish-action are enabled'); - cy.byLegacyTestID('modal-try-again-action').should('be.visible'); - cy.byLegacyTestID('modal-finish-action').click(); - break; - case Actions.created: - cy.log('Check finish-action is enabled'); - cy.byLegacyTestID('modal-finish-action').click(); - break; - case Actions.notAllowed: - cy.log('Check close-action is enabled'); - cy.byLegacyTestID('modal-close-action').click(); - break; - case Actions.bound: - cy.log('Check go-to-pvc-list-action and close-action are enabled'); - cy.byLegacyTestID('modal-go-to-pvc-list-action').should('be.visible'); - cy.byLegacyTestID('modal-close-action').click(); - break; - default: - cy.log(`Invoke ${action} action`); - cy.byLegacyTestID('confirm-action').scrollIntoView(); - cy.byLegacyTestID('confirm-action').click(); - } -}; - export const verifyBlockPoolJSON = ( compressionEnabled: boolean = true, replica: string = replicaCount @@ -100,7 +67,7 @@ export const verifyBlockPoolJSON = ( export const createBlockPool = () => { cy.byTestID('item-create').click(); populateBlockPoolForm(); - verifyFooterActions('create'); + triggerPoolFormFooterAction('create'); app.waitForLoad(); cy.log('Verify a new block pool creation'); cy.byTestID('status-text').should('contain', 'Ready', { timeout: 2 * 60000 }); diff --git a/cypress/views/storage-pool.ts b/cypress/views/storage-pool.ts index 8d78c43ff..24418fc9d 100644 --- a/cypress/views/storage-pool.ts +++ b/cypress/views/storage-pool.ts @@ -1,9 +1,10 @@ import { CEPH_DEFAULT_BLOCK_POOL_NAME, - POOL_PROGRESS, - POOL_TYPE, + CEPH_DEFAULT_FS_POOL_NAME, + PoolProgress, + PoolType, } from '../constants/storage-pool-const'; -import { STORAGE_SYSTEM_NAME } from '../consts'; +import { SECOND, STORAGE_SYSTEM_NAME } from '../consts'; import { NS } from '../utils/consts'; import { ODFCommon } from '../views/odf-common'; import { modal } from './modals'; @@ -14,16 +15,16 @@ export const scName: string = 'testing-sc'; export const poolMessage = ( poolName: string, - poolProgress: POOL_PROGRESS + poolProgress: PoolProgress ): string => { switch (poolProgress) { - case POOL_PROGRESS.FAILED: + case PoolProgress.FAILED: return `Pool "${poolName}" already exists`; - case POOL_PROGRESS.CREATED: + case PoolProgress.CREATED: return `Pool ${poolName} was successfully created`; - case POOL_PROGRESS.NOTALLOWED: + case PoolProgress.NOTALLOWED: return "Pool management tasks are not supported for default pool and ODF's external mode."; - case POOL_PROGRESS.BOUNDED: + case PoolProgress.BOUNDED: return `${poolName} cannot be deleted. When a pool is bounded to PVC it cannot be deleted. Please detach all the resources from StorageClass(es):`; default: return ''; @@ -38,8 +39,13 @@ export const navigateToStoragePoolList = () => { cy.byTestID('horizontal-link-Storage pools').click(); }; -const prepareStorageClassForm = (poolType: POOL_TYPE) => { - const provisioner = poolType === POOL_TYPE.BLOCK ? 'rbd' : 'cephfs'; +export const showAvailablePoolsInSCForm = (poolType: PoolType) => { + const provisioner = poolType === PoolType.BLOCK ? 'rbd' : 'cephfs'; + const defaultPool = + poolType === PoolType.BLOCK + ? CEPH_DEFAULT_BLOCK_POOL_NAME + : CEPH_DEFAULT_FS_POOL_NAME; + cy.log('Selecting provisioner'); cy.byTestID('storage-class-provisioner-dropdown').click(); cy.byLegacyTestID('dropdown-text-filter').type( @@ -48,24 +54,26 @@ const prepareStorageClassForm = (poolType: POOL_TYPE) => { cy.byTestID('dropdown-menu-item-link') .contains(`openshift-storage.${provisioner}.csi.ceph.com`) .click(); - - cy.log('Click on: Create new storage pool'); - cy.byTestID('pool-dropdown-toggle', { timeout: 1000 }) + cy.log('Show Storage pool list.'); + cy.byTestID('pool-dropdown-toggle', { timeout: 5 * SECOND }) .should('be.visible') .click(); - cy.byTestID('create-new-pool-button').should('be.visible').click(); + cy.byTestID('create-new-pool-button').should('be.visible'); + cy.byTestID(defaultPool).should('be.visible'); }; -export const fillPoolModalForm = (poolType: POOL_TYPE, poolName: string) => { - prepareStorageClassForm(poolType); - cy.log('Make sure the storage pool creation form is open'); +export const fillPoolModalForm = (poolType: PoolType, poolName: string) => { + showAvailablePoolsInSCForm(poolType); + cy.log('Click on: Create new storage pool'); + cy.byTestID('create-new-pool-button').click(); + cy.log('Make sure the storage pool creation form modal is opened.'); modal.shouldBeOpened(); modal.modalTitleShouldContain('Create Storage Pool'); fillStoragePoolForm(poolType, poolName); }; export const createStoragePoolInSCForm = ( - poolType: POOL_TYPE, + poolType: PoolType, poolName: string ) => { fillPoolModalForm(poolType, poolName); @@ -73,9 +81,9 @@ export const createStoragePoolInSCForm = ( cy.log(`Verify the ${poolType} pool creation`); cy.byTestID('empty-state-body').contains( - poolMessage(poolName, POOL_PROGRESS.CREATED) + poolMessage(poolName, PoolProgress.CREATED) ); - triggerPoolFormFooterAction(POOL_PROGRESS.CREATED); + triggerPoolFormFooterAction(PoolProgress.CREATED); cy.byTestID('pool-dropdown-toggle').contains(poolName); }; @@ -84,7 +92,7 @@ export const checkStoragePoolIsSelectableInSCForm = (poolName: string) => { cy.byTestID(poolName).should('be.visible'); }; -export const fillStoragePoolForm = (poolType: POOL_TYPE, poolName: string) => { +export const fillStoragePoolForm = (poolType: PoolType, poolName: string) => { cy.byTestID(`type-${poolType.toLowerCase()}`).click(); cy.byTestID('new-pool-name-textbox').clear(); cy.byTestID('new-pool-name-textbox').type(poolName); @@ -95,36 +103,34 @@ export const fillStoragePoolForm = (poolType: POOL_TYPE, poolName: string) => { cy.byTestID('compression-checkbox').check(); }; -export enum Actions { - created = 'created', - failed = 'failed', - notAllowed = 'notAllowed', - bound = 'bounded', -} - export const triggerPoolFormFooterAction = (action: string) => { switch (action) { - case Actions.failed: + case PoolProgress.FAILED: cy.log('Check try-again-action and finish-action are enabled'); cy.byLegacyTestID('modal-try-again-action').should('be.visible'); + cy.byLegacyTestID('modal-finish-action').should('be.visible'); cy.byLegacyTestID('modal-finish-action').click(); break; - case Actions.created: + case PoolProgress.CREATED: cy.log('Check finish-action is enabled'); + cy.byLegacyTestID('modal-finish-action').should('be.visible'); cy.byLegacyTestID('modal-finish-action').click(); break; - case Actions.notAllowed: + case PoolProgress.NOTALLOWED: cy.log('Check close-action is enabled'); + cy.byLegacyTestID('modal-close-action').should('be.visible'); cy.byLegacyTestID('modal-close-action').click(); break; - case Actions.bound: + case PoolProgress.BOUNDED: cy.log('Check go-to-pvc-list-action and close-action are enabled'); cy.byLegacyTestID('modal-go-to-pvc-list-action').should('be.visible'); + cy.byLegacyTestID('modal-close-action').should('be.visible'); cy.byLegacyTestID('modal-close-action').click(); break; default: cy.log(`Invoke ${action} action`); cy.byLegacyTestID('confirm-action').scrollIntoView(); + cy.byLegacyTestID('confirm-action').should('be.visible'); cy.byLegacyTestID('confirm-action').click(); } }; @@ -153,7 +159,7 @@ export const verifyBlockPoolJSON = ( }); }; -export const createStoragePool = (poolType: POOL_TYPE, poolName: string) => { +export const createStoragePool = (poolType: PoolType, poolName: string) => { cy.byTestID('item-create').click(); fillStoragePoolForm(poolType, poolName); triggerPoolFormFooterAction('create'); diff --git a/locales/en/plugin__odf-console.json b/locales/en/plugin__odf-console.json index c4b0aeb3e..305e67331 100644 --- a/locales/en/plugin__odf-console.json +++ b/locales/en/plugin__odf-console.json @@ -981,7 +981,9 @@ "MultiCloud Object Gateway supports encryption for objects by default.": "MultiCloud Object Gateway supports encryption for objects by default.", "Enable data encryption for block and file storage": "Enable data encryption for block and file storage", "Enable encryption": "Enable encryption", - "A secure mode that encrypts all data passing over the network": "A secure mode that encrypts all data passing over the network", + "Encrypts all Ceph traffic including data, using Ceph msgrv2": "Encrypts all Ceph traffic including data, using Ceph msgrv2", + "Verify your RHCS cluster has the necessary in-transit encryption settings configured to enable in-transit encryption on your external cluster. Refer to the documentation for detailed configuration steps.": "Verify your RHCS cluster has the necessary in-transit encryption settings configured to enable in-transit encryption on your external cluster. Refer to the documentation for detailed configuration steps.", + "Documentation link": "Documentation link", "An error has occurred: {{error}}": "An error has occurred: {{error}}", "The uploaded file is not a valid JSON file": "The uploaded file is not a valid JSON file", "External storage system metadata": "External storage system metadata", diff --git a/package.json b/package.json index 605d5854d..7d52b477e 100644 --- a/package.json +++ b/package.json @@ -184,7 +184,8 @@ "webpack": "^5.96.1", "webpack-bundle-analyzer/ws": "^7.5.10", "webpack-dev-server/express": "^4.21.0", - "tough-cookie": "^4.1.3" + "tough-cookie": "^4.1.3", + "cross-spawn": "^7.0.6" }, "engines": { "node": ">=20.x" diff --git a/packages/ibm/system-connection-details.tsx b/packages/ibm/system-connection-details.tsx index f62f79777..95bccb8c4 100644 --- a/packages/ibm/system-connection-details.tsx +++ b/packages/ibm/system-connection-details.tsx @@ -5,7 +5,7 @@ import { CreatePayload, StorageClassComponentProps as ExternalComponentProps, CanGoToNextStep, - waitToCreate, + WaitToCreate, } from '@odf/odf-plugin-sdk/extensions'; import { FormGroupController } from '@odf/shared/form-group-controller'; import { useK8sList } from '@odf/shared/hooks/useK8sList'; @@ -329,7 +329,7 @@ export const flashSystemCanGoToNextStep: CanGoToNextStep = ( const isCRDAvailable = (crd: K8sResourceKind, plural: string) => crd?.status?.acceptedNames?.plural === plural; -export const waitforCRD: waitToCreate = async (model) => { +export const waitforCRD: WaitToCreate = async (model) => { const crdName = [model.plural, model.apiGroup].join('.'); const POLLING_INTERVAL = 5000; const maxAttempts = 30; diff --git a/packages/mco/components/create-dr-policy/create-dr-policy.tsx b/packages/mco/components/create-dr-policy/create-dr-policy.tsx index 4874ef8d2..d0f7401a7 100644 --- a/packages/mco/components/create-dr-policy/create-dr-policy.tsx +++ b/packages/mco/components/create-dr-policy/create-dr-policy.tsx @@ -29,7 +29,7 @@ import { } from '@patternfly/react-core'; import { MAX_ALLOWED_CLUSTERS, - REPLICATION_TYPE, + ReplicationType, ODFMCO_OPERATOR, } from '../../constants'; import { DRPolicyModel, MirrorPeerModel } from '../../models'; @@ -53,7 +53,7 @@ const getDRPolicyListPageLink = (url: string) => const validateDRPolicyInputs = ( policyName: string, - replicationType: REPLICATION_TYPE, + replicationType: ReplicationType, clusterCount: number, isClusterSelectionValid: boolean ) => @@ -235,7 +235,7 @@ const CreateDRPolicy: React.FC<{}> = () => { syncIntervalTime={state.syncIntervalTime} dispatch={dispatch} /> - {state.replicationType === REPLICATION_TYPE.ASYNC && ( + {state.replicationType === ReplicationType.ASYNC && ( > = ({ return ( <> {getName(cluster)} {isManagedClusterAvailable ? ( @@ -78,20 +80,24 @@ const ClusterRow: React.FC> = ({ )} {odfVersion || t('Not Installed')} {!!clientName ? clientName : t('Unavailable')} - + {region || t('Unavailable')} @@ -154,7 +160,7 @@ const PaginatedClusterTable: React.FC = ({ setSelectedRows={onChange} loaded={isLoaded} loadError={error} - variant={TABLE_VARIANT.DEFAULT} + variant={TableVariant.DEFAULT} isColumnSelectableHidden isRowSelectable={(cluster) => isRowSelectable(cluster, selectedClusters) diff --git a/packages/mco/components/create-dr-policy/select-replication-type.tsx b/packages/mco/components/create-dr-policy/select-replication-type.tsx index 01bf97b18..17af53844 100644 --- a/packages/mco/components/create-dr-policy/select-replication-type.tsx +++ b/packages/mco/components/create-dr-policy/select-replication-type.tsx @@ -5,7 +5,7 @@ import { useCustomTranslation } from '@odf/shared/useCustomTranslationHook'; import { RequestSizeInput } from '@odf/shared/utils/RequestSizeInput'; import { FormGroup, SelectOption } from '@patternfly/react-core'; import { - REPLICATION_TYPE, + ReplicationType, REPLICATION_DISPLAY_TEXT, SYNC_SCHEDULE_DISPLAY_TEXT, } from '../../constants'; @@ -69,9 +69,7 @@ export const SelectReplicationType: React.FC = ({ dispatch({ type: DRPolicyActionType.SET_REPLICATION_TYPE, payload: - cephFSID1 === cephFSID2 - ? REPLICATION_TYPE.SYNC - : REPLICATION_TYPE.ASYNC, + cephFSID1 === cephFSID2 ? ReplicationType.SYNC : ReplicationType.ASYNC, }); }, [selectedClusters, dispatch]); @@ -86,7 +84,7 @@ export const SelectReplicationType: React.FC = ({ /> )); - const onChange = (replType: REPLICATION_TYPE) => + const onChange = (replType: ReplicationType) => dispatch({ type: DRPolicyActionType.SET_REPLICATION_TYPE, payload: replType, @@ -107,7 +105,7 @@ export const SelectReplicationType: React.FC = ({ onChange={onChange} /> - {replicationType === REPLICATION_TYPE.ASYNC && ( + {replicationType === ReplicationType.ASYNC && ( ; }; diff --git a/packages/mco/components/create-dr-policy/selected-cluster-validator.tsx b/packages/mco/components/create-dr-policy/selected-cluster-validator.tsx index d819023e9..bc3edfdb2 100644 --- a/packages/mco/components/create-dr-policy/selected-cluster-validator.tsx +++ b/packages/mco/components/create-dr-policy/selected-cluster-validator.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import { pluralize } from '@odf/core/components/utils'; -import { REPLICATION_TYPE } from '@odf/mco/constants'; +import { ReplicationType } from '@odf/mco/constants'; import { getDRPolicyResourceObj } from '@odf/mco/hooks'; import { DRPolicyKind, MirrorPeerKind } from '@odf/mco/types'; import { getReplicationType } from '@odf/mco/utils'; @@ -34,7 +34,7 @@ const checkSyncPolicyExists = ( drPolicies.some((drPolicy) => { const { drClusters, schedulingInterval } = drPolicy.spec; const isSyncPolicy = - getReplicationType(schedulingInterval) === REPLICATION_TYPE.SYNC; + getReplicationType(schedulingInterval) === ReplicationType.SYNC; return ( isSyncPolicy && drClusters.every((cluster) => clusters.includes(cluster)) ); diff --git a/packages/mco/components/create-dr-policy/utils/cluster-list-utils.ts b/packages/mco/components/create-dr-policy/utils/cluster-list-utils.ts index 590527e90..d243cdadd 100644 --- a/packages/mco/components/create-dr-policy/utils/cluster-list-utils.ts +++ b/packages/mco/components/create-dr-policy/utils/cluster-list-utils.ts @@ -29,7 +29,7 @@ import { ManagedClusterInfoType, ODFConfigInfoType } from '../utils/reducer'; export const INITIAL_PAGE_NUMBER = 1; export const COUNT_PER_PAGE_NUMBER = 10; -export enum COLUMN_NAMES { +export enum ClusterListColumns { ManagedCluster, AvailabilityStatus, DataFoundation, @@ -60,18 +60,21 @@ export const getColumns = (t: TFunction) => [ }, ]; -export const getColumnHelper = (name: COLUMN_NAMES, t: TFunction) => { +export const getColumnHelper = ( + name: ClusterListColumns, + t: TFunction +) => { const columns = getColumns(t); switch (name) { - case COLUMN_NAMES.ManagedCluster: + case ClusterListColumns.ManagedCluster: return columns[0]; - case COLUMN_NAMES.AvailabilityStatus: + case ClusterListColumns.AvailabilityStatus: return columns[1]; - case COLUMN_NAMES.DataFoundation: + case ClusterListColumns.DataFoundation: return columns[2]; - case COLUMN_NAMES.StorageClients: + case ClusterListColumns.StorageClients: return columns[3]; - case COLUMN_NAMES.Region: + case ClusterListColumns.Region: return columns[4]; } }; diff --git a/packages/mco/components/create-dr-policy/utils/k8s-utils.ts b/packages/mco/components/create-dr-policy/utils/k8s-utils.ts index c26e90f63..a830d72ce 100644 --- a/packages/mco/components/create-dr-policy/utils/k8s-utils.ts +++ b/packages/mco/components/create-dr-policy/utils/k8s-utils.ts @@ -1,4 +1,4 @@ -import { RBD_IMAGE_FLATTEN_LABEL, REPLICATION_TYPE } from '@odf/mco/constants'; +import { RBD_IMAGE_FLATTEN_LABEL, ReplicationType } from '@odf/mco/constants'; import { DRPolicyModel, MirrorPeerModel } from '@odf/mco/models'; import { DRPolicyKind, MirrorPeerKind } from '@odf/mco/types'; import { parseNamespaceName } from '@odf/mco/utils'; @@ -53,7 +53,7 @@ const fetchMirrorPeer = ( const createMirrorPeer = ( selectedClusters: ManagedClusterInfoType[], - replicationType: REPLICATION_TYPE + replicationType: ReplicationType ): Promise => { const mirrorPeerPayload: MirrorPeerKind = { apiVersion: getAPIVersionForModel(MirrorPeerModel), @@ -73,7 +73,7 @@ const createMirrorPeer = ( const createDRPolicy = ( policyName: string, - replicationType: REPLICATION_TYPE, + replicationType: ReplicationType, syncIntervalTime: string, enableRBDImageFlatten: boolean, peerNames: string[] @@ -87,7 +87,7 @@ const createDRPolicy = ( ? { matchLabels: RBD_IMAGE_FLATTEN_LABEL } : {}, schedulingInterval: - replicationType === REPLICATION_TYPE.ASYNC ? syncIntervalTime : '0m', + replicationType === ReplicationType.ASYNC ? syncIntervalTime : '0m', drClusters: peerNames, }, }; diff --git a/packages/mco/components/create-dr-policy/utils/reducer.ts b/packages/mco/components/create-dr-policy/utils/reducer.ts index 2e02c74b8..e41264e6a 100644 --- a/packages/mco/components/create-dr-policy/utils/reducer.ts +++ b/packages/mco/components/create-dr-policy/utils/reducer.ts @@ -1,4 +1,4 @@ -import { REPLICATION_TYPE } from '@odf/mco/constants'; +import { ReplicationType } from '@odf/mco/constants'; import { ConnectedClient } from '@odf/mco/types'; import { K8sResourceCommon } from '@openshift-console/dynamic-plugin-sdk'; @@ -43,7 +43,7 @@ export type DRPolicyState = { // DRPolicy CR name. policyName: string; // DRPolicy type Async / Sync. - replicationType: REPLICATION_TYPE; + replicationType: ReplicationType; // Sync interval schedule for Async policy. syncIntervalTime: string; // Selected managed cluster for DRPolicy paring. @@ -75,7 +75,7 @@ export const drPolicyInitialState: DRPolicyState = { export type DRPolicyAction = | { type: DRPolicyActionType.SET_POLICY_NAME; payload: string } - | { type: DRPolicyActionType.SET_REPLICATION_TYPE; payload: REPLICATION_TYPE } + | { type: DRPolicyActionType.SET_REPLICATION_TYPE; payload: ReplicationType } | { type: DRPolicyActionType.SET_SYNC_INTERVAL_TIME; payload: string } | { type: DRPolicyActionType.SET_SELECTED_CLUSTERS; diff --git a/packages/mco/components/drpolicy-list-page/drpolicy-list-page.tsx b/packages/mco/components/drpolicy-list-page/drpolicy-list-page.tsx index 4b8b4fa84..8ed96034e 100644 --- a/packages/mco/components/drpolicy-list-page/drpolicy-list-page.tsx +++ b/packages/mco/components/drpolicy-list-page/drpolicy-list-page.tsx @@ -20,7 +20,7 @@ import { } from '@openshift-console/dynamic-plugin-sdk'; import { Trans } from 'react-i18next'; import { useLocation, useNavigate } from 'react-router-dom-v5-compat'; -import { HUB_CLUSTER_NAME, REPLICATION_TYPE } from '../../constants'; +import { HUB_CLUSTER_NAME, ReplicationType } from '../../constants'; import { DRPolicyToAppCount, getDRPolicyResourceObj, @@ -60,12 +60,12 @@ const DRPolicyRow: React.FC> = ({ {clusterNames} - {replicationType === REPLICATION_TYPE.ASYNC + {replicationType === ReplicationType.ASYNC ? t('{{async}}, interval: {{syncInterval}}', { - async: REPLICATION_TYPE.ASYNC, + async: ReplicationType.ASYNC, syncInterval, }) - : REPLICATION_TYPE.SYNC} + : ReplicationType.SYNC} {appCount > 0 diff --git a/packages/mco/components/mco-dashboard/disaster-recovery/cluster-app-card/application.tsx b/packages/mco/components/mco-dashboard/disaster-recovery/cluster-app-card/application.tsx index 498827caf..ff9b0dcd8 100644 --- a/packages/mco/components/mco-dashboard/disaster-recovery/cluster-app-card/application.tsx +++ b/packages/mco/components/mco-dashboard/disaster-recovery/cluster-app-card/application.tsx @@ -3,8 +3,8 @@ */ import * as React from 'react'; -import { DRPC_STATUS } from '@odf/mco/constants'; -import { REPLICATION_TYPE } from '@odf/mco/constants'; +import { DRPCStatus } from '@odf/mco/constants'; +import { ReplicationType } from '@odf/mco/constants'; import { PlacementControlInfo, ProtectedAppsMap } from '@odf/mco/types'; import { getDRStatus } from '@odf/mco/utils'; import { formatTime } from '@odf/shared/details-page/datetime'; @@ -59,12 +59,12 @@ export const getCurrentActivity = ( preferredCluster: string, t: TFunction, isCleanupPending?: boolean, - replicationType?: REPLICATION_TYPE + replicationType?: ReplicationType ): { description: string; status: string; icon: JSX.Element } => { - const status = currentStatus as DRPC_STATUS; + const status = currentStatus as DRPCStatus; switch (status) { - case DRPC_STATUS.Relocating: + case DRPCStatus.Relocating: return isCleanupPending ? { description: t( @@ -82,7 +82,7 @@ export const getCurrentActivity = ( icon: , }; - case DRPC_STATUS.Relocated: + case DRPCStatus.Relocated: return { description: t('Relocated to cluster {{ preferredCluster }}', { preferredCluster, @@ -91,7 +91,7 @@ export const getCurrentActivity = ( icon: , }; - case DRPC_STATUS.FailingOver: + case DRPCStatus.FailingOver: return { description: t('FailingOver to cluster {{ failoverCluster }}', { failoverCluster, @@ -100,9 +100,9 @@ export const getCurrentActivity = ( icon: , }; - case DRPC_STATUS.FailedOver: + case DRPCStatus.FailedOver: if (isCleanupPending) { - return replicationType === REPLICATION_TYPE.ASYNC + return replicationType === ReplicationType.ASYNC ? { description: t( 'Clean up application resources on failed cluster {{ preferredCluster }} to start the replication.', @@ -141,7 +141,7 @@ export const getCurrentActivity = ( const getSubscriptionRow = ( placementControlInfoList: PlacementControlInfo[] = [] ): SubscriptionRowProps[] => { - const _getRowProps = ( + const getRowProps = ( subscriptions: string[], { status, @@ -160,10 +160,7 @@ const getSubscriptionRow = ( return placementControlInfoList.reduce( (acc, placementControlInfo) => [ ...acc, - ..._getRowProps( - placementControlInfo?.subscriptions, - placementControlInfo - ), + ...getRowProps(placementControlInfo?.subscriptions, placementControlInfo), ], [] ); diff --git a/packages/mco/components/mco-dashboard/disaster-recovery/cluster-app-card/cluster-app-card.tsx b/packages/mco/components/mco-dashboard/disaster-recovery/cluster-app-card/cluster-app-card.tsx index 81ddc27f0..83ee4ec8a 100644 --- a/packages/mco/components/mco-dashboard/disaster-recovery/cluster-app-card/cluster-app-card.tsx +++ b/packages/mco/components/mco-dashboard/disaster-recovery/cluster-app-card/cluster-app-card.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import { ALL_APPS, applicationDetails, - APPLICATION_TYPE, + DRApplication, APPLICATION_TYPE_DISPLAY_TEXT, } from '@odf/mco/constants'; import { @@ -218,11 +218,11 @@ const ClusterWiseCard: React.FC = ({ const AppWiseCard: React.FC = (props) => { switch (props?.selectedApplication?.appType) { - case APPLICATION_TYPE.APPSET: + case DRApplication.APPSET: return ; - case APPLICATION_TYPE.SUBSCRIPTION: + case DRApplication.SUBSCRIPTION: return ; - case APPLICATION_TYPE.DISCOVERED: + case DRApplication.DISCOVERED: return ; default: return null; @@ -250,7 +250,7 @@ const ClusterAppCardTitle: React.FC = ({
{t('Application: ')} - {appType === APPLICATION_TYPE.DISCOVERED ? ( + {appType === DRApplication.DISCOVERED ? ( app.name ) : ( @@ -400,5 +400,5 @@ type ClusterAppCardTitleProps = { cluster: string; appKind: string; appAPIVersion: string; - appType: APPLICATION_TYPE; + appType: DRApplication; }; diff --git a/packages/mco/components/mco-dashboard/disaster-recovery/cluster-app-card/cluster.tsx b/packages/mco/components/mco-dashboard/disaster-recovery/cluster-app-card/cluster.tsx index 18e462f24..197a4b745 100644 --- a/packages/mco/components/mco-dashboard/disaster-recovery/cluster-app-card/cluster.tsx +++ b/packages/mco/components/mco-dashboard/disaster-recovery/cluster-app-card/cluster.tsx @@ -11,13 +11,13 @@ import { ODR_CLUSTER_OPERATOR, VOL_SYNC, ACM_ENDPOINT, - VOLUME_REPLICATION_HEALTH, + VolumeReplicationHealth, OBJECT_NAMESPACE, OBJECT_NAME, MANAGED_CLUSTER_CONDITION_AVAILABLE, - APPLICATION_TYPE, + DRApplication, LEAST_SECONDS_IN_PROMETHEUS, - REPLICATION_TYPE, + ReplicationType, } from '@odf/mco/constants'; import { DRClusterAppsMap, ProtectedAppsMap } from '@odf/mco/types'; import { @@ -70,7 +70,7 @@ const checkVolumeReplicationHealth = ( getVolumeReplicationHealth( Number(item.value[1]) || 0, placementInfo.volumeSyncInterval - )[0] !== VOLUME_REPLICATION_HEALTH.HEALTHY + )[0] !== VolumeReplicationHealth.HEALTHY ) ); @@ -81,14 +81,14 @@ const checkKubeObjBackupHealth = ( protectedAppMap.placementControlInfo[0]; const objCaptureInterval = protectedAppMap.placementControlInfo[0].kubeObjSyncInterval; - return protectedAppMap.appType === APPLICATION_TYPE.DISCOVERED && - replicationType === REPLICATION_TYPE.ASYNC + return protectedAppMap.appType === DRApplication.DISCOVERED && + replicationType === ReplicationType.ASYNC ? getVolumeReplicationHealth( !!kubeObjectLastProtectionTime ? getTimeDifferenceInSeconds(kubeObjectLastProtectionTime) : LEAST_SECONDS_IN_PROMETHEUS, objCaptureInterval - )[0] !== VOLUME_REPLICATION_HEALTH.HEALTHY + )[0] !== VolumeReplicationHealth.HEALTHY : false; }; @@ -266,9 +266,7 @@ export const ApplicationsSection: React.FC = ({ checkKubeObjBackupHealth(protectedAppMap); const hasIssue = hasVolumeReplicationIssue || hasKubeObjBackupIssue; hasIssue && - ++acc[ - protectedAppMap.appType === APPLICATION_TYPE.DISCOVERED ? 0 : 1 - ]; + ++acc[protectedAppMap.appType === DRApplication.DISCOVERED ? 0 : 1]; return acc; }, [0, 0] diff --git a/packages/mco/components/mco-dashboard/disaster-recovery/cluster-app-card/common.tsx b/packages/mco/components/mco-dashboard/disaster-recovery/cluster-app-card/common.tsx index da70739fc..ca3249d71 100644 --- a/packages/mco/components/mco-dashboard/disaster-recovery/cluster-app-card/common.tsx +++ b/packages/mco/components/mco-dashboard/disaster-recovery/cluster-app-card/common.tsx @@ -9,8 +9,8 @@ import { GITOPS_OPERATOR_NAMESPACE, LEAST_SECONDS_IN_PROMETHEUS, DISCOVERED_APP_NS, - REPLICATION_TYPE, - VOLUME_REPLICATION_HEALTH, + ReplicationType, + VolumeReplicationHealth, } from '@odf/mco/constants'; import { ACMSubscriptionModel, @@ -105,14 +105,14 @@ export const VolumeSummarySection: React.FC = ({ const pvcLastSyncTime = pvcData?.lastSyncTime; // Only RDR(async) has volume replication const health = - pvcData.replicationType === REPLICATION_TYPE.ASYNC + pvcData.replicationType === ReplicationType.ASYNC ? getVolumeReplicationHealth( !!pvcLastSyncTime ? getTimeDifferenceInSeconds(pvcLastSyncTime) : LEAST_SECONDS_IN_PROMETHEUS, pvcData?.schedulingInterval )[0] - : VOLUME_REPLICATION_HEALTH.HEALTHY; + : VolumeReplicationHealth.HEALTHY; !!selectedApplication ? filterPVCDataUsingApp(pvcData, selectedApplication) && volumeHealth[health]++ @@ -429,18 +429,18 @@ export const ProtectedPVCsSection: React.FC = ({ const pvcLastSyncTime = protectedPVCItem?.lastSyncTime; // Only RDR(async) has volume replication const replicationHealth = - protectedPVCItem.replicationType === REPLICATION_TYPE.ASYNC + protectedPVCItem.replicationType === ReplicationType.ASYNC ? getVolumeReplicationHealth( !!pvcLastSyncTime ? getTimeDifferenceInSeconds(pvcLastSyncTime) : LEAST_SECONDS_IN_PROMETHEUS, protectedPVCItem?.schedulingInterval )[0] - : VOLUME_REPLICATION_HEALTH.HEALTHY; + : VolumeReplicationHealth.HEALTHY; (!!selectedApplication ? !!filterPVCDataUsingApp(protectedPVCItem, selectedApplication) && - replicationHealth !== VOLUME_REPLICATION_HEALTH.HEALTHY - : replicationHealth !== VOLUME_REPLICATION_HEALTH.HEALTHY) && acc++; + replicationHealth !== VolumeReplicationHealth.HEALTHY + : replicationHealth !== VolumeReplicationHealth.HEALTHY) && acc++; return acc; }, 0) || 0; diff --git a/packages/mco/components/mco-dashboard/disaster-recovery/parsers/applicationset-parser.tsx b/packages/mco/components/mco-dashboard/disaster-recovery/parsers/applicationset-parser.tsx index 6b2ea9f8f..6ff717f4e 100644 --- a/packages/mco/components/mco-dashboard/disaster-recovery/parsers/applicationset-parser.tsx +++ b/packages/mco/components/mco-dashboard/disaster-recovery/parsers/applicationset-parser.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { - APPLICATION_TYPE, - DRPC_STATUS, + DRApplication, + DRPCStatus, GITOPS_OPERATOR_NAMESPACE, } from '@odf/mco/constants'; import { @@ -132,7 +132,7 @@ export const useApplicationSetParser: UseApplicationSetParser = ( appNamespace: getNamespace(application), appKind: application?.kind, appAPIVersion: application?.apiVersion, - appType: APPLICATION_TYPE.APPSET, + appType: DRApplication.APPSET, placementControlInfo: [ { deploymentClusterName: decisionCluster, @@ -149,7 +149,7 @@ export const useApplicationSetParser: UseApplicationSetParser = ( drPlacementControl?.spec?.preferredCluster, lastVolumeGroupSyncTime: drPlacementControl?.status?.lastGroupSyncTime, - status: drPlacementControl?.status?.phase as DRPC_STATUS, + status: drPlacementControl?.status?.phase as DRPCStatus, }, ], }); diff --git a/packages/mco/components/mco-dashboard/disaster-recovery/parsers/discovered-parser.tsx b/packages/mco/components/mco-dashboard/disaster-recovery/parsers/discovered-parser.tsx index ea9206c7e..516109425 100644 --- a/packages/mco/components/mco-dashboard/disaster-recovery/parsers/discovered-parser.tsx +++ b/packages/mco/components/mco-dashboard/disaster-recovery/parsers/discovered-parser.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { - APPLICATION_TYPE, - DRPC_STATUS, + DRApplication, + DRPCStatus, DISCOVERED_APP_NS, } from '@odf/mco/constants'; import { @@ -102,7 +102,7 @@ export const useDiscoveredParser: UseDiscoveredParser = ( appNamespace: getNamespace(drPlacementControl), appKind: drPlacementControl.kind, appAPIVersion: drPlacementControl.apiVersion, - appType: APPLICATION_TYPE.DISCOVERED, + appType: DRApplication.DISCOVERED, placementControlInfo: [ { deploymentClusterName: decisionCluster, @@ -117,7 +117,7 @@ export const useDiscoveredParser: UseDiscoveredParser = ( preferredCluster: drPlacementControl.spec?.preferredCluster, lastVolumeGroupSyncTime: drPlacementControl.status?.lastGroupSyncTime, - status: drPlacementControl.status?.phase as DRPC_STATUS, + status: drPlacementControl.status?.phase as DRPCStatus, kubeObjSyncInterval: drPlacementControl.spec?.kubeObjectProtection ?.captureInterval, diff --git a/packages/mco/components/mco-dashboard/disaster-recovery/parsers/subscription-parser.tsx b/packages/mco/components/mco-dashboard/disaster-recovery/parsers/subscription-parser.tsx index 91e114a13..86c6cbc81 100644 --- a/packages/mco/components/mco-dashboard/disaster-recovery/parsers/subscription-parser.tsx +++ b/packages/mco/components/mco-dashboard/disaster-recovery/parsers/subscription-parser.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import { APPLICATION_TYPE, DRPC_STATUS } from '@odf/mco/constants'; +import { DRApplication, DRPCStatus } from '@odf/mco/constants'; import { SubscriptionGroupType, useDisasterRecoveryResourceWatch, @@ -50,7 +50,7 @@ const createPlacementControlInfoList = ( failoverCluster: drPlacementControl?.spec?.failoverCluster, preferredCluster: drPlacementControl?.spec?.preferredCluster, lastVolumeGroupSyncTime: drPlacementControl?.status?.lastGroupSyncTime, - status: drPlacementControl?.status?.phase as DRPC_STATUS, + status: drPlacementControl?.status?.phase as DRPCStatus, subscriptions: subscriptionGroup?.subscriptions?.map((subs) => getName(subs) ), @@ -74,7 +74,7 @@ const createProtectedAppMap = ( appNamespace: applicationNamespace, appKind: application?.kind, appAPIVersion: application?.apiVersion, - appType: APPLICATION_TYPE.SUBSCRIPTION, + appType: DRApplication.SUBSCRIPTION, placementControlInfo: createPlacementControlInfoList( subscriptionGroupsList, clusterName, diff --git a/packages/mco/components/modals/app-data-policies-status/argo-application-set.tsx b/packages/mco/components/modals/app-data-policies-status/argo-application-set.tsx index 7a2b0e666..73cad9223 100644 --- a/packages/mco/components/modals/app-data-policies-status/argo-application-set.tsx +++ b/packages/mco/components/modals/app-data-policies-status/argo-application-set.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { getNamespace, getName } from '@odf/shared/selectors'; import * as _ from 'lodash-es'; -import { DRPC_STATUS } from '../../../constants'; +import { DRPCStatus } from '../../../constants'; import { getDRClusterResourceObj, getDRPlacementControlResourceObj, @@ -42,10 +42,10 @@ export const ArogoApplicationSetStatus: React.FC if (!_.isEmpty(drResource)) { const drpc = drResource?.drPlacementControls?.[0]; const drPolicy = drResource?.drPolicy; - const status = drpc?.status?.phase as DRPC_STATUS; + const status = drpc?.status?.phase as DRPCStatus; const targetCluster = [ - DRPC_STATUS.FailedOver, - DRPC_STATUS.FailingOver, + DRPCStatus.FailedOver, + DRPCStatus.FailingOver, ].includes(status) ? drpc?.spec?.failoverCluster : drpc?.spec?.preferredCluster; diff --git a/packages/mco/components/modals/app-data-policies-status/dr-status.tsx b/packages/mco/components/modals/app-data-policies-status/dr-status.tsx index b379ca957..88519ec5f 100644 --- a/packages/mco/components/modals/app-data-policies-status/dr-status.tsx +++ b/packages/mco/components/modals/app-data-policies-status/dr-status.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import { REPLICATION_TYPE, DRPC_STATUS } from '@odf/mco/constants'; +import { ReplicationType, DRPCStatus } from '@odf/mco/constants'; import { fromNow } from '@odf/shared/details-page/datetime'; import { useCustomTranslation } from '@odf/shared/useCustomTranslationHook'; import { StatusIconAndText } from '@openshift-console/dynamic-plugin-sdk'; @@ -14,8 +14,8 @@ import { } from '@patternfly/react-core'; import { getDRStatus } from '../../../utils'; -const failOverStatus = [DRPC_STATUS.FailedOver, DRPC_STATUS.FailingOver]; -const relocateStatus = [DRPC_STATUS.Relocating, DRPC_STATUS.Relocated]; +const failOverStatus = [DRPCStatus.FailedOver, DRPCStatus.FailingOver]; +const relocateStatus = [DRPCStatus.Relocating, DRPCStatus.Relocated]; export const DRStatus: React.FC = (disasterRecoveryStatus) => { const { t } = useCustomTranslation(); @@ -29,8 +29,8 @@ export const DRStatus: React.FC = (disasterRecoveryStatus) => { targetCluster, } = drStatus || {}; const customText: string = [ - DRPC_STATUS.FailedOver, - DRPC_STATUS.Relocated, + DRPCStatus.FailedOver, + DRPCStatus.Relocated, ].includes(status) ? t('Completed') : t('In Progress'); @@ -54,7 +54,7 @@ export const DRStatus: React.FC = (disasterRecoveryStatus) => { {t('Disaster recovery')} - {replicationType === REPLICATION_TYPE.ASYNC ? ( + {replicationType === ReplicationType.ASYNC ? ( <> {t('{{drPolicy}}, sync every {{syncInterval}}', { @@ -140,9 +140,9 @@ export const DRStatus: React.FC = (disasterRecoveryStatus) => { export type DRStatusProps = { policyName: string; - status: DRPC_STATUS; + status: DRPCStatus; targetCluster: string; - replicationType: REPLICATION_TYPE; + replicationType: ReplicationType; dataLastSyncedOn: string; schedulingInterval: string; }; diff --git a/packages/mco/components/modals/app-data-policies-status/subscriptions/dr-status-card.tsx b/packages/mco/components/modals/app-data-policies-status/subscriptions/dr-status-card.tsx index 4e09acdcd..9747b5078 100644 --- a/packages/mco/components/modals/app-data-policies-status/subscriptions/dr-status-card.tsx +++ b/packages/mco/components/modals/app-data-policies-status/subscriptions/dr-status-card.tsx @@ -10,7 +10,7 @@ import { HelperTextItem, } from '@patternfly/react-core'; import { InProgressIcon } from '@patternfly/react-icons'; -import { DRPC_STATUS } from '../../../../constants'; +import { DRPCStatus } from '../../../../constants'; import { DRPlacementControlKind } from '../../../../types'; import { getDRPoliciesCount, DRPolicyMap } from '../../../../utils'; @@ -18,13 +18,12 @@ const updateStatusSummary = ( currentStatus: string, prevStatus?: DRStatusSummaryType ) => { - (currentStatus === DRPC_STATUS.FailedOver && - prevStatus.failover.finished++) || - (currentStatus === DRPC_STATUS.FailingOver && + (currentStatus === DRPCStatus.FailedOver && prevStatus.failover.finished++) || + (currentStatus === DRPCStatus.FailingOver && prevStatus.failover.inProgress++) || - (currentStatus === DRPC_STATUS.Relocated && + (currentStatus === DRPCStatus.Relocated && prevStatus.relocate.finished++) || - (currentStatus === DRPC_STATUS.Relocating && + (currentStatus === DRPCStatus.Relocating && prevStatus.relocate.inProgress++); return prevStatus; }; diff --git a/packages/mco/components/modals/app-data-policies-status/subscriptions/dr-status-table.tsx b/packages/mco/components/modals/app-data-policies-status/subscriptions/dr-status-table.tsx index 2c62c2417..41e18b8a4 100644 --- a/packages/mco/components/modals/app-data-policies-status/subscriptions/dr-status-table.tsx +++ b/packages/mco/components/modals/app-data-policies-status/subscriptions/dr-status-table.tsx @@ -26,7 +26,7 @@ import { ThProps, SortByDirection, } from '@patternfly/react-table'; -import { DRPC_STATUS } from '../../../../constants'; +import { DRPCStatus } from '../../../../constants'; import { DRPlacementControlKind } from '../../../../types'; import { DRPolicyMap, @@ -39,18 +39,18 @@ import './dr-status-table.scss'; const getLastDataSyncTime = (drpcList: DRPlacementControlKind[]): string => getLatestDate(drpcList?.map((drpc) => drpc?.status?.lastGroupSyncTime)); -const isRelocating = (status: DRPC_STATUS) => - [DRPC_STATUS.Relocating, DRPC_STATUS.Relocated].includes(status); +const isRelocating = (status: DRPCStatus) => + [DRPCStatus.Relocating, DRPCStatus.Relocated].includes(status); -const isFailingOver = (status: DRPC_STATUS) => - [DRPC_STATUS.FailingOver, DRPC_STATUS.FailedOver].includes(status); +const isFailingOver = (status: DRPCStatus) => + [DRPCStatus.FailingOver, DRPCStatus.FailedOver].includes(status); const getTargetClusters = ( currentStatus: string, drpcList: DRPlacementControlKind[] ) => { const targetClusters = drpcList.reduce((acc, drpc) => { - const status = DRPC_STATUS[drpc?.status?.phase] || ''; + const status = DRPCStatus[drpc?.status?.phase] || ''; if (status === currentStatus) { (isRelocating(status) && acc.add(drpc?.spec?.preferredCluster)) || (isFailingOver(status) && acc.add(drpc?.spec?.failoverCluster)); diff --git a/packages/mco/components/modals/app-failover-relocate/failover-relocate-modal-body.tsx b/packages/mco/components/modals/app-failover-relocate/failover-relocate-modal-body.tsx index ab01207cf..ff0750333 100644 --- a/packages/mco/components/modals/app-failover-relocate/failover-relocate-modal-body.tsx +++ b/packages/mco/components/modals/app-failover-relocate/failover-relocate-modal-body.tsx @@ -24,9 +24,9 @@ import { import { UnknownIcon } from '@patternfly/react-icons'; import { DRActionType, - REPLICATION_TYPE, + ReplicationType, ACM_OPERATOR_SPEC_NAME, - VOLUME_REPLICATION_HEALTH, + VolumeReplicationHealth, } from '../../../constants'; import { ErrorMessageType, @@ -39,7 +39,7 @@ import './failover-relocate-modal-body.scss'; const failoverPreCheck = (placementControl: PlacementControlProps) => { // Failover pre-check if (placementControl?.isTargetClusterAvailable) { - if (placementControl?.replicationType === REPLICATION_TYPE.SYNC) { + if (placementControl?.replicationType === ReplicationType.SYNC) { if (!placementControl?.isPrimaryClusterFenced) { // Primary cluster is unfenced return ErrorMessageType.PRIMARY_CLUSTER_IS_NOT_FENCED; @@ -61,7 +61,7 @@ const relocatePreCheck = (placementControl: PlacementControlProps) => { placementControl?.isTargetClusterAvailable && placementControl?.isPrimaryClusterAvailable ) { - if (placementControl?.replicationType === REPLICATION_TYPE.SYNC) { + if (placementControl?.replicationType === ReplicationType.SYNC) { if ( placementControl?.isPrimaryClusterFenced || placementControl?.isTargetClusterFenced @@ -110,8 +110,8 @@ const validatePlacement = ( // Check volume replication health if ( [ - VOLUME_REPLICATION_HEALTH.CRITICAL, - VOLUME_REPLICATION_HEALTH.WARNING, + VolumeReplicationHealth.CRITICAL, + VolumeReplicationHealth.WARNING, ].includes( getReplicationHealth( placementControl?.snapshotTakenTime, @@ -300,7 +300,7 @@ export const FailoverRelocateModalBody: React.FC - {placement?.replicationType === REPLICATION_TYPE.ASYNC && ( + {placement?.replicationType === ReplicationType.ASYNC && ( {t('Volume last synced on:')} @@ -346,7 +346,7 @@ export type PlacementControlProps = Partial<{ isTargetClusterAvailable: boolean; isPrimaryClusterAvailable: boolean; isDRActionReady: boolean; - replicationType: REPLICATION_TYPE; + replicationType: ReplicationType; isTargetClusterFenced: boolean; isPrimaryClusterFenced: boolean; areSiblingApplicationsFound: boolean; diff --git a/packages/mco/components/modals/app-failover-relocate/helper/error-messages.tsx b/packages/mco/components/modals/app-failover-relocate/helper/error-messages.tsx index a97575729..ae08c7017 100644 --- a/packages/mco/components/modals/app-failover-relocate/helper/error-messages.tsx +++ b/packages/mco/components/modals/app-failover-relocate/helper/error-messages.tsx @@ -7,7 +7,7 @@ import { AlertVariant } from '@patternfly/react-core'; export enum ErrorMessageType { // Priority wise error messages - DR_IS_NOT_ENABLED_FAILOVER, + DR_IS_NOT_ENABLED_FAILOVER = 1, DR_IS_NOT_ENABLED_RELOCATE, FAILOVER_READINESS_CHECK_FAILED, RELOCATE_READINESS_CHECK_FAILED, @@ -287,8 +287,8 @@ export const evaluateErrorMessage = ( errorMessage: ErrorMessageType, includeWarning: boolean = false ) => { - if (!includeWarning ? errorMessage < 20 : true) { - return errorMessage; + if (!errorMessage || (!includeWarning && errorMessage >= 20)) { + return -1; } - return -1; + return errorMessage; }; diff --git a/packages/mco/components/modals/app-failover-relocate/subscriptions/failover-relocate-modal.tsx b/packages/mco/components/modals/app-failover-relocate/subscriptions/failover-relocate-modal.tsx index 8ef4a0899..9411323f9 100644 --- a/packages/mco/components/modals/app-failover-relocate/subscriptions/failover-relocate-modal.tsx +++ b/packages/mco/components/modals/app-failover-relocate/subscriptions/failover-relocate-modal.tsx @@ -45,7 +45,7 @@ const generatefooterButtons = (props: ModalFooterProps): FooterButtonProps => ({ type: ButtonType.button, variant: ButtonVariant.primary, isDisabled: props?.isDisable, - onClick: props?.Onclick, + onClick: props?.onClick, }, ], [ModalFooterStatus.INPROGRESS]: [ @@ -195,7 +195,7 @@ export const SubscriptionFailoverRelocateModal: React.FC (