package org.ovirt.engine.ui.uicommonweb.models.storage;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.ovirt.engine.core.common.action.MoveOrCopyImageGroupParameters;
import org.ovirt.engine.core.common.action.VdcActionParametersBase;
import org.ovirt.engine.core.common.action.VdcActionType;
import org.ovirt.engine.core.common.businessentities.QuotaEnforcementTypeEnum;
import org.ovirt.engine.core.common.businessentities.StorageDomain;
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.NameableComparator;
import org.ovirt.engine.core.common.businessentities.profiles.DiskProfile;
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.StorageType;
import org.ovirt.engine.core.compat.Guid;
import org.ovirt.engine.ui.uicommonweb.ICommandTarget;
import org.ovirt.engine.ui.uicommonweb.Linq;
import org.ovirt.engine.ui.uicommonweb.UICommand;
import org.ovirt.engine.ui.uicommonweb.dataprovider.AsyncDataProvider;
import org.ovirt.engine.ui.uicommonweb.models.ListModel;
import org.ovirt.engine.ui.uicommonweb.models.vms.DiskModel;
import org.ovirt.engine.ui.uicommonweb.validation.I18NNameValidation;
import org.ovirt.engine.ui.uicommonweb.validation.IValidation;
import org.ovirt.engine.ui.uicommonweb.validation.NotEmptyValidation;
import org.ovirt.engine.ui.uicommonweb.validation.SelectedQuotaValidation;
import org.ovirt.engine.ui.uicompat.PropertyChangedEventArgs;
public abstract class MoveOrCopyDiskModel extends DisksAllocationModel implements ICommandTarget {
private ArrayList<DiskModel> allDisks;
private StoragePool dataCenter;
public ArrayList<DiskModel> getAllDisks() {
return allDisks;
}
public void setAllDisks(ArrayList<DiskModel> value) {
if (allDisks != value) {
allDisks = value;
onPropertyChanged(new PropertyChangedEventArgs("All Disks")); //$NON-NLS-1$
}
}
private ArrayList<DiskImage> diskImages;
public StoragePool getDataCenter() {
return dataCenter;
}
public void setDataCenter(StoragePool dataCenter) {
this.dataCenter = dataCenter;
}
public ArrayList<DiskImage> getDiskImages() {
return diskImages;
}
public void setDiskImages(ArrayList<DiskImage> value) {
if (diskImages != value) {
diskImages = value;
onPropertyChanged(new PropertyChangedEventArgs("Disk Images")); //$NON-NLS-1$
}
}
// Disks that cannot be moved/copied
protected List<String> problematicDisks = new ArrayList<>();
public abstract void init(ArrayList<DiskImage> diskImages);
protected abstract void onInitDisks();
protected abstract void initStorageDomains();
protected abstract VdcActionType getActionType();
protected abstract String getWarning(List<String> disks);
protected abstract String getNoActiveSourceDomainMessage();
protected abstract String getNoActiveTargetDomainMessage();
protected abstract MoveOrCopyImageGroupParameters createParameters(
Guid sourceStorageDomainGuid,
Guid destStorageDomainGuid,
DiskImage disk);
public MoveOrCopyDiskModel() {
setAllDisks(new ArrayList<DiskModel>());
setActiveStorageDomains(new ArrayList<StorageDomain>());
}
protected boolean isAllVmsDown(Map<Boolean, List<VM>> vmsMap) {
if (vmsMap.get(Boolean.TRUE) != null) {
for (VM vm : vmsMap.get(Boolean.TRUE)) {
if (vm.getStatus() != VMStatus.Down) {
return false;
}
}
}
return true;
}
protected void onInitAllDisks(List<? extends Disk> disks) {
for (Disk disk : disks) {
if (disk.getDiskStorageType() == DiskStorageType.IMAGE) {
allDisks.add(DiskModel.diskToModel(disk));
}
}
}
protected void onInitStorageDomains(List<StorageDomain> storages) {
for (StorageDomain storage : storages) {
if (Linq.isDataActiveStorageDomain(storage)) {
getActiveStorageDomains().add(storage);
}
}
Collections.sort(getActiveStorageDomains(), new NameableComparator());
if (!storages.isEmpty()) {
AsyncDataProvider.getInstance().getDataCenterById(new AsyncQuery<>(dataCenter -> {
setDataCenter(dataCenter);
setQuotaEnforcementType(dataCenter.getQuotaEnforcementType());
postInitStorageDomains();
}), storages.get(0).getStoragePoolId());
}
else {
postInitStorageDomains();
}
}
private boolean isDiskValidForStorage(DiskImage disk, StorageDomain storage) {
if (disk.isShareable() && storage.getStorageType() == StorageType.GLUSTERFS) {
return false;
}
return true;
}
protected void postInitStorageDomains() {
for (DiskModel disk : getDisks()) {
DiskImage diskImage = (DiskImage) disk.getDisk();
// Source storage domains
ArrayList<Guid> diskStorageIds = diskImage.getStorageIds();
List<StorageDomain> sourceStorageDomains =
Linq.getStorageDomainsByIds(diskStorageIds, getActiveStorageDomains());
boolean isDiskBasedOnTemplate = !diskImage.getParentId().equals(Guid.Empty);
ArrayList<StorageDomain> destStorageDomains = getDestinationDomains(getActiveStorageDomains(),
sourceStorageDomains,
disk,
isDiskBasedOnTemplate);
// Add prohibition reasons
if (sourceStorageDomains.isEmpty() || destStorageDomains.isEmpty()) {
problematicDisks.add(disk.getAlias().getEntity());
updateChangeability(disk, isDiskBasedOnTemplate,
sourceStorageDomains.isEmpty(), destStorageDomains.isEmpty());
}
// Sort and add storage domains
Collections.sort(destStorageDomains, new NameableComparator());
Collections.sort(sourceStorageDomains, new NameableComparator());
disk.getStorageDomain().setItems(destStorageDomains);
disk.getSourceStorageDomain().setItems(sourceStorageDomains);
addSourceStorageDomainName(disk, sourceStorageDomains);
}
sortDisks();
postCopyOrMoveInit();
}
private ArrayList<StorageDomain> getDestinationDomains(ArrayList<StorageDomain> activeStorageDomains,
List<StorageDomain> sourceActiveStorageDomains, DiskModel diskModel, boolean isDiskBasedOnTemplate) {
DiskImage diskImage = (DiskImage) diskModel.getDisk();
DiskModel templateDisk = null;
if (isDiskBasedOnTemplate) {
templateDisk = getTemplateDiskByVmDisk(diskModel);
}
ArrayList<StorageDomain> destinationDomains = new ArrayList<>();
for (StorageDomain sd : activeStorageDomains) {
// Storage domain destination should not be a domain which the disk is attached to.
if (!allowedStorageDomain(sourceActiveStorageDomains, diskImage, templateDisk, sd)) {
continue;
}
// All conditions are valid for moving the current disk to this domain.
destinationDomains.add(sd);
}
return destinationDomains;
}
protected boolean allowedStorageDomain(List<StorageDomain> sourceActiveStorageDomains, DiskImage diskImage, DiskModel templateDisk, StorageDomain sd) {
// Destination should be in the same pool as the disk.
boolean connectedToSamePool = sd.getStoragePoolId().equals(diskImage.getStoragePoolId());
if (!connectedToSamePool) {
return false;
}
if (!isDomainValidForDiskTemplate(templateDisk, sd)) {
return false;
}
if (!isDiskValidForStorage(diskImage, sd)) {
return false;
}
return true;
}
private boolean isDomainValidForDiskTemplate(DiskModel templateDisk, StorageDomain sd) {
if (templateDisk != null) {
return ((DiskImage) templateDisk.getDisk()).getStorageIds().contains(sd.getId());
}
return true;
}
private void updateChangeability(DiskModel disk, boolean isDiskBasedOnTemplate, boolean noSources, boolean noTargets) {
disk.getStorageDomain().setIsChangeable(!noTargets);
disk.getSourceStorageDomain().setIsChangeable(!noSources);
disk.getSourceStorageDomainName().setIsChangeable(!noSources);
disk.getStorageDomain().setChangeProhibitionReason(isDiskBasedOnTemplate ?
constants.noActiveStorageDomainWithTemplateMsg() : getNoActiveTargetDomainMessage());
disk.getSourceStorageDomain().setChangeProhibitionReason(getNoActiveSourceDomainMessage());
disk.getSourceStorageDomainName().setChangeProhibitionReason(getNoActiveSourceDomainMessage());
}
private void addSourceStorageDomainName(DiskModel disk, List<StorageDomain> sourceStorageDomains) {
String sourceStorageName = sourceStorageDomains.isEmpty() ?
constants.notAvailableLabel() : sourceStorageDomains.get(0).getStorageName();
disk.getSourceStorageDomainName().setEntity(sourceStorageName);
}
protected void postCopyOrMoveInit() {
ICommandTarget target = (ICommandTarget) getEntity();
if (getActiveStorageDomains().isEmpty()) {
setMessage(constants.noStorageDomainAvailableMsg());
UICommand closeCommand = new UICommand("Cancel", target); //$NON-NLS-1$
closeCommand.setTitle(constants.close());
closeCommand.setIsDefault(true);
closeCommand.setIsCancel(true);
getCommands().add(closeCommand);
}
else {
if (!problematicDisks.isEmpty()) {
setMessage(getWarning(problematicDisks));
}
UICommand actionCommand = new UICommand("OnExecute", this); //$NON-NLS-1$
actionCommand.setTitle(constants.ok());
actionCommand.setIsDefault(true);
getCommands().add(actionCommand);
UICommand cancelCommand = new UICommand("Cancel", target); //$NON-NLS-1$
cancelCommand.setTitle(constants.cancel());
cancelCommand.setIsCancel(true);
getCommands().add(cancelCommand);
}
stopProgress();
}
protected DiskModel getTemplateDiskByVmDisk(DiskModel vmdisk) {
for (DiskModel disk : getAllDisks()) {
if (((DiskImage) disk.getDisk()).getImageId().equals(((DiskImage) vmdisk.getDisk()).getParentId())) {
return disk;
}
}
return null;
}
protected final void onExecute() {
if (this.getProgress() != null) {
return;
}
if (!this.validate()) {
return;
}
doExecute();
}
protected void doExecute() {
startProgress();
}
protected ArrayList<VdcActionParametersBase> getParameters() {
ArrayList<VdcActionParametersBase> parameters = new ArrayList<>();
for (DiskModel diskModel : getDisks()) {
StorageDomain destStorageDomain = diskModel.getStorageDomain().getSelectedItem();
StorageDomain sourceStorageDomain =
diskModel.getSourceStorageDomain().getSelectedItem();
Guid sourceStorageDomainGuid = sourceStorageDomain != null ? sourceStorageDomain.getId() : Guid.Empty;
DiskImage disk = (DiskImage) diskModel.getDisk();
DiskProfile diskProfile = diskModel.getDiskProfile().getSelectedItem();
disk.setDiskProfileId(diskProfile != null ? diskProfile.getId() : null);
disk.setDiskAlias(diskModel.getAlias().getEntity());
if (diskModel.getQuota().getSelectedItem() != null) {
disk.setQuotaId(diskModel.getQuota().getSelectedItem().getId());
}
if (destStorageDomain == null || sourceStorageDomain == null) {
continue;
}
Guid destStorageDomainGuid = destStorageDomain.getId();
addMoveOrCopyParameters(parameters,
sourceStorageDomainGuid,
destStorageDomainGuid,
disk);
}
return parameters;
}
protected void addMoveOrCopyParameters(ArrayList<VdcActionParametersBase> parameters,
Guid sourceStorageDomainGuid,
Guid destStorageDomainGuid,
DiskImage disk) {
MoveOrCopyImageGroupParameters params = createParameters(sourceStorageDomainGuid, destStorageDomainGuid, disk);
params.setQuotaId(disk.getQuotaId());
params.setDiskProfileId(disk.getDiskProfileId());
params.setNewAlias(disk.getDiskAlias());
parameters.add(params);
}
@Override
public void executeCommand(UICommand command) {
super.executeCommand(command);
onExecute();
}
public boolean validate() {
boolean quotaValidated = true;
if (getQuotaEnforcementType() == QuotaEnforcementTypeEnum.DISABLED
|| getQuotaEnforcementType() == QuotaEnforcementTypeEnum.SOFT_ENFORCEMENT) {
quotaValidated = false;
}
boolean isValid = true;
for (DiskModel diskModel : getDisks()) {
if (quotaValidated) {
diskModel.getQuota().validateSelectedItem(new IValidation[] { new SelectedQuotaValidation() });
isValid &= diskModel.getQuota().getIsValid();
}
diskModel.getAlias().validateEntity(new IValidation[] { new NotEmptyValidation(), new I18NNameValidation() });
isValid &= diskModel.getAlias().getIsValid();
}
return isValid;
}
protected void cancel() {
stopProgress();
((ListModel) getEntity()).setWindow(null);
}
}