package org.ovirt.engine.ui.uicommonweb.models.vms;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.ovirt.engine.core.common.VdcActionUtils;
import org.ovirt.engine.core.common.action.ChangeQuotaParameters;
import org.ovirt.engine.core.common.action.GetDiskAlignmentParameters;
import org.ovirt.engine.core.common.action.VdcActionParametersBase;
import org.ovirt.engine.core.common.action.VdcActionType;
import org.ovirt.engine.core.common.action.VmDiskOperationParameterBase;
import org.ovirt.engine.core.common.businessentities.StoragePool;
import org.ovirt.engine.core.common.businessentities.VM;
import org.ovirt.engine.core.common.businessentities.VMStatus;
import org.ovirt.engine.core.common.businessentities.comparators.DiskByDiskAliasComparator;
import org.ovirt.engine.core.common.businessentities.storage.CinderDisk;
import org.ovirt.engine.core.common.businessentities.storage.Disk;
import org.ovirt.engine.core.common.businessentities.storage.DiskImage;
import org.ovirt.engine.core.common.businessentities.storage.DiskStorageType;
import org.ovirt.engine.core.common.businessentities.storage.DiskVmElement;
import org.ovirt.engine.core.common.businessentities.storage.ImageStatus;
import org.ovirt.engine.core.common.businessentities.storage.LunDisk;
import org.ovirt.engine.core.common.businessentities.storage.StorageType;
import org.ovirt.engine.core.common.businessentities.storage.VolumeType;
import org.ovirt.engine.core.common.queries.IdQueryParameters;
import org.ovirt.engine.core.common.queries.VdcQueryType;
import org.ovirt.engine.core.compat.Version;
import org.ovirt.engine.ui.frontend.Frontend;
import org.ovirt.engine.ui.uicommonweb.UICommand;
import org.ovirt.engine.ui.uicommonweb.dataprovider.AsyncDataProvider;
import org.ovirt.engine.ui.uicommonweb.help.HelpTag;
import org.ovirt.engine.ui.uicommonweb.models.ConfirmationModel;
import org.ovirt.engine.ui.uicommonweb.models.ISupportSystemTreeContext;
import org.ovirt.engine.ui.uicommonweb.models.SystemTreeItemModel;
import org.ovirt.engine.ui.uicommonweb.models.quota.ChangeQuotaItemModel;
import org.ovirt.engine.ui.uicommonweb.models.quota.ChangeQuotaModel;
import org.ovirt.engine.ui.uicompat.ConstantsManager;
import org.ovirt.engine.ui.uicompat.PropertyChangedEventArgs;
public class VmDiskListModel extends VmDiskListModelBase<VM> {
private UICommand privateNewCommand;
public UICommand getNewCommand() {
return privateNewCommand;
}
private void setNewCommand(UICommand value) {
privateNewCommand = value;
}
private UICommand attachCommand;
public UICommand getAttachCommand() {
return attachCommand;
}
private void setAttachCommand(UICommand value) {
attachCommand = value;
}
private UICommand privateEditCommand;
@Override
public UICommand getEditCommand() {
return privateEditCommand;
}
private void setEditCommand(UICommand value) {
privateEditCommand = value;
}
private UICommand privateRemoveCommand;
public UICommand getRemoveCommand() {
return privateRemoveCommand;
}
private void setRemoveCommand(UICommand value) {
privateRemoveCommand = value;
}
private UICommand sparsifyCommand;
public UICommand getSparsifyCommand() {
return sparsifyCommand;
}
private void setSparsifyCommand(UICommand value) {
sparsifyCommand = value;
}
private UICommand privatePlugCommand;
public UICommand getPlugCommand() {
return privatePlugCommand;
}
private void setPlugCommand(UICommand value) {
privatePlugCommand = value;
}
private UICommand privateUnPlugCommand;
public UICommand getUnPlugCommand() {
return privateUnPlugCommand;
}
private void setUnPlugCommand(UICommand value) {
privateUnPlugCommand = value;
}
ISupportSystemTreeContext systemTreeContext;
public ISupportSystemTreeContext getSystemTreeContext() {
return systemTreeContext;
}
public void setSystemTreeContext(ISupportSystemTreeContext systemTreeContext) {
this.systemTreeContext = systemTreeContext;
}
private UICommand privateChangeQuotaCommand;
public UICommand getChangeQuotaCommand() {
return privateChangeQuotaCommand;
}
private void setChangeQuotaCommand(UICommand value) {
privateChangeQuotaCommand = value;
}
private UICommand privateMoveCommand;
public UICommand getMoveCommand() {
return privateMoveCommand;
}
private void setMoveCommand(UICommand value) {
privateMoveCommand = value;
}
private UICommand privateScanAlignmentCommand;
public UICommand getScanAlignmentCommand() {
return privateScanAlignmentCommand;
}
private void setScanAlignmentCommand(UICommand value) {
privateScanAlignmentCommand = value;
}
public boolean isExtendImageSizeEnabled() {
return (getEntity() != null) ?
VdcActionUtils.canExecute(Arrays.asList(getEntity()), VM.class, VdcActionType.ExtendImageSize) : false;
}
public VmDiskListModel() {
setTitle(ConstantsManager.getInstance().getConstants().disksTitle());
setHelpTag(HelpTag.disks);
setHashName("disks"); //$NON-NLS-1$
setNewCommand(new UICommand("New", this)); //$NON-NLS-1$
setAttachCommand(new UICommand("Attach", this)); //$NON-NLS-1$
setEditCommand(new UICommand("Edit", this)); //$NON-NLS-1$
setRemoveCommand(new UICommand("Remove", this)); //$NON-NLS-1$
setSparsifyCommand(new UICommand("Sparsify", this)); //$NON-NLS-1$
setPlugCommand(new UICommand("Plug", this)); //$NON-NLS-1$
setUnPlugCommand(new UICommand("Unplug", this)); //$NON-NLS-1$
setMoveCommand(new UICommand("Move", this)); //$NON-NLS-1$
setScanAlignmentCommand(new UICommand("Scan Alignment", this)); //$NON-NLS-1$
setChangeQuotaCommand(new UICommand("changeQuota", this)); //$NON-NLS-1$
getChangeQuotaCommand().setIsAvailable(false);
updateActionAvailability();
}
@Override
protected void onEntityChanged() {
super.onEntityChanged();
if (getEntity() != null) {
updateDataCenterVersion();
getSearchCommand().execute();
}
updateActionAvailability();
}
@Override
protected void syncSearch() {
if (getEntity() == null) {
return;
}
VM vm = getEntity();
super.syncSearch(VdcQueryType.GetAllDisksByVmId, new IdQueryParameters(vm.getId()));
}
@Override
public void setItems(Collection value) {
ArrayList<Disk> disks = value != null ? new ArrayList<>(value) : new ArrayList<Disk>();
Collections.sort(disks, new DiskByDiskAliasComparator());
super.setItems(disks);
updateActionAvailability();
}
private void newEntity() {
if (getWindow() != null) {
return;
}
addDisk(new NewDiskModel(),
ConstantsManager.getInstance().getConstants().newVirtualDiskTitle(),
HelpTag.new_virtual_disk, "new_virtual_disk"); //$NON-NLS-1$
}
private void attach() {
if (getWindow() != null) {
return;
}
addDisk(new AttachDiskModel(),
ConstantsManager.getInstance().getConstants().attachVirtualDiskTitle(),
HelpTag.attach_virtual_disk, "attach_virtual_disk"); //$NON-NLS-1$
}
private void addDisk(AbstractDiskModel model, String title, HelpTag helpTag, String hashName) {
model.setTitle(title);
model.setHelpTag(helpTag);
model.setHashName(hashName); //$NON-NLS-1$
model.setVm(getEntity());
setWindow(model);
UICommand cancelCommand = UICommand.createCancelUiCommand("Cancel", this); //$NON-NLS-1$
model.setCancelCommand(cancelCommand);
model.initialize();
}
private void changeQuota() {
ArrayList<DiskImage> disks = (ArrayList) getSelectedItems();
if (disks == null || getWindow() != null) {
return;
}
ChangeQuotaModel model = new ChangeQuotaModel();
setWindow(model);
model.setTitle(ConstantsManager.getInstance().getConstants().assignQuotaForDisk());
model.setHelpTag(HelpTag.change_quota_disks);
model.setHashName("change_quota_disks"); //$NON-NLS-1$
model.startProgress();
model.init(disks);
model.getCommands().add(UICommand.createDefaultOkUiCommand("onChangeQuota", this)); //$NON-NLS-1$
model.getCommands().add(UICommand.createCancelUiCommand("Cancel", this)); //$NON-NLS-1$
}
private void onChangeQuota() {
ChangeQuotaModel model = (ChangeQuotaModel) getWindow();
ArrayList<VdcActionParametersBase> paramerterList = new ArrayList<>();
for (Object item : model.getItems()) {
ChangeQuotaItemModel itemModel = (ChangeQuotaItemModel) item;
DiskImage disk = itemModel.getEntity();
VdcActionParametersBase parameters =
new ChangeQuotaParameters(itemModel.getQuota().getSelectedItem().getId(),
disk.getId(),
itemModel.getStorageDomainId(),
disk.getStoragePoolId());
paramerterList.add(parameters);
}
model.startProgress();
Frontend.getInstance().runMultipleAction(VdcActionType.ChangeQuotaForDisk, paramerterList,
result -> cancel(),
this);
}
private void edit() {
final Disk disk = getSelectedItem();
if (getWindow() != null) {
return;
}
EditDiskModel model = new EditDiskModel();
model.setTitle(ConstantsManager.getInstance().getConstants().editVirtualDiskTitle());
model.setHelpTag(HelpTag.edit_virtual_disk);
model.setHashName("edit_virtual_disk"); //$NON-NLS-1$
model.setVm(getEntity());
model.setDisk(disk);
setWindow(model);
UICommand cancelCommand = UICommand.createCancelUiCommand("Cancel", this); //$NON-NLS-1$
model.setCancelCommand(cancelCommand);
model.initialize();
}
private void remove() {
if (getWindow() != null) {
return;
}
RemoveDiskModel model = new RemoveDiskModel();
setWindow(model);
model.initialize(getEntity(), getSelectedItems(), this);
}
private void onRemove() {
RemoveDiskModel model = (RemoveDiskModel) getWindow();
if (!model.validate()) {
return;
}
model.onRemove(this);
}
private void sparsify() {
if (getWindow() != null) {
return;
}
SparsifyDiskModel model = new SparsifyDiskModel();
setWindow(model);
model.initialize(getEntity(), getSelectedItems(), this);
}
private void onSparsify() {
SparsifyDiskModel model = (SparsifyDiskModel) getWindow();
if (!model.validate()) {
return;
}
model.onSparsify(this);
}
private void plug() {
Frontend.getInstance().runMultipleAction(VdcActionType.HotPlugDiskToVm, createPlugOrUnplugParams(true),
result -> {
},
this);
}
private void unplug() {
final ConfirmationModel model = (ConfirmationModel) getWindow();
model.startProgress();
Frontend.getInstance().runMultipleAction(VdcActionType.HotUnPlugDiskFromVm, createPlugOrUnplugParams(false),
result -> {
model.stopProgress();
setWindow(null);
},
this);
}
private ArrayList<VdcActionParametersBase> createPlugOrUnplugParams(boolean plug) {
ArrayList<VdcActionParametersBase> parametersList = new ArrayList<>();
VM vm = getEntity();
for (Object item : getSelectedItems()) {
Disk disk = (Disk) item;
disk.setPlugged(plug);
parametersList.add(new VmDiskOperationParameterBase(new DiskVmElement(disk.getId(), vm.getId())));
}
return parametersList;
}
private void confirmUnplug() {
ConfirmationModel model = new ConfirmationModel();
model.setTitle(ConstantsManager.getInstance().getConstants().deactivateVmDisksTitle());
model.setMessage(ConstantsManager.getInstance().getConstants().areYouSureYouWantDeactivateVMDisksMsg());
model.setHashName("deactivate_vm_disk"); //$NON-NLS-1$
setWindow(model);
ArrayList<String> items = new ArrayList<>();
for (Disk selected : getSelectedItems()) {
items.add(selected.getDiskAlias());
}
model.setItems(items);
UICommand unPlug = UICommand.createDefaultOkUiCommand("OnUnplug", this); //$NON-NLS-1$
model.getCommands().add(unPlug);
UICommand cancel = UICommand.createCancelUiCommand("Cancel", this); //$NON-NLS-1$
model.getCommands().add(cancel);
}
private void move() {
ArrayList<DiskImage> disks = (ArrayList) getSelectedItems();
if (disks == null) {
return;
}
if (getWindow() != null) {
return;
}
MoveDiskModel model = new MoveDiskModel();
setWindow(model);
model.setTitle(ConstantsManager.getInstance().getConstants().moveDisksTitle());
model.setHelpTag(HelpTag.move_disk);
model.setHashName("move_disk"); //$NON-NLS-1$
model.setIsSourceStorageDomainNameAvailable(true);
model.setEntity(this);
model.init(disks);
model.startProgress();
}
private void scanAlignment() {
ArrayList<VdcActionParametersBase> parameterList = new ArrayList<>();
for (Disk disk : getSelectedItems()) {
parameterList.add(new GetDiskAlignmentParameters(disk.getId()));
}
Frontend.getInstance().runMultipleAction(VdcActionType.GetDiskAlignment, parameterList,
result -> {
},
this);
}
private void cancel() {
setWindow(null);
}
@Override
protected void onSelectedItemChanged() {
super.onSelectedItemChanged();
updateActionAvailability();
}
@Override
protected void selectedItemsChanged() {
super.selectedItemsChanged();
updateActionAvailability();
}
@Override
protected void entityPropertyChanged(Object sender, PropertyChangedEventArgs e) {
super.entityPropertyChanged(sender, e);
if (e.propertyName.equals("status")) { //$NON-NLS-1$
updateActionAvailability();
}
}
private void updateActionAvailability() {
Disk disk = getSelectedItem();
getNewCommand().setIsExecutionAllowed(true);
getAttachCommand().setIsExecutionAllowed(true);
getEditCommand().setIsExecutionAllowed(disk != null && isSingleDiskSelected() && !isDiskLocked(disk) &&
(isVmDown() || !disk.getPlugged() || isExtendImageSizeEnabled()));
getRemoveCommand().setIsExecutionAllowed(atLeastOneDiskSelected() && isRemoveCommandAvailable());
getSparsifyCommand().setIsExecutionAllowed(atLeastOneDiskSelected() && isSparsifyCommandAvailable());
getMoveCommand().setIsExecutionAllowed(atLeastOneDiskSelected()
&& (isMoveCommandAvailable() || isLiveMoveCommandAvailable()));
updateScanAlignmentCommandAvailability();
getPlugCommand().setIsExecutionAllowed(isPlugCommandAvailable(true));
getUnPlugCommand().setIsExecutionAllowed(isPlugCommandAvailable(false));
ChangeQuotaModel.updateChangeQuotaActionAvailability(getItems() != null ? (List<Disk>) getItems() : null,
getSelectedItems() != null ? getSelectedItems() : null,
getSystemTreeSelectedItem(),
getChangeQuotaCommand());
}
public boolean isVmDown() {
VM vm = getEntity();
return vm != null && vm.getStatus() == VMStatus.Down;
}
private boolean isDiskLocked(Disk disk) {
switch (disk.getDiskStorageType()) {
case IMAGE:
return ((DiskImage) disk).getImageStatus() == ImageStatus.LOCKED;
case CINDER:
return ((CinderDisk) disk).getImageStatus() == ImageStatus.LOCKED;
}
return false;
}
private boolean isSingleDiskSelected() {
return getSelectedItems() != null && getSelectedItems().size() == 1;
}
private boolean atLeastOneDiskSelected() {
return getSelectedItems() != null && getSelectedItems().size() > 0;
}
public boolean isHotPlugAvailable() {
VM vm = getEntity();
return vm != null && (vm.getStatus() == VMStatus.Up || vm.getStatus() == VMStatus.Paused);
}
private boolean isPlugCommandAvailable(boolean plug) {
return getSelectedItems() != null && getSelectedItems().size() > 0
&& isPlugAvailableByDisks(plug) &&
(isVmDown() || isHotPlugAvailable());
}
public boolean isPlugAvailableByDisks(boolean plug) {
List<Disk> disks = getSelectedItems() != null ? getSelectedItems() : new ArrayList<Disk>();
for (Disk disk : disks) {
boolean isLocked =
disk.getDiskStorageType() == DiskStorageType.IMAGE
&& ((DiskImage) disk).getImageStatus() == ImageStatus.LOCKED;
boolean isDiskHotpluggableInterface = false;
if (getEntity() != null && disk.getDiskVmElementForVm(getEntity().getId()) != null) {
isDiskHotpluggableInterface =
AsyncDataProvider.getInstance().getDiskHotpluggableInterfaces(
getEntity().getOs(),
getEntity().getCompatibilityVersion()).contains(disk.getDiskVmElementForVm(getEntity().getId()).getDiskInterface());
}
if (disk.getPlugged() == plug
|| isLocked
|| (!isDiskHotpluggableInterface && !isVmDown())) {
return false;
}
}
return true;
}
private boolean isImageDiskOK(Disk disk) {
return disk.getDiskStorageType() == DiskStorageType.IMAGE &&
((DiskImage) disk).getImageStatus() == ImageStatus.OK;
}
private boolean isImageDiskPreallocated(Disk disk) {
return disk.getDiskStorageType() == DiskStorageType.IMAGE &&
((DiskImage) disk).getImage().getVolumeType() == VolumeType.Preallocated;
}
private boolean isMoveCommandAvailable() {
List<Disk> disks = getSelectedItems() != null ? getSelectedItems() : new ArrayList<Disk>();
for (Disk disk : disks) {
if (!isImageDiskOK(disk) || (!isVmDown() && disk.getPlugged()) || disk.isDiskSnapshot()) {
return false;
}
}
return true;
}
private boolean isLiveMoveCommandAvailable() {
VM vm = getEntity();
if (vm == null || !vm.getStatus().isUpOrPaused() || vm.isStateless()) {
return false;
}
List<Disk> disks = getSelectedItems() != null ? getSelectedItems() : new ArrayList<Disk>();
for (Disk disk : disks) {
if (!isImageDiskOK(disk) || disk.isDiskSnapshot()) {
return false;
}
}
return true;
}
private boolean isRemoveCommandAvailable() {
List<Disk> disks = getSelectedItems() != null ? getSelectedItems() : new ArrayList<Disk>();
for (Disk disk : disks) {
if (isDiskLocked(disk) || (!isVmDown() && disk.getPlugged())) {
return false;
}
}
return true;
}
private boolean isSparsifyCommandAvailable() {
List<Disk> disks = getSelectedItems() != null ?getSelectedItems() : new ArrayList<Disk>();
for (Disk disk : disks) {
if (!isImageDiskOK(disk) || isImageDiskPreallocated(disk) || (!isVmDown() && disk.getPlugged())) {
return false;
}
}
return true;
}
private void updateScanAlignmentCommandAvailability() {
boolean isExecutionAllowed = true;
if (isVmDown() && getSelectedItems() != null && getEntity() != null) {
List<Disk> disks = getSelectedItems();
for (Disk disk : disks) {
if (!(disk instanceof LunDisk) && !isDiskOnBlockDevice(disk)) {
isExecutionAllowed = false;
break;
}
}
}
else {
isExecutionAllowed = false;
}
getScanAlignmentCommand().setIsExecutionAllowed(isExecutionAllowed);
//onPropertyChanged(new PropertyChangedEventArgs("IsScanAlignmentEnabled")); //$NON-NLS-1$
}
@Override
public void executeCommand(UICommand command) {
super.executeCommand(command);
if (command == getNewCommand()) {
newEntity();
}
else if (command == getAttachCommand()) {
attach();
}
else if (command == getEditCommand()) {
edit();
}
else if (command == getRemoveCommand()) {
remove();
}
else if (command == getSparsifyCommand()) {
sparsify();
}
else if (command == getMoveCommand()) {
move();
}
else if (command == getScanAlignmentCommand()) {
scanAlignment();
}
else if ("Cancel".equals(command.getName())) { //$NON-NLS-1$
cancel();
}
else if (RemoveDiskModel.CANCEL_REMOVE.equals(command.getName())) {
cancel();
}
else if (RemoveDiskModel.ON_REMOVE.equals(command.getName())) {
onRemove();
}
else if (SparsifyDiskModel.CANCEL_SPARSIFY.equals(command.getName())) {
cancel();
}
else if (SparsifyDiskModel.ON_SPARSIFY.equals(command.getName())) {
onSparsify();
}
else if (command == getPlugCommand()) {
plug();
}
else if (command == getUnPlugCommand()) {
confirmUnplug();
}
else if ("OnUnplug".equals(command.getName())) { //$NON-NLS-1$
unplug();
}
else if (command == getChangeQuotaCommand()) {
changeQuota();
} else if (command.getName().equals("onChangeQuota")) { //$NON-NLS-1$
onChangeQuota();
}
}
private boolean isDiskOnBlockDevice(Disk disk) {
if (disk instanceof DiskImage) {
List<StorageType> diskStorageTypes = ((DiskImage) disk).getStorageTypes();
for (StorageType type : diskStorageTypes) {
if (!type.isBlockDomain()) {
return false;
}
}
return true;
}
return false; // Should never happen but we might add other Disk types in the future
}
protected void updateDataCenterVersion() {
AsyncQuery<StoragePool> query = new AsyncQuery<>(storagePool -> setDataCenterVersion(storagePool.getCompatibilityVersion()));
AsyncDataProvider.getInstance().getDataCenterById(query, getEntity().getStoragePoolId());
}
private Version dataCenterVersion;
public Version getDataCenterVersion() {
return dataCenterVersion;
}
public void setDataCenterVersion(Version dataCenterVersion) {
if (dataCenterVersion != null && !dataCenterVersion.equals(this.dataCenterVersion)) {
this.dataCenterVersion = dataCenterVersion;
updateActionAvailability();
}
}
@Override
protected String getListName() {
return "VmDiskListModel"; //$NON-NLS-1$
}
public SystemTreeItemModel getSystemTreeSelectedItem() {
if (getSystemTreeContext() == null) {
return null;
}
return getSystemTreeContext().getSystemTreeSelectedItem();
}
}