Skip to content

Commit

Permalink
(feat): Add OCS kebab actions in the LSO disk inventory related to th…
Browse files Browse the repository at this point in the history
…e day2 operations

 - Adds the disk replacement action
 - Utilizes flag for attached devices cluster (`OCS_ATTACHED_DEVICES`) to enable the OCS kebab actions
Implements https://issues.redhat.com/browse/RHSTOR-1197

Signed-off-by: Afreen Rahman <afrahman@redhat.com>
  • Loading branch information
Afreen Rahman committed Jul 28, 2020
1 parent 71e3cce commit 0c63c1c
Show file tree
Hide file tree
Showing 3 changed files with 182 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import * as React from 'react';
import {
ModalTitle,
ModalBody,
ModalSubmitFooter,
createModalLauncher,
ModalComponentProps,
} from '@console/internal/components/factory';
import {
k8sGet,
k8sCreate,
TemplateKind,
TemplateInstanceKind,
apiVersionForModel,
K8sResourceCommon,
SecretKind,
} from '@console/internal/module/k8s';
import { TemplateModel, TemplateInstanceModel, SecretModel } from '@console/internal/models';
import { CEPH_STORAGE_NAMESPACE } from '../../../constants';

const OSD_REMOVAL_TEMPLATE = 'ocs-osd-removal';

const createTemplateSecret = async (template: TemplateKind, osdId: string) => {
const parametersSecret: TemplateSecret = {
apiVersion: SecretModel.apiVersion,
kind: SecretModel.kind,
metadata: {
name: `${OSD_REMOVAL_TEMPLATE}-parameters`,
namespace: CEPH_STORAGE_NAMESPACE,
},
stringData: {
[template.parameters[0].name]: osdId,
},
};
return k8sCreate(SecretModel, parametersSecret);
};

const createTemplateInstance = async (parametersSecret: TemplateSecret, template: TemplateKind) => {
const templateInstance: TemplateInstanceKind = {
apiVersion: apiVersionForModel(TemplateInstanceModel),
kind: TemplateInstanceModel.kind,
metadata: {
name: `${OSD_REMOVAL_TEMPLATE}-template-instance`,
namespace: CEPH_STORAGE_NAMESPACE,
},
spec: {
secret: {
name: parametersSecret.metadata.name,
},
template,
},
};
return k8sCreate(TemplateInstanceModel, templateInstance);
};

const instantiatetemplate = async (osdId: string) => {
const osdRemovalTemplate = await k8sGet(
TemplateModel,
OSD_REMOVAL_TEMPLATE,
CEPH_STORAGE_NAMESPACE,
);
const templateSecret = await createTemplateSecret(osdRemovalTemplate, osdId);
await createTemplateInstance(templateSecret, osdRemovalTemplate);
};

const DiskReplacementAction = (props: DiskReplacementActionProps) => {
const { diskName, osdId, cancel, close } = props;

const [inProgress, setProgress] = React.useState(false);
const [errorMessage, setError] = React.useState('');

const handleSubmit = (event) => {
event.preventDefault();
setProgress(true);
/*
* TODO:(Afreen) Add validations based on ocs status (part of followup PR)
*/
instantiatetemplate(osdId)
.then(() => {
setProgress(false);
close();
})
.catch((err) => {
setProgress(false);
setError(err.message);
});
};

return (
<form onSubmit={handleSubmit} name="form" className="modal-content">
<ModalTitle>Disk Replacement</ModalTitle>
<ModalBody>
<p>This action will start preparing the disk for replacement.</p>
<p>
Are you sure you want to replace <strong>{diskName}</strong> ?
</p>
</ModalBody>
<ModalSubmitFooter
errorMessage={errorMessage}
inProgress={inProgress}
submitText="Replace"
cancel={cancel}
/>
</form>
);
};

export const diskReplacementModal = createModalLauncher(DiskReplacementAction);

export type DiskReplacementActionProps = {
diskName: string;
osdId: string;
} & ModalComponentProps;

type TemplateSecret = K8sResourceCommon & {
stringData: SecretKind['stringData'];
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import * as React from 'react';
import { TableData } from '@console/internal/components/factory';
import { KebabOption, Kebab } from '@console/internal/components/utils';
import { diskReplacementModal } from './disk-replacement-modal';

const startDiskReplacementAction = (diskName: string, osdId: string): KebabOption => ({
label: 'Start Disk Replacement',
callback: () =>
diskReplacementModal({
diskName,
osdId,
}),
});

export const OCSKebabOptions: React.FC<OCSKebabOptionsProps> = ({ diskName, diskOsdMap }) => {
const osdId: string = diskOsdMap.get(diskName);
const kebabOptions: KebabOption[] = [startDiskReplacementAction(diskName, osdId)];

return (
<TableData className={Kebab.columnClass}>
{/* Disable options for non OCS based disks */}
<Kebab options={kebabOptions} isDisabled={!!osdId} />
</TableData>
);
};

type OCSKebabOptionsProps = { diskName: string; diskOsdMap: Map<string, string> };
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@ import {
MultiListPage,
} from '@console/internal/components/factory';
import { sortable } from '@patternfly/react-table';
import { FirehoseResult, humanizeBinaryBytes } from '@console/internal/components/utils';
import { FirehoseResult, humanizeBinaryBytes, Kebab } from '@console/internal/components/utils';
import { referenceForModel, NodeKind, K8sResourceCommon } from '@console/internal/module/k8s';
import { RowFilter } from '@console/internal/components/filter-toolbar';
import { useFlag } from '@console/shared/src/hooks/flag';
import { OCS_ATTACHED_DEVICES_FLAG } from '@console/ceph-storage-plugin/src/features';
import { OCSKebabOptions } from '@console/ceph-storage-plugin/src/components/attached-devices-mode/lso-disk-inventory/ocs-kebab-options';
import { LocalVolumeDiscoveryResult } from '../../models';
import { LABEL_SELECTOR } from '../../constants/disks-list';

Expand Down Expand Up @@ -45,10 +48,11 @@ export const tableColumnClasses = [
cx('pf-m-hidden', 'pf-m-visible-on-2xl'),
cx('pf-m-hidden', 'pf-m-visible-on-lg'),
cx('pf-m-hidden', 'pf-m-visible-on-xl'),
Kebab.columnClass,
];

const DiskHeader = () => {
return [
const getDiskHeader = (isOCSAttachedDevices: boolean) => {
const headers = [
{
title: 'Name',
sortField: 'path',
Expand Down Expand Up @@ -86,9 +90,26 @@ const DiskHeader = () => {
props: { className: tableColumnClasses[5] },
},
];
if (isOCSAttachedDevices) {
headers.push({
title: '',
sortField: '',
transforms: [],
props: { className: tableColumnClasses[6] },
});
}
return () => headers;
};

const DiskRow: RowFunction<DiskMetadata> = ({ obj, index, key, style }) => {
const diskRow: RowFunction<DiskMetadata, OCSMetadata> = ({
obj,
index,
key,
style,
customData,
}) => {
const { isOCSAttachedDevices, diskOsdMap } = customData;
const diskName = obj.path;
return (
<TableRow id={obj.deviceID} index={index} trKey={key} style={style}>
<TableData className={tableColumnClasses[0]}>{obj.path}</TableData>
Expand All @@ -101,15 +122,18 @@ const DiskRow: RowFunction<DiskMetadata> = ({ obj, index, key, style }) => {
{humanizeBinaryBytes(obj.size).string || '-'}
</TableData>
<TableData className={tableColumnClasses[5]}>{obj.fstype || '-'}</TableData>
{isOCSAttachedDevices && <OCSKebabOptions diskName={diskName} diskOsdMap={diskOsdMap} />}
</TableRow>
);
};

const DisksList: React.FC<TableProps> = (props) => {
return <Table {...props} aria-label="Disks List" Header={DiskHeader} Row={DiskRow} virtualize />;
const diskHeader = getDiskHeader(props.customData.isOCSAttachedDevices);
return <Table {...props} aria-label="Disks List" Header={diskHeader} Row={diskRow} virtualize />;
};

const DisksListPage: React.FC<{ obj: NodeKind }> = (props) => {
const isOCSAttachedDevices = useFlag(OCS_ATTACHED_DEVICES_FLAG);
const nodeName = props.obj.metadata.name;
const propName = `lvdr-${nodeName}`;

Expand All @@ -121,7 +145,7 @@ const DisksListPage: React.FC<{ obj: NodeKind }> = (props) => {
textFilter="node-disk-name"
rowFilters={diskFilters}
flatten={(resource: FirehoseResult<LocalVolumeDiscoveryResult>) =>
resource[propName]?.data[0]?.status?.discoveredDevices ?? {}
resource[propName]?.data[0]?.status?.discoveredDevices ?? []
}
ListComponent={DisksList}
resources={[
Expand All @@ -131,13 +155,21 @@ const DisksListPage: React.FC<{ obj: NodeKind }> = (props) => {
selector: { [LABEL_SELECTOR]: nodeName },
},
]}
customData={{
diskOsdMap: new Map() /* TBD(Afreen) Will be changed to actual state with this https://issues.redhat.com/browse/RHSTOR-1194 */,
isOCSAttachedDevices,
}}
/>
);
};

export default DisksListPage;

type DiskMetadata = LocalVolumeDiscoveryResult['status']['discoveredDevices'];
type OCSMetadata = {
isOCSAttachedDevices: boolean;
diskOsdMap: Map<string, string>;
};

type LocalVolumeDiscoveryResult = K8sResourceCommon & {
spec: {
Expand Down

0 comments on commit 0c63c1c

Please sign in to comment.