Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(feat): Setup create storage system wizard #9438

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
62 changes: 47 additions & 15 deletions frontend/packages/ceph-storage-plugin/console-extensions.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,53 +4,75 @@
"properties": {
"alert": "CephOSDDiskUnavailable",
"text": "%ceph-storage-plugin~Troubleshoot%",
"action": { "$codeRef": "alert.getAlertActionPath" }
"action": {
"$codeRef": "alert.getAlertActionPath"
}
},
"flags": {
"required": ["LSO_DEVICE_DISCOVERY", "OCS_ATTACHED_DEVICES"]
"required": [
"LSO_DEVICE_DISCOVERY",
"OCS_ATTACHED_DEVICES"
]
}
},
{
"type": "console.alert-action",
"properties": {
"alert": "CephOSDDiskNotResponding",
"text": "%ceph-storage-plugin~Troubleshoot%",
"action": { "$codeRef": "alert.getAlertActionPath" }
"action": {
"$codeRef": "alert.getAlertActionPath"
}
},
"flags": {
"required": ["LSO_DEVICE_DISCOVERY", "OCS_ATTACHED_DEVICES"]
"required": [
"LSO_DEVICE_DISCOVERY",
"OCS_ATTACHED_DEVICES"
]
}
},
{
"type": "console.alert-action",
"properties": {
"alert": "CephClusterNearFull",
"text": "%ceph-storage-plugin~Add Capacity%",
"action": { "$codeRef": "alert.launchClusterExpansionModal" }
"action": {
"$codeRef": "alert.launchClusterExpansionModal"
}
},
"flags": {
"required": ["OCS"]
"required": [
"OCS"
]
}
},
{
"type": "console.alert-action",
"properties": {
"alert": "CephClusterCriticallyFull",
"text": "%ceph-storage-plugin~Add Capacity%",
"action": { "$codeRef": "alert.launchClusterExpansionModal" }
"action": {
"$codeRef": "alert.launchClusterExpansionModal"
}
},
"flags": {
"required": ["OCS"]
"required": [
"OCS"
]
}
},
{
"type": "console.storage-provider",
"properties": {
"name": "ObjectBucketClaim",
"Component": { "$codeRef": "storageProvider" }
"Component": {
"$codeRef": "storageProvider"
}
},
"flags": {
"required": ["OCS"]
"required": [
"OCS"
]
}
},
{
Expand All @@ -66,7 +88,9 @@
}
},
"flags": {
"required": ["MCG"]
"required": [
"MCG"
]
}
},
{
Expand All @@ -82,7 +106,9 @@
}
},
"flags": {
"required": ["MCG"]
"required": [
"MCG"
]
}
},
{
Expand All @@ -95,7 +121,9 @@
"href": "/ocs-dashboards"
},
"flags": {
"required": ["OCS"]
"required": [
"OCS"
]
}
},
{
Expand All @@ -108,8 +136,12 @@
"href": "/ocs-dashboards"
},
"flags": {
"required": ["MCG"],
"disallowed": ["OCS"]
"required": [
"MCG"
],
"disallowed": [
"OCS"
]
}
}
]
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,24 @@
"Name can contain a max of 43 characters": "Name can contain a max of 43 characters",
"Provider": "Provider",
"Create BackingStore": "Create BackingStore",
"Select external system from list": "Select external system from list",
"Use an existing storage class": "Use an existing storage class",
"Can be used on all platforms except BareMetal. OpenShift Data Foundation will use an infrastructure storage class provided by the hosting platform.": "Can be used on all platforms except BareMetal. OpenShift Data Foundation will use an infrastructure storage class provided by the hosting platform.",
"Create a new storage class using local devices": "Create a new storage class using local devices",
"Can be used on any platform having nodes with local devices. The infrastructure storage class is provided by Local Storage Operator on top of the local devices.": "Can be used on any platform having nodes with local devices. The infrastructure storage class is provided by Local Storage Operator on top of the local devices.",
"Connect a new external storage system": "Connect a new external storage system",
"Can be used to connect an external storage platform to OpenShift Data Foundation.": "Can be used to connect an external storage platform to OpenShift Data Foundation.",
"Capacity and nodes": "Capacity and nodes",
"Security and network": "Security and network",
"Review and create": "Review and create",
"Connection details": "Connection details",
"Create storage class": "Create storage class",
afreen23 marked this conversation as resolved.
Show resolved Hide resolved
"Create local volume set": "Create local volume set",
afreen23 marked this conversation as resolved.
Show resolved Hide resolved
"Backing storage": "Backing storage",
"An error has occurred: {{error}}": "An error has occurred: {{error}}",
"An error has occurred": "An error has occurred",
"Create StorageSystem": "Create StorageSystem",
"StorageSystem is an entity of OpenShift Data Foundation. It represents all of the required storage and compute resources.": "StorageSystem is an entity of OpenShift Data Foundation. It represents all of the required storage and compute resources.",
"Not available": "Not available",
"Not enough usage data": "Not enough usage data",
"used": "used",
Expand Down Expand Up @@ -422,9 +440,6 @@
"Encryption Level: {{level}}": "Encryption Level: {{level}}",
"Using {{networkLabel}}": "Using {{networkLabel}}",
"Discover disks": "Discover disks",
"Capacity and nodes": "Capacity and nodes",
"Security and network": "Security and network",
"Review and create": "Review and create",
"Internal - Attached devices": "Internal - Attached devices",
"Can be used on any platform where there are attached devices to the nodes, using the Local Storage Operator. The infrastructure StorageClass is provided by Local Storage Operator, on top of the attached drives.": "Can be used on any platform where there are attached devices to the nodes, using the Local Storage Operator. The infrastructure StorageClass is provided by Local Storage Operator, on top of the attached drives.",
"Local Storage Operator not installed": "Local Storage Operator not installed",
Expand Down Expand Up @@ -508,7 +523,6 @@
"Storage pool into which volume data shall be stored": "Storage pool into which volume data shall be stored",
"Error retrieving Parameters": "Error retrieving Parameters",
"my-storage-pool": "my-storage-pool",
"Connection details": "Connection details",
"Change connection details": "Change connection details",
"Vault Enterprise Namespace:": "Vault Enterprise Namespace:",
"Key management service name:": "Key management service name:",
Expand Down
5 changes: 3 additions & 2 deletions frontend/packages/ceph-storage-plugin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@
]
},
"exposedModules": {
"alert": "./src/utils/alert-action-path.tsx",
"storageProvider": "./src/components/attach-obc/attach-obc-deployment.tsx"
"alert": "src/utils/alert-action-path.tsx",
"storageProvider": "src/components/attach-obc/attach-obc-deployment.tsx",
"createStorageSystem": "src/components/create-storage-system/create-storage-system.tsx"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.odf-backing-storage__selection--width {
width: 22rem;
afreen23 marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
import * as React from 'react';

import { useTranslation } from 'react-i18next';
import { Form, FormSelect, FormSelectOption, FormSelectProps, Radio } from '@patternfly/react-core';
import { StorageClassDropdown } from '@console/internal/components/utils/storage-class-dropdown';
import { StorageClassResourceKind } from '@console/internal/module/k8s';
import './backing-storage.scss';
import { ExternalProvider } from 'packages/ceph-storage-plugin/src/odf-external-providers/types';
import { ODF_EXTERNAL_PROVIDERS } from '../../../../odf-external-providers/external-providers';
import { StorageSystemKind } from '../../../../types';
import { filterSCWithoutNoProv } from '../../../../utils/install';
import { WizardReducer, WizardState, WizardDispatch } from '../../reducer';
import {
BackingStorageType,
RHCS,
StorageClusterIdentifier,
} from '../../../../constants/create-storage-system';
import { ErrorHandler } from '../../error-handler';

const ExternalSystemSelection: React.FC<ExternalSystemSelectionProps> = ({
dispatch,
providersList,
selectedProvider,
hasOCS,
}) => {
const { t } = useTranslation();
const handleSelection: FormSelectProps['onChange'] = (value: string) =>
dispatch({
type: 'backingStorage/setExternalProvider',
payload: value,
});

return (
<FormSelect
aria-label={t('ceph-storage-plugin~Select external system from list')}
value={selectedProvider}
className="odf-backing-storage__selection--width"
afreen23 marked this conversation as resolved.
Show resolved Hide resolved
onChange={handleSelection}
>
{hasOCS && <FormSelectOption key={RHCS} value={RHCS} label="Red Hat Ceph Storage" />}
{providersList.map((p) => (
<FormSelectOption key={p.id} value={p.id} label={p.label} />
))}
</FormSelect>
);
};

type ExternalSystemSelectionProps = {
dispatch: React.Dispatch<React.ReducerAction<WizardReducer>>;
selectedProvider: WizardState['backingStorage']['externalProvider'];
providersList: ExternalProvider[];
hasOCS: boolean;
};

const StorageClassSelection: React.FC<StorageClassSelectionProps> = ({ dispatch, selected }) => {
const onStorageClassSelect = (sc: StorageClassResourceKind) =>
dispatch({
type: 'wizard/setStorageClass',
payload: { name: sc?.metadata?.name, provisioner: sc?.provisioner },
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
payload: { name: sc?.metadata?.name, provisioner: sc?.provisioner },
payload: { name: sc.metadata.name, provisioner: sc.provisioner },

These are always defined, right? If a user selects a storage class then the object is present.

Copy link
Contributor Author

@afreen23 afreen23 Jul 14, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really, there is an option for no default storage/ no stoarge class class which is an empty object.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think in that case as well the sc.provisioner will be added after figuring out the default storage class from the backend.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant no storage class, updated!

Copy link
Contributor Author

@afreen23 afreen23 Jul 14, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Y'all can check @vbnrh 's comment, he posted the error as well.
#9438 (comment)

});
return (
<div className="odf-backing-storage__selection--width">
<StorageClassDropdown
noSelection
afreen23 marked this conversation as resolved.
Show resolved Hide resolved
onChange={onStorageClassSelect}
selectedKey={selected.name}
filter={filterSCWithoutNoProv}
data-test="storage-class-dropdown"
afreen23 marked this conversation as resolved.
Show resolved Hide resolved
/>
</div>
);
};

type StorageClassSelectionProps = {
dispatch: WizardDispatch;
selected: WizardState['storageClass'];
};

const formatStorageSystemList = (storageSystems: StorageSystemKind[] = []): StorageSystemSet =>
storageSystems.reduce(
(kinds: StorageSystemSet, ss: StorageSystemKind) => kinds.add(ss.spec.kind),
new Set(),
);

type StorageSystemSet = Set<StorageSystemKind['spec']['kind']>;

export const BackingStorage: React.FC<BackingStorageProps> = ({
state,
dispatch,
storageSystems,
storageClass,
error,
loaded,
}) => {
const { t } = useTranslation();

const formattedSS: StorageSystemSet = formatStorageSystemList(storageSystems);

afreen23 marked this conversation as resolved.
Show resolved Hide resolved
const hasOCS: boolean = formattedSS.has(StorageClusterIdentifier);

const externalProviders = ODF_EXTERNAL_PROVIDERS.filter(
(provider) => !formattedSS.has(provider.kind),
);

React.useEffect(() => {
/*
Allow pre selecting the "external connection" option instead of the "existing" option
if an OCS Storage System is already created and no external system is created.
*/
if (hasOCS && externalProviders.length) {
dispatch({ type: 'backingStorage/setType', payload: BackingStorageType.EXTERNAL });
}
}, [dispatch, externalProviders.length, hasOCS]);

const { type, externalProvider } = state;

const showExternalSystemSelection = type === BackingStorageType.EXTERNAL;
const showStorageClassSelection = !hasOCS && type === BackingStorageType.EXISTING;
const RADIO_GROUP_NAME = 'backing-storage-radio-group';
afreen23 marked this conversation as resolved.
Show resolved Hide resolved

const onRadioSelect = (_, event) => {
dispatch({ type: 'backingStorage/setType', payload: event.target.value });
dispatch({
type: 'currentStep/resetCount',
});
};

return (
<ErrorHandler error={error} loaded={loaded}>
<Form>
<Radio
label={t('ceph-storage-plugin~Use an existing storage class')}
description={t(
'ceph-storage-plugin~Can be used on all platforms except BareMetal. OpenShift Data Foundation will use an infrastructure storage class provided by the hosting platform.',
)}
name={RADIO_GROUP_NAME}
value={BackingStorageType.EXISTING}
isChecked={type === BackingStorageType.EXISTING}
onChange={onRadioSelect}
isDisabled={hasOCS}
body={
showStorageClassSelection && (
<StorageClassSelection dispatch={dispatch} selected={storageClass} />
)
}
id={`bs-${BackingStorageType.EXISTING}`}
/>
<Radio
label={t('ceph-storage-plugin~Create a new storage class using local devices')}
description={t(
'ceph-storage-plugin~Can be used on any platform having nodes with local devices. The infrastructure storage class is provided by Local Storage Operator on top of the local devices.',
)}
name={RADIO_GROUP_NAME}
value={BackingStorageType.LOCAL_DEVICES}
isChecked={type === BackingStorageType.LOCAL_DEVICES}
onChange={onRadioSelect}
isDisabled={hasOCS}
id={`bs-${BackingStorageType.LOCAL_DEVICES}`}
/>
<Radio
label={t('ceph-storage-plugin~Connect a new external storage system')}
description={t(
'ceph-storage-plugin~Can be used to connect an external storage platform to OpenShift Data Foundation.',
)}
name={RADIO_GROUP_NAME}
value={BackingStorageType.EXTERNAL}
isChecked={type === BackingStorageType.EXTERNAL}
onChange={onRadioSelect}
isDisabled={externalProviders.length === 0}
body={
showExternalSystemSelection && (
<ExternalSystemSelection
selectedProvider={externalProvider}
dispatch={dispatch}
providersList={externalProviders}
hasOCS={hasOCS}
/>
)
}
id={`bs-${BackingStorageType.EXTERNAL}`}
/>
</Form>
</ErrorHandler>
);
};

type BackingStorageProps = {
dispatch: WizardDispatch;
state: WizardState['backingStorage'];
storageSystems: StorageSystemKind[];
storageClass: WizardState['storageClass'];
error: any;
loaded: boolean;
};