Skip to content

Commit

Permalink
Snapshot code cleanup
Browse files Browse the repository at this point in the history
Fixes: https://issues.redhat.com/browse/RHSTOR-1057
Signed-off-by: Kanika <kmurarka@redhat.com>
  • Loading branch information
Kanika committed Apr 29, 2020
1 parent 57b271b commit e4ee7e6
Show file tree
Hide file tree
Showing 7 changed files with 38 additions and 271 deletions.
Expand Up @@ -46,7 +46,7 @@ describe(VolumeSnapshotModal.name, () => {

it('renders a modal with placeholder name', () => {
expect(wrapper.find(TextInput).exists()).toBe(true);
expect(wrapper.find(TextInput).props().placeholder).toEqual('fake-pvc-snapshot');
expect(wrapper.find(TextInput).props().value).toEqual('fake-pvc-snapshot');
});

it('check for required field', () => {
Expand Down
Expand Up @@ -55,7 +55,7 @@ describe('<VolumeSnapshotList>', () => {
});

it('should render the proper Headers in the Resources tab', () => {
const expectedHeader: string[] = ['Name', 'Date', 'Status', 'Size', 'Labels'];
const expectedHeader: string[] = ['Name', 'Date', 'Status', 'Size'];

const headers = wrapper
.find(Table)
Expand Down
Expand Up @@ -3,32 +3,3 @@
display: grid;
margin-right: var(--pf-global--spacer--md) !important;
}

.ceph-volume-snapshot-modal__input--count {
width: fit-content;
}

.ceph-volume-snapshot-modal__input--inline {
display: inline-flex;
}

.ceph-volume-snapshot-modal__input--group {
display: grid;
}

.ceph-volume-snapshot-modal__input--keep {
display: inline-flex;
}

.ceph-volume-snapshot-modal__input--link {
padding-left: var(--pf-global--spacer--2xl);
}

.ceph-volume-snapshot-modal__label {
width: fit-content !important;
}

.ceph-volume-snapshot-modal__span--keep {
font-size: var(--pf-global--FontSize--md);
padding: var(--pf-global--spacer--xs);
}
Expand Up @@ -2,31 +2,25 @@ import * as React from 'react';

import {
Dropdown,
ExternalLink,
Firehose,
FirehoseResourcesResult,
HandlePromiseProps,
withHandlePromise,
} from '@console/internal/components/utils';
import { Form, FormGroup, TextInput } from '@patternfly/react-core';
import {
K8sResourceKind,
apiVersionForModel,
k8sCreate,
k8sPatch,
} from '@console/internal/module/k8s';
import { getName, getNamespace } from '@console/shared';
import { K8sResourceKind, k8sCreate } from '@console/internal/module/k8s';
import {
ModalBody,
ModalComponentProps,
ModalSubmitFooter,
ModalTitle,
createModalLauncher,
} from '@console/internal/components/factory';
import { SnapshotScheduleModel, VolumeSnapshotModel } from '../../../models';
import { cronLink, numberOfSnapshot, snapshotTypes } from './volume-snapshot';
import { getName, getNamespace } from '@console/shared';

import { PersistentVolumeClaimModel } from '@console/internal/models';
import { VolumeSnapshotModel } from '../../../models';
import { snapshotTypes } from './volume-snapshot';

import './_volume-snapshot-modal.scss';

export type VolumeSnapshotModalProps = {
Expand All @@ -37,195 +31,29 @@ export type VolumeSnapshotModalProps = {
export const VolumeSnapshotModal = withHandlePromise((props: VolumeSnapshotModalProps) => {
const { close, cancel, pvcData, errorMessage, inProgress, handlePromise } = props;
const resource = pvcData.data as K8sResourceKind;
const [snapshotCount, setSnapshotCount] = React.useState(3); // For all schedules
const [snapshotWeek, setSnapshotWeek] = React.useState(0); // For Weekly schedule
const [snapshotTime, setSnapshotTime] = React.useState('00:01'); // For weekly and monthly
const [snapshotMonth, setSnapshotMonth] = React.useState(1); // For monthly schedule
const [snapshotName, setSnapshotName] = React.useState<string>();
const [scheduleLabel, setScheduleLabel] = React.useState<string>();
const [scheduleType, setScheduleType] = React.useState(snapshotTypes.Single);

const makeLabel = (): string => {
const arr = snapshotTime.split(':');
const newLabel = `${arr?.[1]} ${arr?.[0]}`;
if (scheduleType === snapshotTypes.Monthly) {
return `${newLabel} ${snapshotMonth} * *`;
}
if (scheduleType === snapshotTypes.Weekly) {
return `${newLabel} * * ${snapshotWeek}`;
}
return newLabel;
};

const WeeklyElements: React.FC = () => (
<FormGroup
className="ceph-volume-snapshot-modal__input"
fieldId="snapshot-day"
label="Day of week"
>
<TextInput
type="number"
value={snapshotWeek}
onChange={(value) => setSnapshotWeek(Number(value))}
className="ceph-volume-snapshot-modal--label"
aria-labelledby="snapshot-day"
/>
</FormGroup>
);

const MonthlyElements: React.FC = () => (
<FormGroup
className="ceph-volume-snapshot-modal__input"
fieldId="snapshot-month"
label="Day of month"
>
<TextInput
type="number"
name="snapshot-modal__month"
value={snapshotMonth}
onChange={(value) => setSnapshotMonth(Number(value))}
className="ceph-volume-snapshot-modal__label"
aria-labelledby="snapshot-month"
/>
</FormGroup>
);

const CronElements: React.FC = () => (
<FormGroup
className="ceph-volume-snapshot-modal__input"
fieldId="snapshot-schedule"
helperText="* Scheduled for cluster local time"
isRequired
>
<label className="pf-c-form__label" htmlFor="snapshot-modal__schedule">
<span className="pf-c-form__label-text">Label</span>
<ExternalLink
additionalClassName="ceph-volume-snapshot-modal__input--link"
href={cronLink}
text="Whats this?"
/>
</label>
<TextInput
type="text"
name="snapshot-modal__schedule"
value={scheduleLabel}
onChange={(value) => setScheduleLabel(value)}
className="ceph-volume-snapshot-modal__label"
placeholder="* * 5 * *"
aria-labelledby="snapshot-schedule"
/>
</FormGroup>
);

const OtherElements: React.FC = () => (
<div className="ceph-volume-snapshot-modal__input--inline">
{scheduleType === snapshotTypes.Monthly ? <MonthlyElements /> : <WeeklyElements />}
<FormGroup className="ceph-volume-snapshot-modal__input" fieldId="snapshot-time" label="Time">
<TextInput
type="time"
name="snapshot-modal__time-week"
value={snapshotTime}
onChange={setSnapshotTime}
className="ceph-volume-snapshot-modal__label"
aria-labelledby="snapshot-time"
/>
</FormGroup>
</div>
);

const ScheduleElements: React.FC = () => (
<Form>
{scheduleType === snapshotTypes.CronJob ? <CronElements /> : <OtherElements />}
<FormGroup
className="ceph-volume-snapshot-modal__input--group"
label="Keep"
fieldId="snapshot-count"
helperText="*Older snapshots will be deleted automatically"
isRequired
>
<div className="ceph-volume-snapshot-modal__input--keep">
<Dropdown
items={numberOfSnapshot}
selectedKey={snapshotCount}
onChange={(value) => setSnapshotCount(Number(value))}
className="ceph-volume-snapshot-modal__input--count"
/>
<span className="ceph-volume-snapshot-modal__span--keep">last snapshots</span>
</div>
</FormGroup>
</Form>
const [snapshotName, setSnapshotName] = React.useState<string>(
`${getName(resource) || 'pvc'}-snapshot`,
);
const [scheduleType, setScheduleType] = React.useState(snapshotTypes.Single);

const submit = (event: React.FormEvent<EventTarget>) => {
event.preventDefault();
const ns = getNamespace(resource);
const pvcName = getName(resource);
if (scheduleType === snapshotTypes.Single) {
const snapshotTemplate: K8sResourceKind = {
apiVersion: VolumeSnapshotModel.apiVersion,
kind: VolumeSnapshotModel.kind,
metadata: {
name: snapshotName,
namespace: ns,
},
spec: {
source: {
persistentVolumeClaimName: pvcName,
},
},
};
handlePromise(k8sCreate(VolumeSnapshotModel, snapshotTemplate))
.then(close)
.catch((error) => {
// eslint-disable-next-line no-console
console.error(error);
});
} else {
const pvcLabel = Math.random()
.toString(36) // To generate a random string with [a-z] and [0-9]
.slice(2); // To get the part of string which is started from position 2
const scheduleTemplate: K8sResourceKind = {
apiVersion: apiVersionForModel(SnapshotScheduleModel),
kind: SnapshotScheduleModel.kind,
metadata: {
name: snapshotName,
namespace: ns,
},
spec: {
claimSelector: {
matchLabels: {
thislabel: `schedule-${pvcLabel}`,
},
},
disabled: false,
retention: {
maxCount: Number(snapshotCount),
},
schedule: scheduleType === snapshotTypes.CronJob ? scheduleLabel : makeLabel(),
},
};
const patch = [
{
op: 'add',
path: '/metadata/labels/thislabel',
value: `schedule-${pvcLabel}`,
const snapshotTemplate: K8sResourceKind = {
apiVersion: VolumeSnapshotModel.apiVersion,
kind: VolumeSnapshotModel.kind,
metadata: {
name: snapshotName,
namespace: ns,
},
spec: {
source: {
persistentVolumeClaimName: pvcName,
},
];

handlePromise(k8sPatch(PersistentVolumeClaimModel, resource, patch)) // eslint-disable-line promise/no-nesting
.then(() => {
handlePromise(k8sCreate(SnapshotScheduleModel, scheduleTemplate)) // eslint-disable-line promise/no-nesting
.then(close)
.catch((error) => {
// eslint-disable-next-line no-console
console.log(error);
});
})
.catch((error) => {
// eslint-disable-next-line no-console
console.log(error);
});
}
},
};
handlePromise(k8sCreate(VolumeSnapshotModel, snapshotTemplate)).then(close); // eslint-disable-line promise/catch-or-return
};

return (
Expand All @@ -245,7 +73,6 @@ export const VolumeSnapshotModal = withHandlePromise((props: VolumeSnapshotModal
name="snapshot-name"
value={snapshotName}
onChange={setSnapshotName}
placeholder={`${getName(resource) || 'pvc'}-snapshot`}
aria-labelledby="snapshot-name"
/>
</FormGroup>
Expand All @@ -260,9 +87,6 @@ export const VolumeSnapshotModal = withHandlePromise((props: VolumeSnapshotModal
selectedKey={scheduleType}
onChange={(value) => setScheduleType(snapshotTypes[value])}
/>
<div className="co-form-subsection">
{scheduleType === snapshotTypes.Single ? null : <ScheduleElements />}
</div>
</FormGroup>
</ModalBody>
<ModalSubmitFooter
Expand Down
@@ -1,14 +1,8 @@
export const numberOfSnapshot = {
3: '3',
5: '5',
7: '7',
};

export const snapshotTypes = {
Single: 'Single',
/* Other ways to create snapshot
for later implementations
CronJob: 'CronJob',
Monthly: 'Monthly',
Weekly: 'Weekly',
Weekly: 'Weekly' */
};

export const cronLink = 'https://en.wikipedia.org/wiki/Cron#Overview';

0 comments on commit e4ee7e6

Please sign in to comment.