machines: Refresh default storage pool after VM creation or deletion

If user deletes a VM and also decides to remove its associated
storages, the storage pools containing these storages are not refreshed,
thus the deletion is not reflected in the UI.
Also if user creates a new VM with its own new storage, this storage
change is not represented in the UI.
Fix this.

Closes #12883
This commit is contained in:
Simon Kobyda 2019-10-30 11:15:16 +01:00 committed by Katerina Koukiou
parent 7631f5a509
commit b503825fc2
6 changed files with 32 additions and 13 deletions

View File

@ -122,8 +122,8 @@ export function createVm(vmParams) {
return virt(CREATE_VM, vmParams);
}
export function deleteVm(vm, options) {
return virt(DELETE_VM, { name: vm.name, id: vm.id, connectionName: vm.connectionName, options: options });
export function deleteVm(vm, options, storagePools) {
return virt(DELETE_VM, { name: vm.name, id: vm.id, connectionName: vm.connectionName, options, storagePools });
}
export function detachDisk({ connectionName, target, name, id, live = false }) {

View File

@ -50,6 +50,7 @@ import {
getOSStringRepresentation,
} from "./createVmDialogUtils.js";
import MemorySelectRow from '../memorySelectRow.jsx';
import { storagePoolRefresh } from '../../libvirt-dbus.js';
import './createVmDialog.less';
import 'form-layout.less';
@ -684,9 +685,9 @@ class CreateVmModal extends React.Component {
}
onCreateClicked() {
const { dispatch } = this.props;
const { dispatch, providerName, storagePools, close, onAddErrorNotification, osInfoList } = this.props;
const validation = validateParams({ ...this.state, osInfoList: this.props.osInfoList });
const validation = validateParams({ ...this.state, osInfoList: osInfoList });
if (Object.getOwnPropertyNames(validation).length > 0) {
this.setState({ inProgress: false, validate: true });
} else {
@ -711,13 +712,20 @@ class CreateVmModal extends React.Component {
return timeoutedPromise(
dispatch(createVm(vmParams)),
VMS_CONFIG.LeaveCreateVmDialogVisibleAfterSubmit,
() => this.props.close(),
() => {
close();
if (providerName == 'LibvirtDBus' && this.state.storagePool === "NewVolume") {
const storagePool = storagePools.find(pool => pool.connectioName === this.state.connectioName && pool.name === "default");
storagePoolRefresh(storagePool.connectionName, storagePool.id);
}
},
(exception) => {
this.props.onAddErrorNotification({
onAddErrorNotification({
text: cockpit.format(_("Creation of VM $0 failed"), vmParams.vmName),
detail: exception.message,
});
this.props.close();
close();
});
}
}

View File

@ -131,7 +131,7 @@ export class DeleteDialog extends React.Component {
delete() {
const storage = this.state.disks.filter(d => d.checked);
return this.props.dispatch(deleteVm(this.props.vm, { destroy: this.state.destroy, storage: storage }))
return this.props.dispatch(deleteVm(this.props.vm, { destroy: this.state.destroy, storage: storage }, this.props.storagePools))
.catch(exc => {
this.dialogErrorSet(cockpit.format(_("VM $0 failed to get deleted"), this.props.vm.name), exc.message);
});

View File

@ -102,6 +102,7 @@ const Vm = ({
vm,
config,
dispatch,
storagePools,
onStart,
onInstall,
onReboot,

View File

@ -30,7 +30,7 @@ import DropdownButtons from '../dropdownButtons.jsx';
const _ = cockpit.gettext;
const VmActions = ({ vm, config, dispatch, onStart, onInstall, onReboot, onForceReboot, onShutdown, onPause, onResume, onForceoff, onSendNMI }) => {
const VmActions = ({ vm, config, dispatch, storagePools, onStart, onInstall, onReboot, onForceReboot, onShutdown, onPause, onResume, onForceoff, onSendNMI }) => {
const id = vmId(vm.name);
const state = vm.state;
const hasInstallPhase = vm.metadata.hasInstallPhase;
@ -108,7 +108,7 @@ const VmActions = ({ vm, config, dispatch, onStart, onInstall, onReboot, onForce
let deleteAction = null;
if (state !== undefined && config.provider.canDelete && config.provider.canDelete(state, vm.id, config.providerState)) {
deleteAction = (
<DeleteDialog key='action-delete' vm={vm} dispatch={dispatch} />
<DeleteDialog key='action-delete' vm={vm} dispatch={dispatch} storagePools={storagePools} />
);
}
@ -128,6 +128,7 @@ VmActions.propTypes = {
vm: PropTypes.object.isRequired,
config: PropTypes.string.isRequired,
dispatch: PropTypes.func.isRequired,
storagePools: PropTypes.array.isRequired,
onStart: PropTypes.func.isRequired,
onReboot: PropTypes.func.isRequired,
onForceReboot: PropTypes.func.isRequired,

View File

@ -343,7 +343,8 @@ LIBVIRT_DBUS_PROVIDER = {
name,
connectionName,
id: objPath,
options
options,
storagePools
}) {
function destroy() {
return call(connectionName, objPath, 'org.libvirt.Domain', 'Destroy', [0], TIMEOUT);
@ -357,19 +358,27 @@ LIBVIRT_DBUS_PROVIDER = {
const disk = options.storage[i];
switch (disk.type) {
case 'file':
case 'file': {
storageVolPromises.push(
call(connectionName, '/org/libvirt/QEMU', 'org.libvirt.Connect', 'StorageVolLookupByPath', [disk.source.file], TIMEOUT)
.then(volPath => call(connectionName, volPath[0], 'org.libvirt.StorageVol', 'Delete', [0], TIMEOUT))
);
const pool = storagePools.find(pool => pool.connectionName === connectionName && pool.volumes.some(vol => vol.path === disk.source.file));
if (pool)
storageVolPromises.push(storagePoolRefresh(connectionName, pool.id));
break;
case 'volume':
}
case 'volume': {
storageVolPromises.push(
call(connectionName, '/org/libvirt/QEMU', 'org.libvirt.Connect', 'StoragePoolLookupByName', [disk.source.pool], TIMEOUT)
.then(objPath => call(connectionName, objPath[0], 'org.libvirt.StoragePool', 'StorageVolLookupByName', [disk.source.volume], TIMEOUT))
.then(volPath => call(connectionName, volPath[0], 'org.libvirt.StorageVol', 'Delete', [0], TIMEOUT))
);
const pool = storagePools.find(pool => pool.connectionName === connectionName && pool.name === disk.source.pool);
if (pool)
storageVolPromises.push(storagePoolRefresh(connectionName, pool.id));
break;
}
default:
logDebug("Disks of type $0 are currently ignored during VM deletion".format(disk.type));
}