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 java.util.function.Predicate; import java.util.stream.Collectors; import org.ovirt.engine.core.common.businessentities.ActionGroup; import org.ovirt.engine.core.common.businessentities.BusinessEntitiesDefinitions; import org.ovirt.engine.core.common.businessentities.Quota; import org.ovirt.engine.core.common.businessentities.QuotaEnforcementTypeEnum; import org.ovirt.engine.core.common.businessentities.StorageDomain; import org.ovirt.engine.core.common.businessentities.StorageDomainStatus; import org.ovirt.engine.core.common.businessentities.StoragePool; import org.ovirt.engine.core.common.businessentities.VDS; import org.ovirt.engine.core.common.businessentities.VDSStatus; 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.CinderDisk; import org.ovirt.engine.core.common.businessentities.storage.CinderVolumeType; 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.DiskInterface; import org.ovirt.engine.core.common.businessentities.storage.DiskStorageType; import org.ovirt.engine.core.common.businessentities.storage.LunDisk; import org.ovirt.engine.core.common.businessentities.storage.PropagateErrors; import org.ovirt.engine.core.common.businessentities.storage.ScsiGenericIO; 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.VdcQueryReturnValue; import org.ovirt.engine.core.common.queries.VdcQueryType; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.compat.Version; import org.ovirt.engine.ui.frontend.Frontend; 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.help.HelpTag; import org.ovirt.engine.ui.uicommonweb.models.ConfirmationModel; import org.ovirt.engine.ui.uicommonweb.models.EntityModel; import org.ovirt.engine.ui.uicommonweb.models.HasEntity; import org.ovirt.engine.ui.uicommonweb.models.ListModel; import org.ovirt.engine.ui.uicommonweb.models.SystemTreeItemModel; import org.ovirt.engine.ui.uicommonweb.models.storage.SanStorageModelBase; import org.ovirt.engine.ui.uicommonweb.models.storage.StorageModel; import org.ovirt.engine.ui.uicommonweb.validation.I18NNameValidation; import org.ovirt.engine.ui.uicommonweb.validation.IValidation; import org.ovirt.engine.ui.uicommonweb.validation.LengthValidation; import org.ovirt.engine.ui.uicommonweb.validation.NotEmptyQuotaValidation; import org.ovirt.engine.ui.uicommonweb.validation.NotEmptyValidation; import org.ovirt.engine.ui.uicommonweb.validation.SpecialAsciiI18NOrNoneValidation; import org.ovirt.engine.ui.uicompat.ConstantsManager; import org.ovirt.engine.ui.uicompat.Event; import org.ovirt.engine.ui.uicompat.EventArgs; import org.ovirt.engine.ui.uicompat.IFrontendActionAsyncCallback; import org.ovirt.engine.ui.uicompat.UIConstants; public abstract class AbstractDiskModel extends DiskModel { protected static final UIConstants constants = ConstantsManager.getInstance().getConstants(); private EntityModel<Boolean> isWipeAfterDelete; private EntityModel<Boolean> isShareable; private EntityModel<Boolean> isPlugged; private EntityModel<Boolean> isReadOnly; private EntityModel<Boolean> isDirectLunDiskAvaialable; private EntityModel<Boolean> isUsingScsiReservation; private EntityModel<Boolean> isScsiPassthrough; private EntityModel<Boolean> isSgIoUnfiltered; private EntityModel<String> sizeExtend; private EntityModel<DiskStorageType> diskStorageType; private EntityModel<Boolean> isModelDisabled; private ListModel<StorageType> storageType; private ListModel<VDS> host; private ListModel<StoragePool> dataCenter; private ListModel<String> cinderVolumeType; private SanStorageModelBase sanStorageModelBase; private boolean previousIsQuotaAvailable; private SystemTreeItemModel systemTreeSelectedItem; private UICommand cancelCommand; private StorageModel storageModel; public EntityModel<Boolean> getIsWipeAfterDelete() { return isWipeAfterDelete; } public void setIsWipeAfterDelete(EntityModel<Boolean> isWipeAfterDelete) { this.isWipeAfterDelete = isWipeAfterDelete; } public EntityModel<Boolean> getIsShareable() { return isShareable; } public void setIsShareable(EntityModel<Boolean> isShareable) { this.isShareable = isShareable; } public EntityModel<Boolean> getIsPlugged() { return isPlugged; } public void setIsPlugged(EntityModel<Boolean> isPlugged) { this.isPlugged = isPlugged; } public EntityModel<Boolean> getIsReadOnly() { return isReadOnly; } public void setIsReadOnly(EntityModel<Boolean> isReadOnly) { this.isReadOnly = isReadOnly; } public EntityModel<Boolean> getIsDirectLunDiskAvaialable() { return isDirectLunDiskAvaialable; } public void setIsDirectLunDiskAvaialable(EntityModel<Boolean> isDirectLunDiskAvaialable) { this.isDirectLunDiskAvaialable = isDirectLunDiskAvaialable; } public EntityModel<Boolean> getIsUsingScsiReservation() { return isUsingScsiReservation; } public void setIsUsingScsiReservation(EntityModel<Boolean> isUsingScsiReservation) { this.isUsingScsiReservation = isUsingScsiReservation; } public EntityModel<Boolean> getIsScsiPassthrough() { return isScsiPassthrough; } public void setIsScsiPassthrough(EntityModel<Boolean> isScsiPassthrough) { this.isScsiPassthrough = isScsiPassthrough; } public EntityModel<Boolean> getIsSgIoUnfiltered() { return isSgIoUnfiltered; } public void setIsSgIoUnfiltered(EntityModel<Boolean> isSgIoUnfiltered) { this.isSgIoUnfiltered = isSgIoUnfiltered; } public ListModel<StorageType> getStorageType() { return storageType; } public void setStorageType(ListModel<StorageType> storageType) { this.storageType = storageType; } public ListModel<VDS> getHost() { return host; } public void setHost(ListModel<VDS> host) { this.host = host; } public ListModel<StoragePool> getDataCenter() { return dataCenter; } public void setDataCenter(ListModel<StoragePool> dataCenter) { this.dataCenter = dataCenter; } public ListModel<String> getCinderVolumeType() { return cinderVolumeType; } public void setCinderVolumeType(ListModel<String> cinderVolumeType) { this.cinderVolumeType = cinderVolumeType; } public SanStorageModelBase getSanStorageModelBase() { return sanStorageModelBase; } public void setSanStorageModelBase(SanStorageModelBase sanStorageModelBase) { this.sanStorageModelBase = sanStorageModelBase; } public SystemTreeItemModel getSystemTreeSelectedItem() { return systemTreeSelectedItem; } public void setSystemTreeSelectedItem(SystemTreeItemModel systemTreeSelectedItem) { this.systemTreeSelectedItem = systemTreeSelectedItem; } public EntityModel<String> getSizeExtend() { return sizeExtend; } public void setSizeExtend(EntityModel<String> sizeExtend) { this.sizeExtend = sizeExtend; } public EntityModel<DiskStorageType> getDiskStorageType() { return diskStorageType; } public void setDiskStorageType(EntityModel<DiskStorageType> diskStorageType) { this.diskStorageType = diskStorageType; } private EntityModel<Boolean> isVirtioScsiEnabled; public EntityModel<Boolean> getIsVirtioScsiEnabled() { return isVirtioScsiEnabled; } public void setIsVirtioScsiEnabled(EntityModel<Boolean> virtioScsiEnabled) { this.isVirtioScsiEnabled = virtioScsiEnabled; } public EntityModel<Boolean> getIsModelDisabled() { return isModelDisabled; } public void setIsModelDisabled(EntityModel<Boolean> isModelDisabled) { this.isModelDisabled = isModelDisabled; } @Override public UICommand getCancelCommand() { return cancelCommand; } public void setCancelCommand(UICommand cancelCommand) { this.cancelCommand = cancelCommand; } public AbstractDiskModel() { setSizeExtend(new EntityModel<String>()); getSizeExtend().setEntity("0"); //$NON-NLS-1$ setIsWipeAfterDelete(new EntityModel<Boolean>()); getIsWipeAfterDelete().setEntity(false); getIsWipeAfterDelete().getEntityChangedEvent().addListener(this); getPassDiscard().getEntityChangedEvent().addListener(this); setIsShareable(new EntityModel<Boolean>()); getIsShareable().setEntity(false); setIsPlugged(new EntityModel<Boolean>()); getIsPlugged().setEntity(true); getIsPlugged().setIsAvailable(false); setIsReadOnly(new EntityModel<Boolean>()); getIsReadOnly().setEntity(false); getIsReadOnly().getEntityChangedEvent().addListener(this); setIsUsingScsiReservation(new EntityModel<Boolean>()); getIsUsingScsiReservation().setEntity(false); setIsScsiPassthrough(new EntityModel<Boolean>()); getIsScsiPassthrough().setIsAvailable(false); getIsScsiPassthrough().setEntity(true); getIsScsiPassthrough().getEntityChangedEvent().addListener(this); setIsSgIoUnfiltered(new EntityModel<Boolean>()); getIsSgIoUnfiltered().setIsAvailable(false); getIsSgIoUnfiltered().setEntity(false); getIsSgIoUnfiltered().getEntityChangedEvent().addListener(this); setDiskStorageType(new EntityModel<DiskStorageType>()); getDiskStorageType().setEntity(DiskStorageType.IMAGE); getDiskStorageType().getEntityChangedEvent().addListener(this); setIsDirectLunDiskAvaialable(new EntityModel<Boolean>()); getIsDirectLunDiskAvaialable().setEntity(true); setDataCenter(new ListModel<StoragePool>()); getDataCenter().setIsAvailable(false); getDataCenter().getSelectedItemChangedEvent().addListener(this); getStorageDomain().getSelectedItemChangedEvent().addListener(this); setStorageType(new ListModel<StorageType>()); getStorageType().setIsAvailable(false); getStorageType().setItems(AsyncDataProvider.getInstance().getStorageTypeList()); getStorageType().getSelectedItemChangedEvent().addListener(this); setHost(new ListModel<VDS>()); getHost().setIsAvailable(false); getVolumeType().getSelectedItemChangedEvent().addListener(this); getDiskInterface().getSelectedItemChangedEvent().addListener(this); setIsVirtioScsiEnabled(new EntityModel<Boolean>()); setCinderVolumeType(new ListModel<String>()); getCinderVolumeType().setIsAvailable(false); setIsModelDisabled(new EntityModel<Boolean>(false)); } public abstract boolean getIsNew(); public boolean getIsFloating() { return getVm() == null; } protected abstract boolean isDatacenterAvailable(StoragePool dataCenter); protected abstract DiskImage getDiskImage(); protected abstract LunDisk getLunDisk(); protected abstract CinderDisk getCinderDisk(); public void setDefaultInterface() { Guid vmId = getVmId(); if (Guid.isNullOrEmpty(vmId) || getDisk() == null) { boolean virtioScsiEnabled = Boolean.TRUE.equals(getIsVirtioScsiEnabled().getEntity()); getDiskInterface().setSelectedItem(virtioScsiEnabled ? DiskInterface.VirtIO_SCSI : DiskInterface.VirtIO); } else { getDiskInterface().setSelectedItem(getDisk().getDiskVmElementForVm(vmId).getDiskInterface()); } } protected abstract void updateVolumeType(StorageType storageType); public boolean isEditEnabled() { return (getIsFloating() || getIsNew() || getVm().isDown() || !getDisk().getPlugged()) && getIsChangable(); } @Override public void initialize() { commonInitialize(); } public void initialize(List<DiskModel> currentDisks) { commonInitialize(); updateBootableFrom(currentDisks != null ? currentDisks : new ArrayList<DiskModel>()); } protected void commonInitialize() { super.initialize(); // Create and set commands UICommand onSaveCommand = new UICommand("OnSave", this); //$NON-NLS-1$ onSaveCommand.setTitle(constants.ok()); onSaveCommand.setIsDefault(true); getCommands().add(onSaveCommand); getCommands().add(getCancelCommand()); // Update data if (getVm() != null) { updateBootableDiskAvailable(); getIsUsingScsiReservation().setIsAvailable(true); } updateDatacenters(); } protected void updateStorageDomains(final StoragePool datacenter) { AsyncDataProvider.getInstance().getPermittedStorageDomainsByStoragePoolId(new AsyncQuery<>(storageDomains -> { Predicate<StorageDomain> domainByDiskType; switch (getDiskStorageType().getEntity()) { case IMAGE: domainByDiskType = d -> d.getStorageDomainType().isDataDomain(); break; case CINDER: domainByDiskType = d -> d.getStorageType() == StorageType.CINDER; break; default: domainByDiskType = s -> true; } List<StorageDomain> filteredStorageDomains = storageDomains.stream() .filter(domainByDiskType) .filter(d -> d.getStatus() == StorageDomainStatus.Active) .sorted(new NameableComparator()) .collect(Collectors.toList()); StorageDomain storage = Linq.firstOrNull(filteredStorageDomains); getStorageDomain().setItems(filteredStorageDomains, storage); if (storage == null) { switch (getDiskStorageType().getEntity()) { case IMAGE: setMessage(constants.noActiveStorageDomainsInDC()); getIsModelDisabled().setEntity(true); break; case CINDER: setMessage(constants.noCinderStorageDomainsInDC()); getIsModelDisabled().setEntity(true); break; } } updatePassDiscardAvailability(); }), datacenter.getId(), ActionGroup.CREATE_DISK); } private void updateHosts(StoragePool datacenter) { AsyncDataProvider.getInstance().getHostListByDataCenter(new AsyncQuery<>(hosts -> { ArrayList<VDS> filteredHosts = new ArrayList<>(); for (VDS host : hosts) { if (isHostAvailable(host)) { filteredHosts.add(host); } } Collections.sort(filteredHosts, new NameableComparator()); getHost().setItems(filteredHosts); }), datacenter.getId()); } private void updateDatacenters() { boolean isInVm = getVm() != null; getDataCenter().setIsAvailable(!isInVm); setMessage(""); //$NON-NLS-1$ getIsModelDisabled().setEntity(false); if (isInVm) { AsyncDataProvider.getInstance().getDataCenterById(new AsyncQuery<>(dataCenter -> { ArrayList<StoragePool> dataCenters = new ArrayList<>(); if (isDatacenterAvailable(dataCenter)) { dataCenters.add(dataCenter); } getDataCenter().setItems(dataCenters, Linq.firstOrNull(dataCenters)); if (dataCenters.isEmpty()) { setMessage(constants.relevantDCnotActive()); getIsModelDisabled().setEntity(true); } }), getVm().getStoragePoolId()); updateBootableDiskAvailable(); } else { AsyncDataProvider.getInstance().getDataCenterList(new AsyncQuery<>(dataCenters -> { ArrayList<StoragePool> filteredDataCenters = new ArrayList<>(); for (StoragePool dataCenter : dataCenters) { if (isDatacenterAvailable(dataCenter)) { filteredDataCenters.add(dataCenter); } } getDataCenter().setItems(filteredDataCenters); if (filteredDataCenters.isEmpty()) { setMessage(constants.noActiveDataCenters()); getIsModelDisabled().setEntity(true); } })); } } protected void updateBootableDiskAvailable() { AsyncDataProvider.getInstance().getVmDiskList(new AsyncQuery<>(disks -> updateCanSetBoot(disks)), getVm().getId()); } public void updateCanSetBoot(List<Disk> vmDisks) { getIsBootable().setIsChangeable(true); if (getDisk() == null || !getDisk().isDiskSnapshot()) { for (Disk disk : vmDisks) { if (disk.getDiskVmElementForVm(getVmId()).isBoot() && !disk.equals(getDisk())) { getIsBootable().setEntity(false); if (!disk.isDiskSnapshot()) { getIsBootable().setChangeProhibitionReason(constants.onlyOneBootableDisk()); getIsBootable().setIsChangeable(false); break; } } } } } public void updateBootableFrom(List<DiskModel> vmDisks) { getIsBootable().setIsChangeable(true); if (getDisk() == null || !getDisk().isDiskSnapshot()) { for (DiskModel disk : vmDisks) { if (disk.getDiskVmElement().isBoot() && !disk.getDisk().equals(getDisk())) { getIsBootable().setEntity(false); if (!disk.getDisk().isDiskSnapshot()) { getIsBootable().setChangeProhibitionReason(constants.onlyOneBootableDisk()); getIsBootable().setIsChangeable(false); break; } } } } } private void updateShareableDiskEnabled() { getIsShareable().setChangeProhibitionReason(constants.shareableDiskNotSupported()); getIsShareable().setIsChangeable(isEditEnabled()); } private void updateDirectLunDiskEnabled() { if (getDiskStorageType().getEntity() != DiskStorageType.LUN) { return; } getIsDirectLunDiskAvaialable().setEntity(true); setMessage(""); //$NON-NLS-1$ getIsModelDisabled().setEntity(false); } private void updateShareable(VolumeType volumeType, StorageType storageType) { if (storageType.isBlockDomain() && volumeType == VolumeType.Sparse) { getIsShareable().setChangeProhibitionReason(constants.shareableDiskNotSupportedByConfiguration()); getIsShareable().setIsChangeable(false); getIsShareable().setEntity(false); } else { getIsShareable().setIsChangeable(isEditEnabled()); } } public void updateInterface(final Version clusterVersion) { if (getVm() != null) { AsyncDataProvider.getInstance().isVirtioScsiEnabledForVm(new AsyncQuery<>(r -> { getIsVirtioScsiEnabled().setEntity(Boolean.TRUE.equals(r)); updateInterfaceList(clusterVersion); }), getVm().getId()); } else { setInterfaces(AsyncDataProvider.getInstance().getDiskInterfaceList()); } } public void updateInterfaceList(final Version clusterVersion) { AsyncDataProvider.getInstance().getDiskInterfaceList(getVm().getOs(), clusterVersion, new AsyncQuery<>( diskInterfaces -> { if (Boolean.FALSE.equals(getIsVirtioScsiEnabled().getEntity())) { diskInterfaces.remove(DiskInterface.VirtIO_SCSI); } setInterfaces(diskInterfaces); })); } private void setInterfaces(List<DiskInterface> diskInterfaces) { getDiskInterface().setItems(diskInterfaces); setDefaultInterface(); } protected void updateCinderVolumeTypes() { StorageDomain storageDomain = getStorageDomain().getSelectedItem(); if (storageDomain == null || storageDomain.getStorageType() != StorageType.CINDER) { return; } AsyncDataProvider.getInstance().getCinderVolumeTypesList(new AsyncQuery<>(cinderVolumeTypes -> { List<String> volumeTypesNames = new ArrayList<>(); for (CinderVolumeType cinderVolumeType : cinderVolumeTypes) { volumeTypesNames.add(cinderVolumeType.getName()); } getCinderVolumeType().setItems(volumeTypesNames); }), storageDomain.getId()); } private void updateDiskProfiles(StoragePool selectedItem) { StorageDomain storageDomain = getStorageDomain().getSelectedItem(); if (storageDomain == null) { return; } Frontend.getInstance().runQuery(VdcQueryType.GetDiskProfilesByStorageDomainId, new IdQueryParameters(storageDomain.getId()), new AsyncQuery<VdcQueryReturnValue>(value -> setDiskProfilesList((List<DiskProfile>) value.getReturnValue()))); } private void setDiskProfilesList(List<DiskProfile> diskProfiles) { // set disk profiles if (diskProfiles != null && !diskProfiles.isEmpty()) { getDiskProfile().setItems(diskProfiles); } // handle disk profile selected item Guid defaultProfileId = (getDisk() != null && !getIsNew() && getDisk().getDiskStorageType() == DiskStorageType.IMAGE) ? ((DiskImage) getDisk()).getDiskProfileId() : null; if (defaultProfileId != null) { for (DiskProfile profile : diskProfiles) { if (profile.getId().equals(defaultProfileId)) { getDiskProfile().setSelectedItem(profile); return; } } // set dummy disk profile (if not fetched because of permissions, and it's attached to disk. DiskProfile diskProfile = new DiskProfile(); diskProfile.setId(defaultProfileId); if (getDisk() != null) { diskProfile.setName(getDiskImage().getDiskProfileName()); } diskProfiles.add(diskProfile); getDiskProfile().setItems(diskProfiles); getDiskProfile().setSelectedItem(diskProfile); } } private void updateQuota(StoragePool datacenter) { if (datacenter.getQuotaEnforcementType().equals(QuotaEnforcementTypeEnum.DISABLED) || !getDiskStorageType().getEntity().isInternal()) { getQuota().setIsAvailable(false); return; } getQuota().setIsAvailable(true); StorageDomain storageDomain = getStorageDomain().getSelectedItem(); if (storageDomain == null) { return; } final Guid diskQuota = getDisk() != null ? ((DiskImage) getDisk()).getQuotaId() : null; final Guid vmQuota = getVm() != null ? getVm().getQuotaId() : null; final Guid defaultQuota = diskQuota != null ? diskQuota : vmQuota; AsyncDataProvider.getInstance().getAllRelevantQuotasForStorageSorted(new AsyncQuery<>( quotaList -> { if (quotaList != null && !quotaList.isEmpty()) { getQuota().setItems(quotaList); // If list contains default quota, return if (quotaList.get(0).getId().equals(defaultQuota)) { return; } } if (diskQuota != null) { Quota quota = new Quota(); quota.setId(diskQuota); quota.setQuotaName(getDiskImage().getQuotaName()); if (quotaList == null) { quotaList = new ArrayList<>(); } quotaList.add(quota); getQuota().setItems(quotaList); getQuota().setSelectedItem(quota); } }), storageDomain.getId(), defaultQuota); } private boolean isHostAvailable(VDS host) { boolean isStatusUp = host.getStatus() == VDSStatus.Up; return isStatusUp; } protected void diskStorageType_EntityChanged() { boolean isInVm = getVm() != null; boolean isDiskImage = getDiskStorageType().getEntity() == DiskStorageType.IMAGE; boolean isLunDisk = getDiskStorageType().getEntity() == DiskStorageType.LUN; boolean isCinderDisk = getDiskStorageType().getEntity() == DiskStorageType.CINDER; getSize().setIsAvailable(isDiskImage || isCinderDisk); getSizeExtend().setIsAvailable((isDiskImage || isCinderDisk) && !getIsNew()); getStorageDomain().setIsAvailable(isDiskImage || isCinderDisk); getVolumeType().setIsAvailable(isDiskImage); getIsWipeAfterDelete().setIsAvailable(isDiskImage); updatePassDiscardChangeability(); updateWipeAfterDeleteChangeability(); getHost().setIsAvailable(isLunDisk); getStorageType().setIsAvailable(isLunDisk); getDataCenter().setIsAvailable(!isInVm); getDiskProfile().setIsAvailable(isDiskImage); getCinderVolumeType().setIsAvailable(isCinderDisk); if (!isDiskImage) { previousIsQuotaAvailable = getQuota().getIsAvailable(); } getQuota().setIsAvailable(isDiskImage ? previousIsQuotaAvailable : false); setIsChangeable(true); updateDatacenters(); } protected void volumeType_SelectedItemChanged() { if (getVolumeType().getSelectedItem() == null || getDataCenter().getSelectedItem() == null || getStorageDomain().getSelectedItem() == null) { return; } VolumeType volumeType = getVolumeType().getSelectedItem(); StorageType storageType = getStorageDomain().getSelectedItem().getStorageType(); updateShareable(volumeType, storageType); } private void DiskInterface_SelectedItemChanged() { boolean isLunDisk = getDiskStorageType().getEntity() == DiskStorageType.LUN; DiskInterface diskInterface = getDiskInterface().getSelectedItem(); getIsSgIoUnfiltered().setIsAvailable(isLunDisk && DiskInterface.VirtIO_SCSI.equals(diskInterface)); getIsScsiPassthrough().setIsAvailable(isLunDisk && DiskInterface.VirtIO_SCSI.equals(diskInterface)); getIsUsingScsiReservation().setIsAvailable(isLunDisk && DiskInterface.VirtIO_SCSI.equals(diskInterface)); getIsReadOnly().setIsAvailable(!DiskInterface.IDE.equals(diskInterface)); updatePassDiscardAvailability(); updateScsiPassthroughChangeability(); updateScsiReservationChangeability(); updateReadOnlyChangeability(); updatePlugChangeability(); updatePassDiscardChangeability(); updateWipeAfterDeleteChangeability(); } protected void updatePassDiscardAvailability() { if (!AsyncDataProvider.getInstance().isPassDiscardFeatureSupported( getDataCenter().getSelectedItem().getCompatibilityVersion())) { getPassDiscard().setIsAvailable(false); return; } if (getIsFloating()) { getPassDiscard().setIsAvailable(false); } else { DiskInterface selectedInterface = getDiskInterface().getSelectedItem(); DiskStorageType selectedDiskStorageType = getDiskStorageType().getEntity(); boolean isApplicableInterface = selectedInterface == DiskInterface.VirtIO_SCSI || selectedInterface == DiskInterface.IDE; boolean isApplicableDiskStorageType = selectedDiskStorageType == DiskStorageType.LUN || selectedDiskStorageType == DiskStorageType.IMAGE; boolean isApplicableStorageType = selectedDiskStorageType == DiskStorageType.LUN || (getStorageDomain().getSelectedItem() != null && getStorageDomain().getSelectedItem().getStorageType().isInternal()); if (isApplicableInterface && isApplicableDiskStorageType && isApplicableStorageType) { getPassDiscard().setIsAvailable(true); if (!getIsNew()) { getPassDiscard().setEntity(getDiskVmElement().isPassDiscard()); } } else { // Reset PassDiscard's availability and value. getPassDiscard().setIsAvailable(false); getPassDiscard().setEntity(false); } } } protected void updatePassDiscardChangeability() { if (isEditEnabled() && getPassDiscard().getIsAvailable()) { if (getDiskStorageType().getEntity() == DiskStorageType.LUN) { updatePassDiscardChangeabilityForDirectLun(); } else if (getDiskStorageType().getEntity() == DiskStorageType.IMAGE) { updatePassDiscardChangeabilityForDiskImage(); } } } private void updatePassDiscardChangeabilityForDirectLun() { // New direct lun. if (getSanStorageModelBase() != null && getSanStorageModelBase().getAddedLuns() != null) { if (getSanStorageModelBase().getAddedLuns().isEmpty()) { getPassDiscard().setIsChangeable(false); } else { getPassDiscard().setIsChangeable( getSanStorageModelBase().getAddedLuns().get(0).getEntity().supportsDiscard(), constants.discardIsNotSupportedByUnderlyingStorage()); if (!getPassDiscard().getIsChangable()) { getPassDiscard().setEntity(false); } } } else if (getLunDisk() != null) { // Edit an existing direct lun. getPassDiscard().setIsChangeable(getLunDisk().getLun().supportsDiscard(), constants.discardIsNotSupportedByUnderlyingStorage()); } } private void updatePassDiscardChangeabilityForDiskImage() { if (getStorageDomain().getSelectedItem() == null) { return; } if (getStorageDomain().getSelectedItem().getStorageType().isFileDomain()) { getPassDiscard().setIsChangeable(true); } else if (getStorageDomain().getSelectedItem().getStorageType().isBlockDomain()) { if (!getStorageDomain().getSelectedItem().getSupportsDiscard()) { getPassDiscard().setIsChangeable(false, constants.discardIsNotSupportedByUnderlyingStorage()); getPassDiscard().setEntity(false); } else { getPassDiscard().setIsChangeable(!getIsWipeAfterDelete().getEntity() || getStorageDomain().getSelectedItem().getSupportsDiscardZeroesData(), constants.theUnderlyingStorageDoesNotSupportDiscardWhenWipeAfterDeleteIsEnabled()); if (!getPassDiscard().getIsChangable()) { getPassDiscard().setEntity(false); } } } } protected void updateScsiPassthroughChangeability() { getIsScsiPassthrough().setIsChangeable(!getIsReadOnly().getEntity() && isEditEnabled()); getIsScsiPassthrough().setChangeProhibitionReason(constants.cannotEnableScsiPassthroughForLunReadOnlyDisk()); updateSgIoUnfilteredChangeability(); } protected void updateSgIoUnfilteredChangeability() { if (!getIsScsiPassthrough().getEntity()) { getIsSgIoUnfiltered().setChangeProhibitionReason(constants.cannotEnableSgioWhenScsiPassthroughDisabled()); getIsSgIoUnfiltered().setIsChangeable(false); getIsSgIoUnfiltered().setEntity(false); return; } if (isEditEnabled()) { getIsSgIoUnfiltered().setChangeProhibitionReason(null); } getIsSgIoUnfiltered().setIsChangeable(isEditEnabled()); } protected void updateScsiReservationChangeability() { boolean isSgioUnfiltered = getIsSgIoUnfiltered().getEntity(); if (getVm() != null) { if (isSgioUnfiltered) { getIsUsingScsiReservation().setIsChangeable(true); } else { getIsUsingScsiReservation().setIsChangeable(false); getIsUsingScsiReservation().setEntity(false); } } else { getIsUsingScsiReservation().setIsAvailable(false); getIsUsingScsiReservation().setEntity(false); getIsUsingScsiReservation().setIsChangeable(false); } } protected void updateReadOnlyChangeability() { if (getVm() == null) { // read-only is a characteristic of a VM device, not a disk getIsReadOnly().setIsAvailable(false); getIsReadOnly().setEntity(false); getIsReadOnly().setIsChangeable(false); return; } DiskInterface diskInterface = getDiskInterface().getSelectedItem(); if (diskInterface == DiskInterface.IDE) { getIsReadOnly().setEntity(false); return; } boolean isDirectLUN = getDiskStorageType().getEntity() == DiskStorageType.LUN; boolean isScsiPassthrough = getIsScsiPassthrough().getEntity(); if (diskInterface == DiskInterface.VirtIO_SCSI && isDirectLUN && isScsiPassthrough) { getIsReadOnly().setChangeProhibitionReason(constants.cannotEnableReadonlyWhenScsiPassthroughEnabled()); getIsReadOnly().setIsChangeable(false); getIsReadOnly().setEntity(false); return; } if (isVmAttachedToPool() && !getIsNew()) { getIsReadOnly().setIsChangeable(false); } else { getIsReadOnly().setIsChangeable(isEditEnabled()); } if (!getIsNew()) { getIsReadOnly().setEntity(getDiskVmElement().isReadOnly()); } } protected void updateWipeAfterDeleteChangeability() { if (!isVmAttachedToPool()) { getIsWipeAfterDelete().setIsChangeable( !(getDiskStorageType().getEntity() == DiskStorageType.IMAGE && getStorageDomain().getSelectedItem() != null && getStorageDomain().getSelectedItem().getStorageType().isBlockDomain() && getPassDiscard().getIsChangable() && getPassDiscard().getEntity() && !getStorageDomain().getSelectedItem().getSupportsDiscardZeroesData()), constants.theUnderlyingStorageDoesNotSupportDiscardWhenWipeAfterDeleteIsEnabled()); } else { getIsWipeAfterDelete().setIsChangeable(false); } } private void updatePlugChangeability() { if (getVm() == null) { // No point in updating plug to VM if there's no VM return; } DiskInterface diskInterface = getDiskInterface().getSelectedItem(); boolean isVmRunning = getVm() != null && getVm().getStatus() != VMStatus.Down; if (DiskInterface.IDE.equals(diskInterface) && isVmRunning) { getIsPlugged().setChangeProhibitionReason(constants.cannotHotPlugDiskWithIdeInterface()); getIsPlugged().setIsChangeable(false); getIsPlugged().setEntity(false); } else { if (!canDiskBePlugged(getVm())) { getIsPlugged().setChangeProhibitionReason(constants.cannotPlugDiskIncorrectVmStatus()); getIsPlugged().setIsChangeable(false); getIsPlugged().setEntity(false); } else { getIsPlugged().setIsChangeable(isEditEnabled()); getIsPlugged().setEntity(true); } } } private void updateDiskSize(DiskImage diskImage) { long sizeToAddInGigabytes = Long.parseLong(getSizeExtend().getEntity()); if (sizeToAddInGigabytes > 0) { diskImage.setSizeInGigabytes(diskImage.getSizeInGigabytes() + sizeToAddInGigabytes); } } private boolean canDiskBePlugged(VM vm) { return vm.getStatus() == VMStatus.Up || vm.getStatus() == VMStatus.Down || vm.getStatus() == VMStatus.Paused; } private boolean isVmAttachedToPool() { return getVm() != null && getVm().getVmPoolId() != null; } protected void datacenter_SelectedItemChanged() { StoragePool datacenter = getDataCenter().getSelectedItem(); boolean isInVm = getVm() != null; if (datacenter == null) { return; } setMessage(null); getIsModelDisabled().setEntity(false); updateShareableDiskEnabled(); updateDirectLunDiskEnabled(); updateInterface(isInVm ? getVm().getCompatibilityVersion() : null); switch (getDiskStorageType().getEntity()) { case IMAGE: case CINDER: updateStorageDomains(datacenter); break; default: break; } if (performUpdateHosts()) { updateHosts(datacenter); } } private void storageDomain_SelectedItemChanged() { StorageDomain selectedStorage = getStorageDomain().getSelectedItem(); if (selectedStorage != null) { updateVolumeType(selectedStorage.getStorageType()); if (getIsNew()) { getIsWipeAfterDelete().setEntity(selectedStorage.getWipeAfterDelete()); } } updateQuota(getDataCenter().getSelectedItem()); updateDiskProfiles(getDataCenter().getSelectedItem()); updateCinderVolumeTypes(); updatePassDiscardAvailability(); updatePassDiscardChangeability(); updateWipeAfterDeleteChangeability(); } public boolean validate() { getDescription().validateEntity(new IValidation[] { new SpecialAsciiI18NOrNoneValidation(), new LengthValidation(BusinessEntitiesDefinitions.DISK_DESCRIPTION_MAX_SIZE)}); getAlias().validateEntity(getDiskAliasValidations()); StoragePool dataCenter = getDataCenter().getSelectedItem(); if (dataCenter != null && dataCenter.getQuotaEnforcementType() == QuotaEnforcementTypeEnum.HARD_ENFORCEMENT) { getQuota().validateSelectedItem(new IValidation[] { new NotEmptyQuotaValidation() }); } if (getCinderVolumeType().getIsAvailable()) { getCinderVolumeType().validateSelectedItem(new IValidation[]{new NotEmptyValidation()}); } return getAlias().getIsValid() && getDescription().getIsValid() && getQuota().getIsValid() && getDiskInterface().getIsValid() && getCinderVolumeType().getIsValid(); } private IValidation[] getDiskAliasValidations() { Collection<IValidation> diskAliasValidations = new ArrayList<>(Arrays.asList( new I18NNameValidation(), new LengthValidation(BusinessEntitiesDefinitions.GENERAL_NAME_SIZE))); if (getVm() == null) { diskAliasValidations.add(new NotEmptyValidation()); } return diskAliasValidations.toArray(new IValidation[diskAliasValidations.size()]); } protected void forceCreationWarning(ArrayList<String> usedLunsMessages) { ConfirmationModel confirmationModel = new ConfirmationModel(); setConfirmWindow(confirmationModel); confirmationModel.setTitle(constants.forceStorageDomainCreation()); confirmationModel.setMessage(constants.lunsAlreadyPartOfSD()); confirmationModel.setHelpTag(HelpTag.force_lun_disk_creation); confirmationModel.setHashName("force_lun_disk_creation"); //$NON-NLS-1$ confirmationModel.setItems(usedLunsMessages); UICommand forceSaveCommand = new UICommand("OnForceSave", this); //$NON-NLS-1$ forceSaveCommand.setTitle(constants.ok()); forceSaveCommand.setIsDefault(true); confirmationModel.getCommands().add(forceSaveCommand); UICommand cancelconfirmCommand = new UICommand("CancelConfirm", this); //$NON-NLS-1$ cancelconfirmCommand.setTitle(constants.cancel()); cancelconfirmCommand.setIsCancel(true); confirmationModel.getCommands().add(cancelconfirmCommand); } private void onForceSave() { ConfirmationModel confirmationModel = (ConfirmationModel) getConfirmWindow(); if (confirmationModel != null && !confirmationModel.validate()) { return; } cancelConfirm(); getSanStorageModelBase().setForce(true); onSave(); } private void cancelConfirm() { setConfirmWindow(null); } protected void cancel() { getCancelCommand().execute(); } protected Guid getVmId() { return getVm() != null ? getVm().getId() : Guid.Empty; } public void onSave() { flush(); store(null); } public void flush() { switch (getDiskStorageType().getEntity()) { case LUN: LunDisk lunDisk = getLunDisk(); DiskInterface diskInterface = getDiskInterface().getSelectedItem(); if (DiskInterface.VirtIO_SCSI.equals(diskInterface)) { lunDisk.setSgio(!getIsScsiPassthrough().getEntity() ? null : getIsSgIoUnfiltered().getEntity() ? ScsiGenericIO.UNFILTERED : ScsiGenericIO.FILTERED); if (!getIsFloating()) { getDiskVmElement().setUsingScsiReservation(getIsUsingScsiReservation().getEntity()); } } else { getIsScsiPassthrough().setEntity(false); lunDisk.setSgio(null); if (!getIsFloating()) { getDiskVmElement().setUsingScsiReservation(false); } } setDisk(lunDisk); break; case CINDER: CinderDisk cinderDisk = getCinderDisk(); updateQuota(cinderDisk); updateDiskSize(cinderDisk); setDisk(cinderDisk); break; case IMAGE: DiskImage diskImage = getDiskImage(); // For a long time it was possible to delete all disk profiles if (getDiskProfile().getSelectedItem() != null) { diskImage.setDiskProfileId(getDiskProfile().getSelectedItem().getId()); } updateQuota(diskImage); updateDiskSize(diskImage); setDisk(diskImage); break; } getDisk().setDiskAlias(getAlias().getEntity()); getDisk().setDiskDescription(getDescription().getEntity()); getDisk().setWipeAfterDelete(getIsWipeAfterDelete().getEntity()); getDisk().setShareable(getIsShareable().getEntity()); getDisk().setPlugged(getIsPlugged().getEntity()); getDisk().setPropagateErrors(PropagateErrors.Off); if (getVm() != null) { getDiskVmElement().setReadOnly(getIsReadOnly().getIsAvailable() ? getIsReadOnly().getEntity() : false); getDiskVmElement().setBoot(getIsBootable().getEntity()); getDiskVmElement().setDiskInterface(getDiskInterface().getSelectedItem()); getDiskVmElement().setPassDiscard(getPassDiscard().getEntity()); } } private void updateQuota(DiskImage diskImage) { if (getQuota().getIsAvailable() && getQuota().getSelectedItem() != null) { diskImage.setQuotaId(getQuota().getSelectedItem().getId()); } } public abstract void store(IFrontendActionAsyncCallback callback); @Override public void executeCommand(UICommand command) { super.executeCommand(command); if ("OnSave".equals(command.getName())) { //$NON-NLS-1$ onSave(); } if ("OnForceSave".equals(command.getName())) { //$NON-NLS-1$ onForceSave(); } else if ("CancelConfirm".equals(command.getName())) { //$NON-NLS-1$ cancelConfirm(); } } @Override public void eventRaised(Event<? extends EventArgs> ev, Object sender, EventArgs args) { super.eventRaised(ev, sender, args); if (ev.matchesDefinition(HasEntity.entityChangedEventDefinition)) { if (sender == getIsReadOnly()) { updateScsiPassthroughChangeability(); } else if (sender == getIsScsiPassthrough()) { updateScsiPassthroughChangeability(); updateSgIoUnfilteredChangeability(); updateReadOnlyChangeability(); updateScsiReservationChangeability(); } else if (sender == getIsSgIoUnfiltered()) { updateScsiReservationChangeability(); } else if (sender == getDiskStorageType()) { diskStorageType_EntityChanged(); } else if (sender == getIsWipeAfterDelete()) { updatePassDiscardChangeability(); } else if (sender == getPassDiscard()) { updateWipeAfterDeleteChangeability(); } } else if (ev.matchesDefinition(ListModel.selectedItemChangedEventDefinition)) { if (sender == getVolumeType()) { volumeType_SelectedItemChanged(); } else if (sender == getDiskInterface()) { DiskInterface_SelectedItemChanged(); } else if (sender == getDataCenter()) { datacenter_SelectedItemChanged(); } else if (sender == getStorageDomain()) { storageDomain_SelectedItemChanged(); } } } public StorageModel getStorageModel() { return storageModel; } public void setStorageModel(StorageModel storageModel) { this.storageModel = storageModel; } protected Guid getStorageDomainId() { switch (getDisk().getDiskStorageType()) { case IMAGE: return getDiskImage().getStorageIds().get(0); case CINDER: return getCinderDisk().getStorageIds().get(0); } return null; } protected boolean performUpdateHosts() { return getDiskStorageType().getEntity() == DiskStorageType.LUN; } }