package org.ovirt.engine.ui.uicommonweb.models.storage; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; 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.profiles.DiskProfile; 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.VolumeFormat; 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.ui.frontend.Frontend; import org.ovirt.engine.ui.uicommonweb.Linq; import org.ovirt.engine.ui.uicommonweb.dataprovider.AsyncDataProvider; import org.ovirt.engine.ui.uicommonweb.models.EntityModel; import org.ovirt.engine.ui.uicommonweb.models.ListModel; import org.ovirt.engine.ui.uicommonweb.models.Model; 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.uicompat.ConstantsManager; import org.ovirt.engine.ui.uicompat.EventArgs; import org.ovirt.engine.ui.uicompat.IEventListener; import org.ovirt.engine.ui.uicompat.PropertyChangedEventArgs; import org.ovirt.engine.ui.uicompat.UIConstants; import org.ovirt.engine.ui.uicompat.UIMessages; public class DisksAllocationModel extends EntityModel { protected static final UIConstants constants = ConstantsManager.getInstance().getConstants(); protected static final UIMessages messages = ConstantsManager.getInstance().getMessages(); private static final String VOLUME_TYPE = "VOLUME_TYPE"; //$NON-NLS-1$ private static final String VOLUME_FORMAT = "VOLUME_FORMAT"; //$NON-NLS-1$ private static final String THIN_PROVISIONING = "THIN_PROVISIONING"; //$NON-NLS-1$ private final IEventListener<EventArgs> storageDomainEventListener = (ev, sender, args) -> updateDisks(sender); private List<DiskModel> disks; public List<DiskModel> getDisks() { return disks; } private Model container; public Model getContainer() { return container; } public void setContainer(Model container) { this.container = container; } private EntityModel<Boolean> diskAllocationTargetEnabled; public EntityModel<Boolean> getDiskAllocationTargetEnabled() { return diskAllocationTargetEnabled; } public void setDiskAllocationTargetEnabled(EntityModel<Boolean> enabled) { this.diskAllocationTargetEnabled = enabled; } public void setDisks(List<DiskModel> value) { disks = value; if (disks == null) { return; } sortDisks(); setDefaultVolumeInformationSelection(disks); for (final DiskModel diskModel : disks) { diskModel.getStorageDomain().getSelectedItemChangedEvent().removeListener(storageDomainEventListener); diskModel.getStorageDomain().getSelectedItemChangedEvent().addListener(storageDomainEventListener); diskModel.getStorageDomain().getItemsChangedEvent().addListener((ev, sender, args) -> { DiskImage disk = (DiskImage) diskModel.getDisk(); if (diskModel.getStorageDomain().getItems() != null && disk.getStorageIds() != null && !disk.getStorageIds().isEmpty() && !diskModel.getStorageDomain().getItems().isEmpty()) { diskModel.getStorageDomain().setSelectedItem(Linq.firstOrDefault( diskModel.getStorageDomain().getItems(), new Linq.IdsPredicate<>(disk.getStorageIds()), diskModel.getStorageDomain().getItems().iterator().next())); } }); } } protected void setDefaultVolumeInformationSelection(List<DiskModel> diskModels) { final Map<Guid, DiskModel> diskModelsMap = new HashMap<>(); for (DiskModel diskModel : diskModels) { diskModelsMap.put(((DiskImage) diskModel.getDisk()).getImageId(), diskModel); } AsyncDataProvider.getInstance().getAncestorImagesByImagesIds(new AsyncQuery<>(imagesAncestors -> { for (Map.Entry<Guid, DiskImage> entry : imagesAncestors.entrySet()) { DiskModel diskModel = diskModelsMap.get(entry.getKey()); diskModel.getVolumeType().setSelectedItem(entry.getValue().getVolumeType()); diskModel.getVolumeFormat().setSelectedItem(entry.getValue().getVolumeFormat()); updateStorageDomainsAvailability(); } }), new ArrayList<>(diskModelsMap.keySet())); } public void sortDisks() { if (disks != null) { Collections.sort(disks, Comparator.comparing(d -> d.getDisk().getDiskAlias())); onPropertyChanged(new PropertyChangedEventArgs("Disks")); //$NON-NLS-1$ } } private HashMap<Guid, DiskImage> imageToDestinationDomainMap; public HashMap<Guid, DiskImage> getImageToDestinationDomainMap() { updateImageToDestinationDomainMap(); return imageToDestinationDomainMap; } public void setImageToDestinationDomainMap(HashMap<Guid, DiskImage> imageToDestinationDomainMap) { this.imageToDestinationDomainMap = imageToDestinationDomainMap; } private ArrayList<StorageDomain> activeStorageDomains; public ArrayList<StorageDomain> getActiveStorageDomains() { return activeStorageDomains; } public void setActiveStorageDomains(ArrayList<StorageDomain> activeStorageDomains) { this.activeStorageDomains = activeStorageDomains; } private QuotaEnforcementTypeEnum quotaEnforcementType; public void setQuotaEnforcementType(QuotaEnforcementTypeEnum value) { this.quotaEnforcementType = value; onPropertyChanged(new PropertyChangedEventArgs("QuotaEnforcmentType")); //$NON-NLS-1$ } public QuotaEnforcementTypeEnum getQuotaEnforcementType() { return quotaEnforcementType; } private boolean isVolumeFormatAvailable; private boolean isVolumeFormatChangeable; private boolean isVolumeTypeAvailable; private boolean isVolumeTypeChangable; private boolean isThinProvisioning; private boolean isAliasChangable; private boolean isSourceStorageDomainAvailable; private boolean isSourceStorageDomainNameAvailable; private boolean isTargetAvailable = true; public DisksAllocationModel() { setImageToDestinationDomainMap(new HashMap<Guid, DiskImage>()); setDynamicWarning(new EntityModel<String>()); getDynamicWarning().setIsAvailable(false); setDiskAllocationTargetEnabled(new EntityModel<>(false)); getDiskAllocationTargetEnabled().setIsAvailable(false); } private void updateQuota(Guid storageDomainId, final ListModel<Quota> isItem, final Guid diskQuotaId) { if (getQuotaEnforcementType() != QuotaEnforcementTypeEnum.DISABLED && storageDomainId != null) { AsyncDataProvider.getInstance().getAllRelevantQuotasForStorageSorted(new AsyncQuery<>( list -> { if (list == null) { return; } if (isItem == null) { for (DiskModel diskModel : getDisks()) { diskModel.getQuota().setItems(list); if (diskModel.getDisk() instanceof DiskImage) { DiskImage diskImage = (DiskImage) diskModel.getDisk(); for (Quota quota : list) { if (quota.getId().equals(diskImage.getQuotaId())) { diskModel.getQuota().setSelectedItem(quota); break; } } } } } else { Guid selectedQuota = isItem.getSelectedItem() != null ? isItem.getSelectedItem().getId() : null; selectedQuota = selectedQuota != null ? selectedQuota : diskQuotaId; isItem.setItems(list); if (selectedQuota != null && list.size() > 1) { for (Quota quota : list) { if (quota.getId().equals(selectedQuota)) { isItem.setSelectedItem(quota); break; } } } } }), storageDomainId, null); } } private void updateDiskProfile(Guid storageDomainId, final ListModel<DiskProfile> diskProfiles) { Frontend.getInstance().runQuery(VdcQueryType.GetDiskProfilesByStorageDomainId, new IdQueryParameters(storageDomainId), new AsyncQuery<VdcQueryReturnValue>(returnValue -> { List<DiskProfile> fetchedDiskProfiles = returnValue.getReturnValue(); DisksAllocationModel.this.setDiskProfilesList(diskProfiles, fetchedDiskProfiles); })); } private void setDiskProfilesList(final ListModel<DiskProfile> diskProfiles, List<DiskProfile> fetchedDiskProfiles) { if (fetchedDiskProfiles != null) { // normal flow, set items and selected item according to current selected. if (diskProfiles == null) { for (DiskModel diskModel : getDisks()) { diskModel.getDiskProfile().setItems(fetchedDiskProfiles); for (DiskProfile diskProfile : fetchedDiskProfiles) { if (diskModel.getDisk().getDiskStorageType() == DiskStorageType.IMAGE && diskProfile.getId().equals(((DiskImage) diskModel.getDisk()).getDiskProfileId())) { diskModel.getDiskProfile().setSelectedItem(diskProfile); } } } // inner model disk profiles } else { DiskProfile selectedDiskProfile = null; if (diskProfiles.getSelectedItem() != null) { selectedDiskProfile = diskProfiles.getSelectedItem(); } diskProfiles.setItems(fetchedDiskProfiles); if (selectedDiskProfile != null && fetchedDiskProfiles.size() > 1) { for (DiskProfile diskProfile : fetchedDiskProfiles) { if (diskProfile.getId().equals(selectedDiskProfile.getId())) { diskProfiles.setSelectedItem(diskProfile); break; } } } } } } @Override protected void onPropertyChanged(PropertyChangedEventArgs e) { super.onPropertyChanged(e); if (e.propertyName.equals("Disks") || e.propertyName.equals(VOLUME_TYPE) //$NON-NLS-1$ || e.propertyName.equals(VOLUME_FORMAT) || e.propertyName.equals(THIN_PROVISIONING)) { updateStorageDomainsAvailability(); updateQuotaAvailability(); } } private void updateStorageDomainsAvailability() { if (disks == null) { return; } for (DiskModel diskModel : disks) { diskModel.getSourceStorageDomain().setIsAvailable(isSourceStorageDomainAvailable); diskModel.getSourceStorageDomainName().setIsAvailable(isSourceStorageDomainNameAvailable); diskModel.getStorageDomain().setIsAvailable(isTargetAvailable); diskModel.getVolumeType().setIsAvailable(isVolumeTypeAvailable); diskModel.getVolumeType().setIsChangeable(isVolumeTypeChangable); diskModel.getVolumeFormat().setIsAvailable(isVolumeFormatAvailable); diskModel.getVolumeFormat().setIsChangeable(isVolumeFormatChangeable); diskModel.getAlias().setIsChangeable(isAliasChangable); boolean isCinder = diskModel.getDisk().getDiskStorageType() == DiskStorageType.CINDER; if (isCinder) { diskModel.getVolumeFormat().setIsChangeable(false); diskModel.getVolumeFormat().setSelectedItem(VolumeFormat.RAW); } else if (isThinProvisioning) { diskModel.getVolumeFormat().setSelectedItem(VolumeFormat.COW); } } } private void updateImageToDestinationDomainMap() { if (disks == null) { return; } for (DiskModel diskModel : disks) { StorageDomain storageDomain = diskModel.getStorageDomain().getSelectedItem(); DiskImage diskImage = (DiskImage) diskModel.getDisk(); diskImage.setStorageIds(new ArrayList<>(Arrays.asList(storageDomain.getId()))); diskImage.setDiskAlias(diskModel.getAlias().getEntity()); DiskProfile diskProfile = diskModel.getDiskProfile().getSelectedItem(); diskImage.setDiskProfileId(diskProfile != null ? diskProfile.getId() : null); if (diskModel.getQuota().getSelectedItem() != null) { diskImage.setQuotaId(diskModel.getQuota().getSelectedItem().getId()); } if (diskModel.getVolumeFormat().getIsAvailable()) { VolumeFormat volumeFormat = diskModel.getVolumeFormat().getSelectedItem(); diskImage.setVolumeFormat(volumeFormat); diskImage.setVolumeType(AsyncDataProvider.getInstance().getVolumeType( volumeFormat, storageDomain.getStorageType())); } else if (diskModel.getVolumeType().getIsAvailable()) { VolumeType volumeType = diskModel.getVolumeType().getSelectedItem(); diskImage.setVolumeType(volumeType); diskImage.setVolumeFormat(AsyncDataProvider.getInstance().getDiskVolumeFormat( volumeType, storageDomain.getStorageType())); } imageToDestinationDomainMap.put(diskImage.getId(), diskImage); } } public void updateTargetChangeable(boolean enabled) { if (disks != null) { for (DiskModel diskModel : disks) { diskModel.getStorageDomain().setIsChangeable(enabled); diskModel.getDiskProfile().setIsChangeable(enabled); } } } private void updateQuotaAvailability() { if (disks != null) { for (DiskModel diskModel : disks) { diskModel.getQuota().setIsAvailable(quotaEnforcementType != QuotaEnforcementTypeEnum.DISABLED); } } } private void updateDisks(Object sender) { StorageDomain storageDomain = (StorageDomain) ((ListModel) sender).getSelectedItem(); if (storageDomain != null) { for (DiskModel innerDisk : disks) { if (innerDisk.getStorageDomain().equals(sender)) { Guid diskQuotaId = null; if (innerDisk.getDisk() instanceof DiskImage) { DiskImage img = (DiskImage) innerDisk.getDisk(); diskQuotaId = img.getQuotaId(); } updateQuota(storageDomain.getId(), innerDisk.getQuota(), diskQuotaId); updateDiskProfile(storageDomain.getId(), innerDisk.getDiskProfile()); break; } } } } @Override public void validateEntity(IValidation[] validations) { super.validateEntity(validations); if (getDisks() == null) { return; } boolean isModelValid = true; for (DiskModel diskModel : getDisks()) { ListModel diskStorageDomains = diskModel.getStorageDomain(); if (!diskStorageDomains.getItems().iterator().hasNext() || diskStorageDomains.getSelectedItem() == null) { diskModel.getStorageDomain().getInvalidityReasons().add( constants.storageDomainMustBeSpecifiedInvalidReason()); diskModel.getStorageDomain().setIsValid(false); isModelValid = false; } diskModel.getAlias().validateEntity(new IValidation[] { new NotEmptyValidation(), new I18NNameValidation() }); isModelValid = isModelValid && diskModel.getAlias().getIsValid(); } setIsValid(isModelValid); } public void setIsVolumeTypeAvailable(boolean isVolumeFormatAvailable) { this.isVolumeTypeAvailable = isVolumeFormatAvailable; } public boolean getIsVolumeTypeAvailable() { return isVolumeTypeAvailable; } public void setIsVolumeFormatAvailable(boolean isVolumeFormatAvailable) { this.isVolumeFormatAvailable = isVolumeFormatAvailable; } public boolean getIsVolumeFormatAvailable() { return isVolumeFormatAvailable; } public boolean getIsAliasChangable() { return isAliasChangable; } public void setIsAliasChangable(boolean isAliasChangable) { this.isAliasChangable = isAliasChangable; } public void setIsThinProvisioning(boolean isThinProvisioning) { if (this.isThinProvisioning != isThinProvisioning) { this.isThinProvisioning = isThinProvisioning; onPropertyChanged(new PropertyChangedEventArgs(THIN_PROVISIONING)); } } public void setIsVolumeTypeChangable(boolean isVolumeTypeChangable) { if (this.isVolumeTypeChangable != isVolumeTypeChangable) { this.isVolumeTypeChangable = isVolumeTypeChangable; onPropertyChanged(new PropertyChangedEventArgs(VOLUME_TYPE)); } } public void setIsVolumeFormatChangeable(boolean isVolumeFormatChangeable) { if (this.isVolumeFormatChangeable != isVolumeFormatChangeable) { this.isVolumeFormatChangeable = isVolumeFormatChangeable; onPropertyChanged(new PropertyChangedEventArgs(VOLUME_FORMAT)); } } public void setIsSourceStorageDomainAvailable(boolean isSourceStorageDomainAvailable) { this.isSourceStorageDomainAvailable = isSourceStorageDomainAvailable; } public void setIsSourceStorageDomainNameAvailable(boolean isSourceStorageDomainNameAvailable) { this.isSourceStorageDomainNameAvailable = isSourceStorageDomainNameAvailable; } private EntityModel<String> dynamicWarning; public EntityModel<String> getDynamicWarning() { return dynamicWarning; } public void setDynamicWarning(EntityModel<String> value) { dynamicWarning = value; } public boolean isSourceAvailable() { return isSourceStorageDomainAvailable || isSourceStorageDomainNameAvailable; } public boolean isTargetAvailable() { return isTargetAvailable; } public void setTargetAvailable(boolean targetAvailable) { isTargetAvailable = targetAvailable; } public void initializeAutoSelectTarget(boolean changeable, boolean value) { getDiskAllocationTargetEnabled().setIsAvailable(true); getDiskAllocationTargetEnabled().setIsChangeable(changeable); getDiskAllocationTargetEnabled().setEntity(value); updateTargetChangeable(changeable); getDiskAllocationTargetEnabled().getEntityChangedEvent().addListener((ev, sender, args) -> updateTargetChangeable(!getDiskAllocationTargetEnabled().getEntity())); } @Override public void cleanup() { if (disks != null) { for (DiskModel diskModel : disks) { diskModel.cleanup(); } } super.cleanup(); } }