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

Adds Local Volume Set Creation Form and enables LSO Plugin #5014

Merged

Conversation

afreen23
Copy link
Contributor

@afreen23 afreen23 commented Apr 13, 2020

  • Local Volume Set is the new CR to be introduced in Local Storage Operator.
  • Local Volume Set will allow to filter a set of storage volumes, group them and create a dedicated storage class to consume storage for them.

Designs: https://marvelapp.com/8752a03/screen/67632184

Screenshot from 2020-04-09 23-15-59
Screenshot from 2020-04-13 15-31-22
Screenshot from 2020-04-13 13-08-01
Screenshot from 2020-04-14 17-33-20

@openshift-ci-robot openshift-ci-robot added the component/core Related to console core functionality label Apr 13, 2020
@gnehapk
Copy link
Contributor

gnehapk commented Apr 13, 2020

@afreen23 Can you please attach the screenshots too

@afreen23 afreen23 force-pushed the lso-local-volume-set branch 2 times, most recently from 019839b to 50115c9 Compare April 13, 2020 07:03
Comment on lines 34 to 45
const volumeTypeOptions = Object.freeze({
'SSD/NVMe': 'SSD/NVMe',
HDD: 'HDD',
});
const volumeModeOptions = Object.freeze({
Block: 'Block',
Filesystem: 'Filesystem',
});
const volumeSizeUnitOptions = Object.freeze({
TiB: 'TiB',
GiB: 'GiB',
});
Copy link
Contributor

Choose a reason for hiding this comment

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

I would prefer enums.

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 need to keep the plain objects for future fields

GiB: 'GiB',
});

const CreateLocalVolumeSet: React.FC = withHandlePromise((props: CreateLocalVolumeSetProps) => {
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
const CreateLocalVolumeSet: React.FC = withHandlePromise((props: CreateLocalVolumeSetProps) => {
const CreateLocalVolumeSet: React.FC = withHandlePromise<CreateLocalVolumeSetProps>((props) => {

Comment on lines 97 to 99
.catch((e) => {
// eslint-disable-next-line no-console
console.error(e);
Copy link
Contributor

Choose a reason for hiding this comment

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

This is pointless if you're already showing the error in the ActionBar.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure, I think just catch(() -> null) here would be suffice for linter

]}
/>
</div>
<h1 className="co-create-operand__header-text">{`Create ${modelName}`}</h1>
Copy link
Contributor

Choose a reason for hiding this comment

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

<Title>

isRequired
/>
</FormGroup>
<FormGroup label="Storage Class Name" fieldId="create-lvs--storage-class-name">
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this not a required field?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

as per uxd

Comment on lines +150 to +168
<Radio
label="All nodes"
name="nodes-selection"
id="create-lvs--radio-all-nodes"
className="lso-create-lvs__all-nodes-radio--padding"
value="allNodes"
onChange={toggleShowNodesList}
description="Selecting all nodes will search for available volume storage on all nodes."
defaultChecked
/>
<Radio
label="Select nodes"
name="nodes-selection"
id="create-lvs--radio-select-nodes"
value="selectedNodes"
onChange={toggleShowNodesList}
description="Selecting nodes allow you to limit the search for available volumes to specific nodes."
/>
Copy link
Contributor Author

Choose a reason for hiding this comment

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

These are radio groups. Only one of them will be selected at a time.
The value is not significant here.
showNodesList state takes care of toggling

const nodeLocation = node.metadata.labels?.['failure-domain.beta.kubernetes.io/zone'] ?? '-';
const nodeCpuCapacity = getNodeCPUCapacity(node);
const nodeAllocatableMemory = getNodeAllocatableMemory(node);
const nodeTaints = node?.spec?.taints?.length ?? 0;
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
const nodeTaints = node?.spec?.taints?.length ?? 0;
const nodeTaints = node.spec?.taints?.length ?? 0;

};

type SetTableRows = (props: {
componentProps: { data: NodeKind[]; filters: { name: string } };
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
componentProps: { data: NodeKind[]; filters: { name: string } };
componentProps: { data: NodeKind[]; filters: { name: string, labels: { all: string[] } } };

Comment on lines 18 to 48
apiVersion: string;
kind: string;
metadata: { name: string };
spec: {
nodeSelector?: {
nodeSelectorTerms: [
{
matchExpressions: [{ key: string; operator: string; values: string[] }];
},
];
};
Copy link
Contributor

Choose a reason for hiding this comment

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

K8sResourceCommon might handle a few of these fields.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure 👍

Comment on lines +35 to +49
title: 'CPU',
props: { className: tableColumnClasses[1] },
},
{
title: 'Memory',
props: { className: tableColumnClasses[2] },
},
{
title: 'Location',
props: { className: tableColumnClasses[3] },
},
{
title: 'Taints',
props: { className: tableColumnClasses[3] },
},
Copy link
Contributor

Choose a reason for hiding this comment

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

Add sorts for all these fields as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It as per UXD

Copy link
Contributor

Choose a reason for hiding this comment

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

@yuvalgalanti why are we only allowing users to sort on the basis of Name? IMO we should sort on CPU and Memory too.

];
rowUIDMap[uid] = {
cells,
selected: !!rows?.[uid]?.selected,
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
selected: !!rows?.[uid]?.selected,
selected: rows?.[uid]?.selected,

Comment on lines +150 to +168
<Radio
label="All nodes"
name="nodes-selection"
id="create-lvs--radio-all-nodes"
className="lso-create-lvs__all-nodes-radio--padding"
value="allNodes"
onChange={toggleShowNodesList}
description="Selecting all nodes will search for available volume storage on all nodes."
defaultChecked
/>
<Radio
label="Select nodes"
name="nodes-selection"
id="create-lvs--radio-select-nodes"
value="selectedNodes"
onChange={toggleShowNodesList}
description="Selecting nodes allow you to limit the search for available volumes to specific nodes."
/>
Copy link
Contributor Author

Choose a reason for hiding this comment

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

These are radio groups. Only one of them will be selected at a time.
The value is not significant here.
showNodesList state takes care of toggling

.then((resource) => {
history.push(resourceObjPath(resource, referenceFor(resource)));
})
.catch(() => null);
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
.catch(() => null);

No need for the catch statement

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is enforced by linter

Copy link
Contributor

Choose a reason for hiding this comment

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

It's not. handlePromise handles the catch part for you.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Surely handlePromise sets state and error message on catching error but it also returns a promise. Linters are dumb they dont know that, hence I need to put a dummy catch.
This will not break anything in our case because we have error handled in state.

handlePromise: <T>(promise: Promise<T>) => Promise<T>;

<ListPage
customData={{ rows, setRows, allSelected, setAllSelected }}
showTitle={false}
kind="Node"
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
kind="Node"
kind={NodeKind.kind}

Comment on lines 234 to 242
<Button data-test-id="create-lvs-form-create-button" type="submit" variant="primary">
Create
</Button>
<Button
data-test-id="create-lvs-form-cancel-button"
type="button"
variant="secondary"
onClick={onCancel}
>
Copy link
Contributor

Choose a reason for hiding this comment

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

Button's really don't need data-test-id since we have a common class for Primary used throughout the console.

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 added as per your suggestion on chat, will remove again.

setAllSelected: React.Dispatch<React.SetStateAction<boolean>>;
setRows: React.Dispatch<React.SetStateAction<RowUIDMap>>;
};
filters: { name: string };
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
filters: { name: string };

You are not using it here. The type is incomplete.

storageClassName: string;
volumeMode: string;
deviceInclusionSpec: {
deviceTypes: ('RawDisk' | 'Partition')[];
Copy link
Contributor

@bipuladh bipuladh Apr 13, 2020

Choose a reason for hiding this comment

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

Suggested change
deviceTypes: ('RawDisk' | 'Partition')[];
deviceTypes: ('RawDisk' | 'Partition')[];

Please use enum instead of String Literals it's easier to use and understand.

volumeMode: string;
deviceInclusionSpec: {
deviceTypes: ('RawDisk' | 'Partition')[];
deviceMechanicalProperty: ('Rotational' | 'Non Rotational')[];
Copy link
Contributor

Choose a reason for hiding this comment

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

Same as above.

volumeMode,
deviceInclusionSpec: {
// Only Raw disk supported for 4.5
deviceTypes: ['RawDisk'],
Copy link
Contributor

Choose a reason for hiding this comment

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

What is this magic string RawDisk?

Copy link
Contributor Author

@afreen23 afreen23 Apr 13, 2020

Choose a reason for hiding this comment

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

This is hard coded intentionally. The support is for RawDisk only.
Hence, the request data just needs that. No other values are applicable

Copy link
Contributor

Choose a reason for hiding this comment

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

I would prefer it if it came via an enum.

Comment on lines 68 to 69
const [volumeType, setVolumeType] = React.useState('SSD');
const [volumeMode, setVolumeMode] = React.useState('Block');
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider using enums for these values.

Comment on lines 35 to 49
SSD: {
title: 'SSD / NVMe',
property: 'Non Rotational',
},
HDD: {
title: 'HDD',
property: 'Rotational',
},
};

const VOLUME_MODE = {
Block: {
title: 'Block',
},
Filesystem: {
title: 'Filesystem',
},
};
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
SSD: {
title: 'SSD / NVMe',
property: 'Non Rotational',
},
HDD: {
title: 'HDD',
property: 'Rotational',
},
};
const VOLUME_MODE = {
Block: {
title: 'Block',
},
Filesystem: {
title: 'Filesystem',
},
};
enum VolumeType {
SSD = 'SSD',
HDD = 'HDD'
}
[VolumeType.SSD]: {
title: 'SSD / NVMe',
property: 'Non Rotational',
},
[VolumeType.HDD]: {
title: 'HDD',
property: 'Rotational',
},
};
enum VolumeMode {
BLOCK = 'Block',
FS = 'FileSystem'
};
const VOLUME_MODE = {
[VolumeMode.Block]: {
title: 'Block',
},
[VolumeMode.FS]: {
title: 'Filesystem',
},
};

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Surely, I can consider but a bit different .
Thanks!

Comment on lines +102 to +104
handlePromise(k8sCreate(LocalVolumeSetModel, requestData))
.then((resource) => history.push(resourceObjPath(resource, referenceFor(resource))))
.catch(() => null);
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
handlePromise(k8sCreate(LocalVolumeSetModel, requestData))
.then((resource) => history.push(resourceObjPath(resource, referenceFor(resource))))
.catch(() => null);
return handlePromise(k8sCreate(LocalVolumeSetModel, requestData))
.then((resource) => history.push(resourceObjPath(resource, referenceFor(resource))));

Copy link
Contributor

Choose a reason for hiding this comment

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

Or just disable the rule that enforces you to do so.

const [volumeMode, setVolumeMode] = React.useState(volumeModeDropdownItems.Block);
const [maxVolumeLimit, setMaxVolumeLimit] = React.useState('');
const [rows, setRows] = React.useState<RowUIDMap>({});
const [allSelected, setAllSelected] = React.useState(null);
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
const [allSelected, setAllSelected] = React.useState(null);
const [allSelected, setAllSelected] = React.useState<boolean>(null);

@@ -366,6 +366,13 @@ export type TableProps = {
Row?: RowFunction;
Rows?: (...args) => any[];
'aria-label': string;
onSelect?: (
Copy link
Contributor

Choose a reason for hiding this comment

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

you can use OnSelect already defined in @patternfly/react-table

Suggested change
onSelect?: (
onSelect?: OnSelect

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure , I forgot to replace it here.
Thanks!

@rawagner
Copy link
Contributor

/approve

@openshift-ci-robot openshift-ci-robot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Apr 14, 2020
onChange={setVolumeType}
/>
</FormGroup>
<Expandable toggleText="Advanced">
Copy link
Contributor

Choose a reason for hiding this comment

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

Please put a data-test-id on the toggler.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added

type={TextInputTypes.text}
id="create-lvs--storage-class-name"
value={storageClassName}
onChange={setStorageClassName}
Copy link
Contributor

Choose a reason for hiding this comment

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

This would show some errors in the console. onChange send two params whereas setStorageClass only accepts one.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure 👍

- Local Volume Set is the new CR to be introduced in Local Stoarge Operator.
- Local Volume Set will allow to filter a set of storage volumes, group them and create a dedicated storage class to consume storage for them.
@bipuladh
Copy link
Contributor

/lgtm

@openshift-ci-robot openshift-ci-robot added the lgtm Indicates that a PR is ready to be merged. label Apr 14, 2020
@openshift-ci-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: afreen23, bipuladh, rawagner

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-merge-robot openshift-merge-robot merged commit 180113b into openshift:master Apr 14, 2020
@spadgett spadgett added this to the v4.5 milestone Apr 16, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Indicates a PR has been approved by an approver from all required OWNERS files. component/core Related to console core functionality lgtm Indicates that a PR is ready to be merged.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants