Skip to content

Commit

Permalink
Fixes 1871742: It is not possible to delete a PVC created using a dat…
Browse files Browse the repository at this point in the history
…a upload
  • Loading branch information
Gilad Lekner authored and glekner committed Aug 24, 2020
1 parent b906377 commit 5ab1911
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 4 deletions.
17 changes: 17 additions & 0 deletions frontend/packages/console-plugin-sdk/src/typings/pvc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,15 @@ namespace ExtensionProperties {
/** path for the create prop */
path: string;
}

export interface PVCDelete<T> {
/** predicate that tells if to use the extension or not */
predicate: (pvc: K8sResourceCommon) => boolean;
/** method for the pvc delete operation */
onPVCKill: (pvc: K8sResourceCommon) => Promise<void>;
/** alert for additional info */
alertLoader?: LazyLoader<T>;
}
}

export interface PVCAlert<R = any> extends Extension<ExtensionProperties.PVCAlert<R>> {
Expand All @@ -36,6 +45,10 @@ export interface PVCCreateProp extends Extension<ExtensionProperties.PVCCreatePr
type: 'PVCCreateProp';
}

export interface PVCDelete<R = any> extends Extension<ExtensionProperties.PVCDelete<R>> {
type: 'PVCDelete';
}

export const isPVCAlert = (e: Extension): e is PVCAlert => {
return e.type === 'PVCAlert';
};
Expand All @@ -47,3 +60,7 @@ export const isPVCStatus = (e: Extension): e is PVCStatus => {
export const isPVCCreateProp = (e: Extension): e is PVCCreateProp => {
return e.type === 'PVCCreateProp';
};

export const isPVCDelete = (e: Extension): e is PVCDelete => {
return e.type === 'PVCDelete';
};
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ export enum UPLOAD_STATUS {
export const CDI_UPLOAD_POD_ANNOTATION = 'cdi.kubevirt.io/storage.pod.phase';
export const CDI_UPLOAD_POD_NAME_ANNOTATION = 'cdi.kubevirt.io/storage.uploadPodName';
export const CDI_UPLOAD_RUNNING = 'Running';
export const CDI_BOUND_PVC_ANNOTATION = 'cdi.kubevirt.io/storage.condition.bound';
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import * as React from 'react';
import { Alert, AlertVariant } from '@patternfly/react-core';
import { k8sKill, K8sResourceKind } from '@console/internal/module/k8s';
import { DataVolumeModel } from '../../models';

export const killCDIBoundPVC = (pvc: K8sResourceKind) => k8sKill(DataVolumeModel, pvc);

export const PVCDeleteAlertExtension: React.FC<PVCDeleteAlertExtension> = ({ pvc }) => (
<Alert className="co-m-form-row" isInline variant={AlertVariant.warning} title="PVC Delete">
Deleting this PVC will also delete{' '}
<strong className="co-break-word">{pvc?.metadata?.name}</strong> Data Volume
</Alert>
);

type PVCDeleteAlertExtension = {
pvc: K8sResourceKind;
};
21 changes: 19 additions & 2 deletions frontend/packages/kubevirt-plugin/src/plugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
PVCCreateProp,
PVCAlert,
PVCStatus,
PVCDelete,
} from '@console/plugin-sdk';
import { DashboardsStorageCapacityDropdownItem } from '@console/ceph-storage-plugin';
import { TemplateModel, PodModel, PersistentVolumeClaimModel } from '@console/internal/models';
Expand All @@ -42,8 +43,9 @@ import {
CDIUploadContext,
useCDIUploadHook,
} from './components/cdi-upload-provider/cdi-upload-provider';
import { killCDIBoundPVC } from './components/cdi-upload-provider/pvc-delete-extension';
import { isPvcBoundToCDI, isPvcUploading } from './selectors/pvc/selectors';
import './style.scss';
import { isPvcUploading } from './selectors/pvc/selectors';

type ConsumedExtensions =
| ResourceNSNavItem
Expand All @@ -66,7 +68,8 @@ type ConsumedExtensions =
| ContextProvider
| PVCCreateProp
| PVCAlert
| PVCStatus;
| PVCStatus
| PVCDelete;

export const FLAG_KUBEVIRT = 'KUBEVIRT';

Expand Down Expand Up @@ -544,6 +547,20 @@ const plugin: Plugin<ConsumedExtensions> = [
required: [FLAG_KUBEVIRT],
},
},
{
type: 'PVCDelete',
properties: {
predicate: isPvcBoundToCDI,
onPVCKill: killCDIBoundPVC,
alertLoader: () =>
import('./components/cdi-upload-provider/pvc-delete-extension').then(
(m) => m.PVCDeleteAlertExtension,
),
},
flags: {
required: [FLAG_KUBEVIRT],
},
},
];

export default plugin;
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
CDI_UPLOAD_RUNNING,
CDI_UPLOAD_POD_ANNOTATION,
CDI_UPLOAD_POD_NAME_ANNOTATION,
CDI_BOUND_PVC_ANNOTATION,
} from '../../components/cdi-upload-provider/consts';
import { STORAGE_IMPORT_POD_LABEL } from '../../constants';

Expand All @@ -24,3 +25,5 @@ export const getPvcUploadPhase = (pvc) => getAnnotation(pvc, CDI_UPLOAD_POD_ANNO

export const isPvcUploading = (pvc) =>
getPvcUploadPodName(pvc) && getPvcUploadPhase(pvc) === CDI_UPLOAD_RUNNING;

export const isPvcBoundToCDI = (pvc) => getAnnotation(pvc, CDI_BOUND_PVC_ANNOTATION) === 'true';
71 changes: 71 additions & 0 deletions frontend/public/components/modals/delete-pvc-modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import * as React from 'react';
import { Stack, StackItem } from '@patternfly/react-core';
import { AsyncComponent, HandlePromiseProps, withHandlePromise } from '../utils';
import { getName, YellowExclamationTriangleIcon } from '@console/shared';
import {
createModalLauncher,
ModalTitle,
ModalBody,
ModalSubmitFooter,
ModalComponentProps,
} from '../factory';
import { k8sKill, K8sResourceCommon } from '@console/internal/module/k8s';
import { PersistentVolumeClaimModel } from '../../models';
import { isPVCDelete, PVCDelete, useExtensions } from '@console/plugin-sdk';

const DeletePVCModal = withHandlePromise((props: DeletePVCModalProps) => {
const { pvc, inProgress, errorMessage, handlePromise, close, cancel } = props;
const pvcDeleteExtensions = useExtensions<PVCDelete>(isPVCDelete);
const pvcName = getName(pvc);

const submit = (e) => {
e.preventDefault();

const promise = k8sKill(PersistentVolumeClaimModel, pvc).then(() =>
Promise.all(
pvcDeleteExtensions.map(
({ properties: { predicate, onPVCKill } }) => predicate(pvc) && onPVCKill(pvc),
),
),
);
return handlePromise(promise, close);
};

const alertComponents = pvcDeleteExtensions.map(
({ properties: { predicate, alertLoader } }, i) =>
predicate(pvc) && <AsyncComponent key={`ext-${i}`} loader={alertLoader} pvc={pvc} />,
);

return (
<form onSubmit={submit} className="modal-content">
<ModalTitle>
<YellowExclamationTriangleIcon className="co-icon-space-r" /> Delete Persistent Volume Claim
</ModalTitle>
<ModalBody>
<Stack hasGutter>
{alertComponents.map((alert, i) => (
<StackItem key={`alert-${i}`}>{alert}</StackItem>
))}
<StackItem>
Are you sure you want to delete <strong className="co-break-word">{pvcName}</strong>{' '}
Persistent Volume Claim?
</StackItem>
</Stack>
</ModalBody>
<ModalSubmitFooter
errorMessage={errorMessage}
inProgress={inProgress}
submitText="Delete"
submitDanger
cancel={cancel}
/>
</form>
);
});

export type DeletePVCModalProps = {
pvc: K8sResourceCommon;
} & ModalComponentProps &
HandlePromiseProps;

export default createModalLauncher(DeletePVCModal);
16 changes: 14 additions & 2 deletions frontend/public/components/persistent-volume-claim.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,32 @@ import {
humanizeBinaryBytes,
convertToBaseValue,
AsyncComponent,
asAccessReview,
} from './utils';
import { ResourceEventStream } from './events';
import { PersistentVolumeClaimModel } from '../models';
import { setPVCMetrics } from '../actions/ui';
import { PrometheusEndpoint } from './graphs/helpers';
import { usePrometheusPoll } from './graphs/prometheus-poll-hook';
import deletePVCModal from './modals/delete-pvc-modal';

const { common, ExpandPVC, PVCSnapshot, ClonePVC } = Kebab.factory;
const { ModifyLabels, ModifyAnnotations, Edit, ExpandPVC, PVCSnapshot, ClonePVC } = Kebab.factory;
const menuActions = [
...Kebab.getExtensionsActionsForKind(PersistentVolumeClaimModel),
ExpandPVC,
PVCSnapshot,
ClonePVC,
...common,
ModifyLabels,
ModifyAnnotations,
Edit,
(kind, obj) => ({
label: `Delete ${kind.label}`,
callback: () =>
deletePVCModal({
pvc: obj,
}),
accessReview: asAccessReview(kind, obj, 'delete'),
}),
];

export const PVCStatus = ({ pvc }) => {
Expand Down

0 comments on commit 5ab1911

Please sign in to comment.