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 Gilad Lekner committed Aug 25, 2020
1 parent b906377 commit faf955c
Show file tree
Hide file tree
Showing 7 changed files with 165 additions and 6 deletions.
29 changes: 27 additions & 2 deletions frontend/packages/console-plugin-sdk/src/typings/pvc.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { K8sResourceCommon } from '@console/internal/module/k8s';
import { PersistentVolumeClaimKind } from '@console/internal/module/k8s';
import { AlertVariant } from '@patternfly/react-core';
import { Extension, LazyLoader } from './base';

namespace ExtensionProperties {
Expand All @@ -11,7 +12,7 @@ namespace ExtensionProperties {
/** Loader for the corresponding Status component. */
loader: LazyLoader<T>;
/** predicate that tells if to render the status or not */
predicate: (pvc: K8sResourceCommon) => boolean;
predicate: (pvc: PersistentVolumeClaimKind) => boolean;
/** priority for the corresponding Status component. bigger is prioritized */
priority: number;
}
Expand All @@ -22,6 +23,22 @@ namespace ExtensionProperties {
/** path for the create prop */
path: string;
}

export interface PVCDelete {
/** predicate that tells if to use the extension or not */
predicate: (pvc: PersistentVolumeClaimKind) => boolean;
/** method for the pvc delete operation */
onPVCKill: (pvc: PersistentVolumeClaimKind) => Promise<void>;
/** alert for additional info */
alert?: {
/** alert title */
alertTitle: string;
/** alert variant */
alertType: AlertVariant;
/** alert body */
alertBody: LazyLoader<{ pvc: PersistentVolumeClaimKind }>;
};
}
}

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

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

export const isPVCAlert = (e: Extension): e is PVCAlert => {
return e.type === 'PVCAlert';
};
Expand All @@ -47,3 +68,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,18 @@
import * as React from 'react';
import { k8sKill, K8sResourceKind } from '@console/internal/module/k8s';
import { DataVolumeModel } from '../../models';

export const killCDIBoundPVC = (pvc: K8sResourceKind) =>
k8sKill(DataVolumeModel, {
metadata: {
name: pvc?.metadata?.name,
namespace: pvc?.metadata?.namespace,
},
});

export const PVCDeleteAlertExtension = ({ pvc }) => (
<>
Deleting this PVC will also delete{' '}
<strong className="co-break-word">{pvc?.metadata?.name}</strong> Data Volume
</>
);
26 changes: 24 additions & 2 deletions frontend/packages/kubevirt-plugin/src/plugin.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as React from 'react';
import * as _ from 'lodash';
import * as virtualMachineIcon from './images/virtual-machine.svg';
import { AlertVariant } from '@patternfly/react-core';
import {
Plugin,
ResourceNSNavItem,
Expand All @@ -21,6 +22,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 +44,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 +69,8 @@ type ConsumedExtensions =
| ContextProvider
| PVCCreateProp
| PVCAlert
| PVCStatus;
| PVCStatus
| PVCDelete;

export const FLAG_KUBEVIRT = 'KUBEVIRT';

Expand Down Expand Up @@ -544,6 +548,24 @@ const plugin: Plugin<ConsumedExtensions> = [
required: [FLAG_KUBEVIRT],
},
},
{
type: 'PVCDelete',
properties: {
predicate: isPvcBoundToCDI,
onPVCKill: killCDIBoundPVC,
alert: {
alertType: AlertVariant.warning,
alertTitle: 'PVC Delete',
alertBody: () =>
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';
78 changes: 78 additions & 0 deletions frontend/public/components/modals/delete-pvc-modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import * as React from 'react';
import { Alert, 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, PersistentVolumeClaimKind } from '@console/internal/module/k8s';
import { PersistentVolumeClaimModel } from '../../models';
import { isPVCDelete, PVCDelete, useExtensions } from '@console/plugin-sdk';

const DeletePVCModal = withHandlePromise<DeletePVCModalProps>((props) => {
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);
const extensionPromises = pvcDeleteExtensions.map(
({ properties: { predicate, onPVCKill } }) => predicate(pvc) && onPVCKill(pvc),
);
return handlePromise(Promise.all([promise, ...extensionPromises]), close);
};

const alertComponents = pvcDeleteExtensions.map(
({ properties: { predicate, alert }, uid }) =>
predicate(pvc) && (
<Alert
key={`pvc-alert-${uid}`}
className="co-m-form-row"
isInline
variant={alert?.alertType}
title={alert?.alertTitle}
>
<AsyncComponent loader={alert?.alertBody} pvc={pvc} />
</Alert>
),
);

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: PersistentVolumeClaimKind;
} & 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 faf955c

Please sign in to comment.