Skip to content

Commit

Permalink
Merge pull request #1091 from SanjalKatiyar/rbd_default_sc
Browse files Browse the repository at this point in the history
set RBD as default StorageClass
  • Loading branch information
openshift-merge-bot[bot] authored Nov 10, 2023
2 parents 0db0190 + a97fe7c commit e71d640
Show file tree
Hide file tree
Showing 8 changed files with 237 additions and 35 deletions.
4 changes: 4 additions & 0 deletions locales/en/plugin__odf-console.json
Original file line number Diff line number Diff line change
Expand Up @@ -622,6 +622,8 @@
"Deploys MultiCloud Object Gateway without block and file services.": "Deploys MultiCloud Object Gateway without block and file services.",
"Deploys Data Foundation with block, shared fileSystem and object services.": "Deploys Data Foundation with block, shared fileSystem and object services.",
"Deployment type": "Deployment type",
"Set Ceph RBD as the default StorageClass": "Set Ceph RBD as the default StorageClass",
"Configure a default RBD StorageClass to eliminate manual annotations within a StorageClass or selecting a specific StorageClass when making storage requests or provisions in your PVCs.": "Configure a default RBD StorageClass to eliminate manual annotations within a StorageClass or selecting a specific StorageClass when making storage requests or provisions in your PVCs.",
"If not labeled, the selected nodes are labeled <2>{{label}}</2> to make them target hosts for Data Foundation's components.": "If not labeled, the selected nodes are labeled <2>{{label}}</2> to make them target hosts for Data Foundation's components.",
"Taint nodes": "Taint nodes",
"Selected nodes will be dedicated to Data Foundation use only": "Selected nodes will be dedicated to Data Foundation use only",
Expand Down Expand Up @@ -701,10 +703,12 @@
"{{displayName}} connection details": "{{displayName}} connection details",
"Prepare cluster for disaster recovery (Regional-DR only)": "Prepare cluster for disaster recovery (Regional-DR only)",
"Set up the storage system for disaster recovery service with the essential configurations in place. This will subsequently allows seamless implementation of the disaster recovery strategies for your workloads.": "Set up the storage system for disaster recovery service with the essential configurations in place. This will subsequently allows seamless implementation of the disaster recovery strategies for your workloads.",
"No": "No",
"Not connected": "Not connected",
"Backing storage": "Backing storage",
"Deployment type: {{deployment}}": "Deployment type: {{deployment}}",
"Network file system: {{nfsStatus}}": "Network file system: {{nfsStatus}}",
"Set Ceph RBD as the default StorageClass: {{isCephRBDSetAsDefault}}": "Set Ceph RBD as the default StorageClass: {{isCephRBDSetAsDefault}}",
"Backing storage type: {{name}}": "Backing storage type: {{name}}",
"External storage platform: {{storagePlatform}}": "External storage platform: {{storagePlatform}}",
"Capacity and nodes": "Capacity and nodes",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import { ErrorHandler } from '../../error-handler';
import { WizardState, WizardDispatch } from '../../reducer';
import { EnableNFS } from './enable-nfs';
import { SelectDeployment } from './select-deployment';
import { SetCephRBDStorageClassDefault } from './set-rbd-sc-default';
import './backing-storage-step.scss';

const RHCS_SUPPORTED_INFRA = [
Expand Down Expand Up @@ -181,7 +182,13 @@ export const BackingStorage: React.FC<BackingStorageProps> = ({
stepIdReached,
supportedExternalStorage,
}) => {
const { type, enableNFS, externalStorage, deployment } = state;
const {
type,
enableNFS,
isRBDStorageClassDefault,
externalStorage,
deployment,
} = state;

const { t } = useCustomTranslation();
const [sc, scLoaded, scLoadError] =
Expand Down Expand Up @@ -263,6 +270,10 @@ export const BackingStorage: React.FC<BackingStorageProps> = ({
dispatch({ type: 'backingStorage/setType', payload: newType });
};

const doesDefaultSCAlreadyExists = sc?.items?.some((item) =>
isDefaultClass(item)
);

return (
<ErrorHandler
error={error || scLoadError || csvListLoadError}
Expand Down Expand Up @@ -335,11 +346,18 @@ export const BackingStorage: React.FC<BackingStorageProps> = ({
/>
</FormGroup>
{isFullDeployment && !hasOCS && (
<EnableNFS
dispatch={dispatch}
nfsEnabled={enableNFS}
backingStorageType={type}
/>
<>
<EnableNFS
dispatch={dispatch}
nfsEnabled={enableNFS}
backingStorageType={type}
/>
<SetCephRBDStorageClassDefault
dispatch={dispatch}
isRBDStorageClassDefault={isRBDStorageClassDefault}
doesDefaultSCAlreadyExists={doesDefaultSCAlreadyExists}
/>
</>
)}
</Form>
</ErrorHandler>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import * as React from 'react';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { SetCephRBDStorageClassDefault } from './set-rbd-sc-default';

describe('Setting Ceph RBD StorageClass as default, during installation', () => {
it('renders the FC, on infra with existing default StorageClass', async () => {
const uEvent = userEvent.setup();
const Wrapper = () => {
const [isRBDStorageClassDefault, dispatch] = React.useState(false);
const dispatchWrapper = ({ payload }) => dispatch(payload);
return (
<SetCephRBDStorageClassDefault
doesDefaultSCAlreadyExists={true}
isRBDStorageClassDefault={isRBDStorageClassDefault}
dispatch={dispatchWrapper}
/>
);
};

const { container, rerender } = render(<Wrapper />);
const checkbox = container.querySelector(
'[data-test="set-rbd-sc-default"]'
) as HTMLInputElement;

expect(
screen.getByText('Set Ceph RBD as the default StorageClass')
).toBeInTheDocument();

// by defaut checkbox should not be checked
expect(checkbox.checked).toBe(false);

// on clicking, checkbox should get checked
await uEvent.click(checkbox);
expect(checkbox.checked).toBe(true);

// re-render should not change the checkbox state
rerender(<Wrapper />);
expect(checkbox.checked).toBe(true);
});

it('renders the FC, on infra with non-existing default StorageClass', async () => {
const uEvent = userEvent.setup();
const Wrapper = () => {
const [isRBDStorageClassDefault, dispatch] = React.useState(false);
const dispatchWrapper = ({ payload }) => dispatch(payload);
return (
<SetCephRBDStorageClassDefault
doesDefaultSCAlreadyExists={false}
isRBDStorageClassDefault={isRBDStorageClassDefault}
dispatch={dispatchWrapper}
/>
);
};

const { container, rerender } = render(<Wrapper />);
const checkbox = container.querySelector(
'[data-test="set-rbd-sc-default"]'
) as HTMLInputElement;

expect(
screen.getByText('Set Ceph RBD as the default StorageClass')
).toBeInTheDocument();

// by defaut checkbox should be checked
expect(checkbox.checked).toBe(true);

// on clicking, checkbox should get un-checked
await uEvent.click(checkbox);
expect(checkbox.checked).toBe(false);

// re-render should not change the checkbox state
rerender(<Wrapper />);
expect(checkbox.checked).toBe(false);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import * as React from 'react';
import { useCustomTranslation } from '@odf/shared/useCustomTranslationHook';
import { FormGroup, Checkbox } from '@patternfly/react-core';
import { WizardDispatch, WizardState } from '../../reducer';
import './backing-storage-step.scss';

export const SetCephRBDStorageClassDefault: React.FC<SetCephRBDStorageClassDefaultProps> =
({ dispatch, isRBDStorageClassDefault, doesDefaultSCAlreadyExists }) => {
const { t } = useCustomTranslation();

// for infra with already existing "default" SC (eg: say gp3-csi): option should be default unchecked.
// for infra with no "default" SC (BM here): option should be default checked.
React.useEffect(() => {
if (!doesDefaultSCAlreadyExists) {
dispatch({
type: 'backingStorage/setIsRBDStorageClassDefault',
payload: true,
});
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

return (
<FormGroup>
<Checkbox
id="set-rbd-sc-default"
data-test="set-rbd-sc-default"
label={t('Set Ceph RBD as the default StorageClass')}
description={t(
'Configure a default RBD StorageClass to eliminate manual annotations within a StorageClass or selecting a specific StorageClass when making storage requests or provisions in your PVCs.'
)}
isChecked={isRBDStorageClassDefault}
onChange={() =>
dispatch({
type: 'backingStorage/setIsRBDStorageClassDefault',
payload: !isRBDStorageClassDefault,
})
}
className="odf-backing-store__radio--margin-bottom"
/>
</FormGroup>
);
};

type SetCephRBDStorageClassDefaultProps = {
dispatch: WizardDispatch;
isRBDStorageClassDefault: WizardState['backingStorage']['isRBDStorageClassDefault'];
doesDefaultSCAlreadyExists: boolean;
};
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,13 @@ export const ReviewAndCreate: React.FC<ReviewAndCreateProps> = ({
enableSingleReplicaPool,
} = capacityAndNodes;
const { encryption, kms, networkType } = securityAndNetwork;
const { deployment, externalStorage, type, enableNFS } = backingStorage;
const {
deployment,
externalStorage,
type,
enableNFS,
isRBDStorageClassDefault,
} = backingStorage;

// NooBaa standalone deployment
const isMCG = deployment === DeploymentType.MCG;
Expand Down Expand Up @@ -93,6 +99,7 @@ export const ReviewAndCreate: React.FC<ReviewAndCreateProps> = ({
? t('Enabled')
: t('Disabled');
const nfsStatus = enableNFS ? t('Enabled') : t('Disabled');
const isCephRBDSetAsDefault = isRBDStorageClassDefault ? t('Yes') : t('No');

const kmsStatus = encryption.advanced
? kms.providerState.name.value
Expand Down Expand Up @@ -123,6 +130,16 @@ export const ReviewAndCreate: React.FC<ReviewAndCreateProps> = ({
})}
</ListItem>
)}
{deployment === DeploymentType.FULL && !hasOCS && (
<ListItem>
{t(
'Set Ceph RBD as the default StorageClass: {{isCephRBDSetAsDefault}}',
{
isCephRBDSetAsDefault,
}
)}
</ListItem>
)}
{!isRhcs && (
<ListItem>
{t('Backing storage type: {{name}}', {
Expand Down
25 changes: 15 additions & 10 deletions packages/odf/components/create-storage-system/payloads.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ export const createStorageCluster = async (state: WizardState) => {
enableSingleReplicaPool,
} = capacityAndNodes;
const { encryption, publicNetwork, clusterNetwork, kms } = securityAndNetwork;
const { type, enableNFS, deployment } = backingStorage;
const { type, enableNFS, isRBDStorageClassDefault, deployment } =
backingStorage;
const { enableRDRPreparation } = dataProtection;

const isNoProvisioner = storageClass?.provisioner === NO_PROVISIONER;
Expand All @@ -88,24 +89,28 @@ export const createStorageCluster = async (state: WizardState) => {
deployment === DeploymentType.FULL &&
type !== BackingStorageType.EXTERNAL;

const payload = getOCSRequestData(
const shouldSetCephRBDAsDefault =
isRBDStorageClassDefault && deployment === DeploymentType.FULL;

const payload = getOCSRequestData({
storageClass,
storage,
encryption,
isMinimal,
nodes,
isFlexibleScaling,
flexibleScaling: isFlexibleScaling,
publicNetwork,
clusterNetwork,
kms.providerState.hasHandled && encryption.advanced,
arbiterLocation,
enableArbiter,
pvCount,
kmsEnable: kms.providerState.hasHandled && encryption.advanced,
selectedArbiterZone: arbiterLocation,
stretchClusterChecked: enableArbiter,
availablePvsCount: pvCount,
isMCG,
isNFSEnabled,
enableSingleReplicaPool,
enableRDRPreparation
);
shouldSetCephRBDAsDefault,
isSingleReplicaPoolEnabled: enableSingleReplicaPool,
enableRDRPreparation,
});
return k8sCreate({ model: OCSStorageClusterModel, data: payload });
};

Expand Down
11 changes: 11 additions & 0 deletions packages/odf/components/create-storage-system/reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export const initialState: CreateStorageSystemState = {
backingStorage: {
type: BackingStorageType.EXISTING,
enableNFS: false,
isRBDStorageClassDefault: false,
externalStorage: '',
deployment: DeploymentType.FULL,
},
Expand Down Expand Up @@ -92,6 +93,7 @@ type CreateStorageSystemState = {
backingStorage: {
type: BackingStorageType;
enableNFS: boolean;
isRBDStorageClassDefault: boolean;
externalStorage: string;
deployment: DeploymentType;
};
Expand Down Expand Up @@ -174,6 +176,8 @@ const setDeployment = (state: WizardState, deploymentType: DeploymentType) => {

state.backingStorage.deployment = deploymentType;
state.backingStorage.enableNFS = initialState.backingStorage.enableNFS;
state.backingStorage.isRBDStorageClassDefault =
initialState.backingStorage.isRBDStorageClassDefault;
return state;
};

Expand Down Expand Up @@ -260,6 +264,9 @@ export const reducer: WizardReducer = (prevState, action) => {
case 'backingStorage/enableNFS':
newState.backingStorage.enableNFS = action.payload;
break;
case 'backingStorage/setIsRBDStorageClassDefault':
newState.backingStorage.isRBDStorageClassDefault = action.payload;
break;
case 'backingStorage/setDeployment':
return setDeployment(newState, action.payload);
case 'backingStorage/setExternalStorage':
Expand Down Expand Up @@ -352,6 +359,10 @@ export type CreateStorageSystemAction =
type: 'backingStorage/enableNFS';
payload: WizardState['backingStorage']['enableNFS'];
}
| {
type: 'backingStorage/setIsRBDStorageClassDefault';
payload: WizardState['backingStorage']['isRBDStorageClassDefault'];
}
| {
type: 'backingStorage/setExternalStorage';
payload: WizardState['backingStorage']['externalStorage'];
Expand Down
Loading

0 comments on commit e71d640

Please sign in to comment.