Skip to content

Commit

Permalink
kubevirt: add basic actions to VM list
Browse files Browse the repository at this point in the history
  • Loading branch information
suomiy committed Jun 26, 2019
1 parent b7a23ff commit ead6e8a
Show file tree
Hide file tree
Showing 4 changed files with 189 additions and 21 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import * as React from 'react';

import { withHandlePromise } from '@console/internal/components/utils';

import {
createModalLauncher,
ModalTitle,
ModalBody,
ModalSubmitFooter,
} from '@console/internal/components/factory';

import { k8sPatch } from '@console/internal/module/k8s';

import { getPxeBootPatch } from 'kubevirt-web-ui-components';
import { getName, getNamespace } from '@console/shared/src';
import { VirtualMachineModel } from '../../models';
import { VMKind } from '../../types/vm';

const StartStopVmModal = withHandlePromise((props: StartStopVmModalProps) => {
const { vm, start, inProgress, errorMessage, handlePromise, close, cancel } = props;

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

const patches = [];

// handle PXE boot
if (start) {
const pxePatch = getPxeBootPatch(vm);
patches.push(...pxePatch);
}

patches.push({
op: 'replace',
path: '/spec/running',
value: start,
});

const promise = k8sPatch(VirtualMachineModel, vm, patches);
return handlePromise(promise).then(close);
};

const action = start ? 'Start' : 'Stop';
return (
<form onSubmit={submit} name="form" className="modal-content">
<ModalTitle>{action} Virtual Machine</ModalTitle>
<ModalBody>
Are you sure you want to {action.toLowerCase()} <strong>{getName(vm)}</strong> in namespace{' '}
<strong>{getNamespace(vm)}</strong>?
</ModalBody>
<ModalSubmitFooter
errorMessage={errorMessage}
inProgress={inProgress}
submitText={action}
cancel={cancel}
/>
</form>
);
});

export type StartStopVmModalProps = {
vm: VMKind;
start: boolean;
handlePromise: <T>(promise: Promise<T>) => Promise<T>;
inProgress: boolean;
errorMessage: string;
cancel: () => void;
close: () => void;
};

export const startStopVmModal = createModalLauncher(StartStopVmModal);
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import {
getVmStatus,
VM_STATUS_IMPORTING,
VM_STATUS_V2V_CONVERSION_IN_PROGRESS,
} from 'kubevirt-web-ui-components';

import { asAccessReview, Kebab, KebabAction } from '@console/internal/components/utils';
import { K8sKind, PodKind } from '@console/internal/module/k8s';
import { isVMRunning } from '../../selectors/vm';
import { startStopVmModal } from '../modals/start-stop-vm-modal';
import { VMKind } from '../../types/vm';

type ActionArgs = {
pods: PodKind[];
migrations: any[];
};

const isImporting = (vm: VMKind, { pods, migrations }: ActionArgs): boolean => {
const status = getVmStatus(vm, pods, migrations);
return (
status && [VM_STATUS_IMPORTING, VM_STATUS_V2V_CONVERSION_IN_PROGRESS].includes(status.status)
);
};

const menuActionStart = (kindObj: K8sKind, vm: VMKind, actionArgs: ActionArgs): KebabAction => {
return {
hidden: isImporting(vm, actionArgs) || isVMRunning(vm),
label: 'Start Virtual Machine',
callback: () =>
startStopVmModal({
vm,
start: true,
}),
accessReview: asAccessReview(kindObj, vm, 'patch'),
};
};

const menuActionStop = (kindObj: K8sKind, vm: VMKind): KebabAction => {
return {
hidden: !isVMRunning(vm),
label: 'Stop Virtual Machine',
callback: () =>
startStopVmModal({
vm,
start: false,
}),
accessReview: asAccessReview(kindObj, vm, 'patch'),
};
};

export const menuActions = [
menuActionStart,
menuActionStop,
Kebab.factory.ModifyLabels,
Kebab.factory.ModifyAnnotations,
Kebab.factory.Delete,
];
71 changes: 50 additions & 21 deletions frontend/packages/kubevirt-plugin/src/components/vms/vm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,23 @@ import {
} from 'kubevirt-web-ui-components';
import { getName, getNamespace, getUid } from '@console/shared';

import { NamespaceModel } from '@console/internal/models';
import { NamespaceModel, PodModel } from '@console/internal/models';
import { Table, MultiListPage, TableRow, TableData } from '@console/internal/components/factory';
import { Kebab, ResourceLink } from '@console/internal/components/utils';
import { FirehoseResult, Kebab, ResourceLink } from '@console/internal/components/utils';
// import { actions } from '../../module/okdk8s';

import { sortable } from '@patternfly/react-table';
import { PodKind } from '@console/internal/module/k8s';
import {
VirtualMachineInstanceMigrationModel,
VirtualMachineModel,
// VirtualMachineInstanceModel,
// VirtualMachineInstanceMigrationModel,
} from '../../models';

import { VMKind } from '../../types';
import { menuActions } from './menu-actions';

// import { openCreateVmWizard } from '../modals/create-vm-modal';
// import { menuActions } from './menu-actions';

const tableColumnClasses = [
classNames('col-lg-4', 'col-md-4', 'col-sm-6', 'col-xs-6'),
Expand All @@ -51,39 +53,52 @@ const VMHeader = () => [
// title: 'Status',
// props: { className: tableColumnClasses[2] },
// },
// {
// title: '',
// props: { className: Kebab.columnClass, props: { className: tableColumnClasses[3] } },
// },
{
title: '',
props: { className: Kebab.columnClass, props: { className: tableColumnClasses[3] } },
},
];

const VMRow: React.FC<VMRowProps> = ({ obj: vm, index, key, style }) => {
const VMRow: React.FC<VMRowProps> = ({ obj: vm, customData, index, key, style }) => {
const name = getName(vm);
const namespace = getNamespace(vm);
const uid = getUid(vm);

return (
<TableRow id={getUid(vm)} index={index} trKey={key} style={style}>
<TableRow id={uid} index={index} trKey={key} style={style}>
<TableData className={tableColumnClasses[0]}>
<ResourceLink kind={VirtualMachineModel.kind} name={name} namespace={namespace} />
</TableData>
<TableData className={tableColumnClasses[1]}>
<ResourceLink kind={NamespaceModel.kind} name={namespace} title={namespace} />
</TableData>
{/* TODO(mlibra): migrate VM status in a follow-up */}
{/* TODO(mlibra): migrate actions in a follow-up */}
<TableData className={Kebab.columnClass}>
<Kebab
options={menuActions.map((action) => action(VirtualMachineModel, vm, customData))}
key={`kebab-for-${uid}`}
id={`kebab-for-${uid}`}
/>
</TableData>
</TableRow>
);
};

const VMList: React.FC<React.ComponentProps<typeof Table> & VMListProps> = (props) => (
<Table
{...props}
aria-label={VirtualMachineModel.labelPlural}
Header={VMHeader}
Row={VMRow}
virtualize
/>
);
const VMList: React.FC<React.ComponentProps<typeof Table> & VMListProps> = (props) => {
const { resources } = props;
return (
<Table
{...props}
aria-label={VirtualMachineModel.labelPlural}
Header={VMHeader}
Row={VMRow}
customData={{
pods: resources.pods.data || [],
migrations: resources.migrations.data || [],
}}
/>
);
};

VMList.displayName = 'VMList';

Expand Down Expand Up @@ -122,6 +137,12 @@ const getCreateProps = (namespace: string) => ({

export const VirtualMachinesPage: React.FC<VirtualMachinesPageProps> = (props) => {
const { namespace } = props;
const resources = [
getResource(VirtualMachineModel, { namespace, prop: 'vms' }),
getResource(PodModel, { namespace, prop: 'pods' }),
getResource(VirtualMachineInstanceMigrationModel, { namespace, prop: 'migrations' }),
];

const flatten = ({ vms: { data: vmsData, loaded, loadError } }) =>
loaded && !loadError ? vmsData : [];

Expand All @@ -133,7 +154,7 @@ export const VirtualMachinesPage: React.FC<VirtualMachinesPageProps> = (props) =
rowFilters={filters}
ListComponent={VMList}
createProps={getCreateProps(props.namespace)}
resources={[getResource(VirtualMachineModel, { namespace, prop: 'vms' })]}
resources={resources}
flatten={flatten}
/>
);
Expand All @@ -144,10 +165,18 @@ type VMRowProps = {
index: number;
key: string;
style: object;
customData: {
pods: PodKind[];
migrations: any[];
};
};

type VMListProps = {
data: VMKind[];
resources: {
pods: FirehoseResult<PodKind[]>;
migrations: FirehoseResult<any[]>;
};
};

type VirtualMachinesPageProps = {
Expand Down
11 changes: 11 additions & 0 deletions frontend/packages/kubevirt-plugin/src/selectors/vm/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import * as _ from 'lodash';
import { VMKind } from '../../types/vm';

export const isVMRunning = (value: VMKind) =>
_.get(value, 'spec.running', false) as VMKind['spec']['running'];

export const isVMReady = (value: VMKind) =>
_.get(value, 'status.ready', false) as VMKind['status']['ready'];

export const isVMCreated = (value: VMKind) =>
_.get(value, 'status.created', false) as VMKind['status']['created'];

0 comments on commit ead6e8a

Please sign in to comment.