package org.ovirt.engine.ui.uicommonweb.models.providers; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; import org.ovirt.engine.core.common.action.ImportProviderCertificateParameters; import org.ovirt.engine.core.common.action.ProviderParameters; import org.ovirt.engine.core.common.action.VdcActionType; import org.ovirt.engine.core.common.action.VdcReturnValueBase; import org.ovirt.engine.core.common.businessentities.CertificateInfo; import org.ovirt.engine.core.common.businessentities.OpenStackImageProviderProperties; import org.ovirt.engine.core.common.businessentities.OpenstackNetworkProviderProperties; import org.ovirt.engine.core.common.businessentities.Provider; import org.ovirt.engine.core.common.businessentities.ProviderType; import org.ovirt.engine.core.common.businessentities.StoragePool; import org.ovirt.engine.core.common.businessentities.TenantProviderProperties; import org.ovirt.engine.core.common.businessentities.VDS; import org.ovirt.engine.core.common.businessentities.comparators.LexoNumericComparator; import org.ovirt.engine.core.common.businessentities.comparators.NameableComparator; import org.ovirt.engine.core.common.businessentities.storage.OpenStackVolumeProviderProperties; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.ui.frontend.AsyncCallback; import org.ovirt.engine.ui.frontend.Frontend; import org.ovirt.engine.ui.uicommonweb.UICommand; import org.ovirt.engine.ui.uicommonweb.Uri; 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.ListModel; import org.ovirt.engine.ui.uicommonweb.models.Model; import org.ovirt.engine.ui.uicommonweb.models.SearchableListModel; import org.ovirt.engine.ui.uicommonweb.validation.AsciiNameValidation; import org.ovirt.engine.ui.uicommonweb.validation.IValidation; import org.ovirt.engine.ui.uicommonweb.validation.NotEmptyValidation; import org.ovirt.engine.ui.uicommonweb.validation.UrlValidation; import org.ovirt.engine.ui.uicompat.ConstantsManager; import org.ovirt.engine.ui.uicompat.EnumTranslator; import org.ovirt.engine.ui.uicompat.Event; import org.ovirt.engine.ui.uicompat.EventArgs; import org.ovirt.engine.ui.uicompat.IEventListener; public class ProviderModel extends Model { private static final String CMD_SAVE = "OnSave"; //$NON-NLS-1$ private static final String CMD_TEST = "OnTest"; //$NON-NLS-1$ private static final String CMD_CANCEL = "Cancel"; //$NON-NLS-1$ private static final String CMD_IMPORT_CERTIFICATE = "ImportCertificate"; //$NON-NLS-1$ private static final String CMD_CANCEL_IMPORT = "CancelImport"; //$NON-NLS-1$ private static final String EMPTY_ERROR_MESSAGE = ""; //$NON-NLS-1$ protected final SearchableListModel sourceListModel; private final VdcActionType action; protected final Provider provider; private EntityModel<String> name = new EntityModel<>(); private EntityModel<String> description = new EntityModel<>(); private EntityModel<String> url = new EntityModel<>(); private EntityModel<Boolean> requiresAuthentication = new EntityModel<>(); private EntityModel<String> username = new EntityModel<>(); private EntityModel<String> password = new EntityModel<>(); private EntityModel<String> tenantName = new EntityModel<>(); private ListModel<ProviderType> type; private UICommand testCommand; private EntityModel<String> testResult = new EntityModel<>(); private EntityModel<String> authUrl = new EntityModel<>(); private ListModel<StoragePool> dataCenter; private NeutronAgentModel neutronAgentModel = new NeutronAgentModel(); private VmwarePropertiesModel vmwarePropertiesModel = new VmwarePropertiesModel(); private KVMPropertiesModel kvmPropertiesModel = new KVMPropertiesModel(); private XENPropertiesModel xenPropertiesModel = new XENPropertiesModel(); private String certificate; private EntityModel<Boolean> readOnly = new EntityModel<>(); public EntityModel<String> getName() { return name; } public ListModel<ProviderType> getType() { return type; } private void setType(ListModel<ProviderType> value) { type = value; } public ListModel<String> getPluginType() { return getNeutronAgentModel().getPluginType(); } public EntityModel<String> getDescription() { return description; } public EntityModel<String> getUrl() { return url; } public EntityModel<Boolean> getRequiresAuthentication() { return requiresAuthentication; } public EntityModel<Boolean> getReadOnly() { return readOnly; } public EntityModel<String> getUsername() { return username; } public EntityModel<String> getPassword() { return password; } public EntityModel<String> getTenantName() { return tenantName; } public UICommand getTestCommand() { return testCommand; } private void setTestCommand(UICommand value) { testCommand = value; } public EntityModel<String> getTestResult() { return testResult; } public NeutronAgentModel getNeutronAgentModel() { return neutronAgentModel; } public VmwarePropertiesModel getVmwarePropertiesModel() { return vmwarePropertiesModel; } public KVMPropertiesModel getKvmPropertiesModel() { return kvmPropertiesModel; } public XENPropertiesModel getXenPropertiesModel() { return xenPropertiesModel; } protected boolean isExternalNetwork() { return getType().getSelectedItem() == ProviderType.EXTERNAL_NETWORK; } protected boolean isTypeOpenStackNetwork() { return getType().getSelectedItem() == ProviderType.OPENSTACK_NETWORK; } private boolean isTypeOpenStackImage() { return getType().getSelectedItem() == ProviderType.OPENSTACK_IMAGE; } private boolean isTypeOpenStackVolume() { return getType().getSelectedItem() == ProviderType.OPENSTACK_VOLUME; } protected boolean isTypeVmware() { return getType().getSelectedItem() == ProviderType.VMWARE; } protected boolean isTypeKVM() { return getType().getSelectedItem() == ProviderType.KVM; } protected boolean isTypeXEN() { return getType().getSelectedItem() == ProviderType.XEN; } public ListModel<StoragePool> getDataCenter() { return dataCenter; } public void setDataCenter(ListModel<StoragePool> dataCenter) { this.dataCenter = dataCenter; } public EntityModel<String> getAuthUrl() { return authUrl; } private boolean isTypeRequiresAuthentication() { return false; } private String getDefaultUrl(ProviderType type) { if (type == null) { return ""; //$NON-NLS-1$ } switch (type) { case EXTERNAL_NETWORK: case OPENSTACK_NETWORK: return "http://localhost:9696"; //$NON-NLS-1$ case OPENSTACK_IMAGE: return "http://localhost:9292"; //$NON-NLS-1$ case OPENSTACK_VOLUME: return "http://localhost:8776"; //$NON-NLS-1$ case VMWARE: return ""; //$NON-NLS-1$ case KVM: return ""; //$NON-NLS-1$ case XEN: return ""; //$NON-NLS-1$ case FOREMAN: default: return "http://localhost"; //$NON-NLS-1$ } } public ProviderModel(SearchableListModel sourceListModel, VdcActionType action, final Provider provider) { this.sourceListModel = sourceListModel; this.action = action; this.provider = provider; getRequiresAuthentication().getEntityChangedEvent().addListener((ev, sender, args) -> { boolean authenticationRequired = requiresAuthentication.getEntity(); getUsername().setIsChangeable(authenticationRequired); getPassword().setIsChangeable(authenticationRequired); getTenantName().setIsChangeable(authenticationRequired); getAuthUrl().setIsChangeable(authenticationRequired); }); setType(new ListModel<ProviderType>() { @Override protected void onSelectedItemChanging(ProviderType newValue, ProviderType oldValue) { super.onSelectedItemChanging(newValue, oldValue); String url = getUrl().getEntity(); if (url == null) { url = ""; //$NON-NLS-1$ } url = url.trim(); if (url.equals("") || url.equalsIgnoreCase(getDefaultUrl(oldValue))) { //$NON-NLS-1$ getUrl().setEntity(getDefaultUrl(newValue)); } } }); getType().getSelectedItemChangedEvent().addListener((ev, sender, args) -> { boolean isTenantAware = getType().getSelectedItem().isTenantAware(); boolean isAuthUrlAware = getType().getSelectedItem().isAuthUrlAware(); boolean isReadOnlyAware = getType().getSelectedItem().isReadOnlyAware(); getTenantName().setIsAvailable(isTenantAware); getAuthUrl().setIsAvailable(isAuthUrlAware); if (isTenantAware) { TenantProviderProperties properties = (TenantProviderProperties) provider.getAdditionalProperties(); getTenantName().setEntity(properties == null ? null : properties.getTenantName()); } boolean isNeutron = isTypeOpenStackNetwork(); getNeutronAgentModel().setIsAvailable(isNeutron); getReadOnly().setIsAvailable(isReadOnlyAware); if (isReadOnlyAware){ OpenstackNetworkProviderProperties properties = (OpenstackNetworkProviderProperties) provider.getAdditionalProperties(); getReadOnly().setEntity(properties != null ? properties.getReadOnly() : true); } boolean isVmware = isTypeVmware(); boolean isKvm = isTypeKVM(); boolean isXen = isTypeXEN(); boolean requiresAuth = isTypeRequiresAuthentication(); getRequiresAuthentication().setEntity(isVmware || Boolean.valueOf(requiresAuth)); getRequiresAuthentication().setIsChangeable(!requiresAuth); boolean isCinder = isTypeOpenStackVolume(); getDataCenter().setIsAvailable(isCinder || isVmware || isKvm || isXen); if (isCinder) { updateDatacentersForVolumeProvider(); } getVmwarePropertiesModel().setIsAvailable(isVmware); getKvmPropertiesModel().setIsAvailable(isKvm); getXenPropertiesModel().setIsAvailable(isXen); getRequiresAuthentication().setIsAvailable(!isVmware && !isXen); getUsername().setIsAvailable(!isXen); getPassword().setIsAvailable(!isXen); getUrl().setIsAvailable(!isVmware && !isKvm && !isXen); if (isVmware || isKvm || isXen) { updateDatacentersForExternalProvider(); } }); getNeutronAgentModel().setIsAvailable(false); getVmwarePropertiesModel().setIsAvailable(false); getTenantName().setIsAvailable(false); List<ProviderType> providerTypes = new ArrayList<>(Arrays.asList(ProviderType.values())); Collections.sort(providerTypes, Comparator.comparing(t -> EnumTranslator.getInstance().translate(t), new LexoNumericComparator())); getType().setItems(providerTypes); getCommands().add(UICommand.createDefaultOkUiCommand(CMD_SAVE, this)); getCommands().add(UICommand.createCancelUiCommand(CMD_CANCEL, this)); setTestCommand(new UICommand(CMD_TEST, this)); setDataCenter(new ListModel<StoragePool>()); getDataCenter().setIsAvailable(false); getDataCenter().getSelectedItemChangedEvent().addListener(new IEventListener<EventArgs>() { @Override public void eventRaised(Event<? extends EventArgs> ev, Object sender, EventArgs args) { if (!isTypeVmware() && !isTypeKVM() && !isTypeXEN()) { return; } final ProxyHostPropertiesModel proxyHostPropertiesModel = getProxyHostPropertiesModel(); if (getDataCenter().getSelectedItem() == null) { proxyHostPropertiesModel.disableProxyHost(); } else { proxyHostPropertiesModel.getProxyHost().setIsChangeable(true); AsyncDataProvider.getInstance().getHostListByDataCenter(new AsyncQuery<>(hosts -> { VDS prevHost = getPreviousHost(hosts); hosts.add(0, null); // Any host in the cluster proxyHostPropertiesModel.getProxyHost().setItems(hosts); proxyHostPropertiesModel.getProxyHost().setSelectedItem(prevHost); }), getDataCenter().getSelectedItem().getId()); } } private VDS getPreviousHost(List<VDS> hosts) { Guid previousProxyHostId = getProxyHostPropertiesModel().getLastProxyHostId(); for (VDS host : hosts) { if (host.getId().equals(previousProxyHostId)) { return host; } } return null; } }); } public ProxyHostPropertiesModel getProxyHostPropertiesModel() { if (isTypeXEN()) { return getXenPropertiesModel(); } else if (isTypeKVM()) { return getKvmPropertiesModel(); } else if (isTypeVmware()) { return getVmwarePropertiesModel(); } else { // null object, to avoid null checks everywhere return new ProxyHostPropertiesModel() {}; } } protected void updateDatacentersForExternalProvider() { AsyncDataProvider.getInstance().getDataCenterList(new AsyncQuery<>(new AsyncCallback<List<StoragePool>>() { @Override public void onSuccess(List<StoragePool> dataCenters) { StoragePool prevDataCenter = getPreviousDataCenter(dataCenters); Collections.sort(dataCenters, new NameableComparator()); dataCenters.add(0, null); //any data center getDataCenter().setItems(dataCenters); getDataCenter().setSelectedItem(prevDataCenter); if (getDataCenter().getSelectedItem() == null) { getProxyHostPropertiesModel().disableProxyHost(); } } private StoragePool getPreviousDataCenter(List<StoragePool> dataCenters) { Guid previousDataCenterId = getProxyHostPropertiesModel().getLastStoragePoolId(); for (StoragePool dataCenter : dataCenters) { if (dataCenter.getId().equals(previousDataCenterId)) { return dataCenter; } } return null; } })); } protected void updateDatacentersForVolumeProvider() { // implemented on sub-classes } private boolean validate() { getName().validateEntity(new IValidation[] { new NotEmptyValidation(), new AsciiNameValidation() }); getType().validateSelectedItem(new IValidation[] { new NotEmptyValidation() }); getNeutronAgentModel().validate(); getVmwarePropertiesModel().validate(); getKvmPropertiesModel().validate(); getXenPropertiesModel().validate(); boolean connectionSettingsValid = validateConnectionSettings(); return connectionSettingsValid && getName().getIsValid() && getType().getIsValid() && getNeutronAgentModel().getIsValid() && getKvmPropertiesModel().getIsValid() && getXenPropertiesModel().getIsValid() && getVmwarePropertiesModel().getIsValid(); } private boolean validateConnectionSettings() { getUsername().validateEntity(new IValidation[] { new NotEmptyValidation() }); getPassword().validateEntity(new IValidation[] { new NotEmptyValidation() }); if (getType().getSelectedItem().isTenantRequired()) { getTenantName().validateEntity(new IValidation[] { new NotEmptyValidation()} ); } getAuthUrl().validateEntity(new IValidation[] { new NotEmptyValidation(), new UrlValidation(Uri.SCHEME_HTTP, Uri.SCHEME_HTTPS) }); getUrl().validateEntity(new IValidation[] { new NotEmptyValidation(), new UrlValidation(Uri.SCHEME_HTTP, Uri.SCHEME_HTTPS) }); return getUrl().getIsValid() && getUsername().getIsValid() && getPassword().getIsValid() && getTenantName().getIsValid() && getAuthUrl().getIsValid(); } private void cancel() { sourceListModel.setWindow(null); } private void flush() { provider.setName(name.getEntity()); provider.setType(type.getSelectedItem()); provider.setDescription(description.getEntity()); provider.setUrl(url.getEntity()); if (isTypeOpenStackNetwork() || isExternalNetwork()) { getNeutronAgentModel().flush(provider); OpenstackNetworkProviderProperties properties = (OpenstackNetworkProviderProperties) provider.getAdditionalProperties(); properties.setReadOnly(readOnly.getEntity()); } else if (isTypeOpenStackImage()) { provider.setAdditionalProperties(new OpenStackImageProviderProperties()); } else if (isTypeOpenStackVolume()) { provider.setAdditionalProperties(new OpenStackVolumeProviderProperties(getDataCenter().getSelectedItem().getId())); } else if (isTypeVmware()) { provider.setAdditionalProperties(getVmwarePropertiesModel().getVmwareVmProviderProperties( dataCenter.getSelectedItem() != null ? dataCenter.getSelectedItem().getId() : null)); provider.setUrl(getVmwarePropertiesModel().getUrl()); } else if (isTypeKVM()) { provider.setUrl(getKvmPropertiesModel().getUrl().getEntity()); provider.setAdditionalProperties(getKvmPropertiesModel().getKVMVmProviderProperties( dataCenter.getSelectedItem() != null ? dataCenter.getSelectedItem().getId() : null)); } else if (isTypeXEN()) { provider.setUrl(getXenPropertiesModel().getUrl().getEntity()); provider.setAdditionalProperties(getXenPropertiesModel().getXENVmProviderProperties( dataCenter.getSelectedItem() != null ? dataCenter.getSelectedItem().getId() : null)); } boolean authenticationRequired = requiresAuthentication.getEntity(); provider.setRequiringAuthentication(authenticationRequired); if (authenticationRequired) { provider.setUsername(getUsername().getEntity()); provider.setPassword(getPassword().getEntity()); if (getTenantName().getIsAvailable()) { TenantProviderProperties properties = (TenantProviderProperties) provider.getAdditionalProperties(); if (properties == null) { properties = new TenantProviderProperties(); provider.setAdditionalProperties(properties); } properties.setTenantName(getTenantName().getEntity()); } provider.setAuthUrl(getAuthUrl().getEntity()); } else { provider.setUsername(null); provider.setPassword(null); if (getTenantName().getIsAvailable()) { TenantProviderProperties properties = (TenantProviderProperties) provider.getAdditionalProperties(); if (properties != null) { properties.setTenantName(null); } } provider.setAuthUrl(null); } } protected void preSave() { actualSave(); } protected void actualSave() { flush(); Frontend.getInstance().runAction(action, new ProviderParameters(provider), result -> { if (result.getReturnValue() == null || !result.getReturnValue().getSucceeded()) { return; } sourceListModel.getSearchCommand().execute(); cancel(); }, this); } private void onSave() { if (!validate()) { return; } preSave(); } private void onTest() { if (!validateConnectionSettings()) { getTestResult().setEntity(ConstantsManager.getInstance().getConstants().testFailedInsufficientParams()); return; } flush(); startProgress(); if (provider.getUrl().startsWith(Uri.SCHEME_HTTPS)) { AsyncDataProvider.getInstance().getProviderCertificateChain(new AsyncQuery<>(certs -> { boolean ok = false; certificate = null; if (certs != null) { if (!certs.isEmpty()) { certificate = certs.get(certs.size() - 1).getPayload(); ConfirmationModel confirmationModel = getImportCertificateConfirmationModel(certs.get(certs.size() - 1)); sourceListModel.setConfirmWindow(confirmationModel); ok = true; } } if (!ok) { stopProgress(); getTestResult().setEntity(ConstantsManager.getInstance() .getConstants() .testFailedUnknownErrorMsg()); } }), provider); } else { testProviderConnectivity(); } } private void testProviderConnectivity() { Frontend.getInstance().runAction(VdcActionType.TestProviderConnectivity, new ProviderParameters(provider), result -> { VdcReturnValueBase res = result.getReturnValue(); // If the connection failed on SSL issues, we try to fetch the provider // certificate chain, and import it to the engine stopProgress(); setTestResultValue(res); }, null, false); } private ImportProviderCertificateParameters importCertificateParams() { return new ImportProviderCertificateParameters(provider, certificate); } private ConfirmationModel getImportCertificateConfirmationModel(CertificateInfo certInfo) { ConfirmationModel confirmationModel = new ConfirmationModel(); if (certInfo.getSelfSigned()) { confirmationModel.setMessage( ConstantsManager.getInstance().getMessages().approveRootCertificateTrust( certInfo.getSubject(), certInfo.getSHA1Fingerprint())); } else { confirmationModel.setMessage( ConstantsManager.getInstance().getMessages().approveCertificateTrust( certInfo.getSubject(), certInfo.getIssuer(), certInfo.getSHA1Fingerprint())); } confirmationModel.setTitle(ConstantsManager.getInstance().getConstants().importProviderCertificateTitle()); confirmationModel.setHelpTag(HelpTag.import_provider_certificate); confirmationModel.setHashName("import_provider_certificate"); //$NON-NLS-1$ UICommand importCertificateCommand = new UICommand(CMD_IMPORT_CERTIFICATE, this); importCertificateCommand.setTitle(ConstantsManager.getInstance().getConstants().yes()); importCertificateCommand.setIsDefault(false); confirmationModel.getCommands().add(importCertificateCommand); UICommand cancelImport = new UICommand(CMD_CANCEL_IMPORT, this); cancelImport.setTitle(ConstantsManager.getInstance().getConstants().no()); cancelImport.setIsCancel(true); cancelImport.setIsDefault(true); confirmationModel.getCommands().add(cancelImport); return confirmationModel; } private void importCertificate() { Frontend.getInstance().runAction(VdcActionType.ImportProviderCertificate, importCertificateParams(), result -> testProviderConnectivity(), null, false); sourceListModel.setConfirmWindow(null); } private void cancelImport() { stopProgress(); sourceListModel.setConfirmWindow(null); } @Override public void executeCommand(UICommand command) { super.executeCommand(command); if (CMD_SAVE.equals(command.getName())) { onSave(); } else if (CMD_TEST.equals(command.getName())) { onTest(); } else if (CMD_CANCEL.equals(command.getName())) { cancel(); } else if (CMD_IMPORT_CERTIFICATE.equals(command.getName())) { importCertificate(); } else if (CMD_CANCEL_IMPORT.equals(command.getName())) { cancelImport(); } } private void setTestResultValue(VdcReturnValueBase result) { String errorMessage = EMPTY_ERROR_MESSAGE; if (result == null) { errorMessage = ConstantsManager.getInstance().getConstants().testFailedUnknownErrorMsg(); } else if (!result.getSucceeded()) { errorMessage = result.isValid() ? result.getFault().getMessage() : result.getValidationMessages().get(0); } getTestResult().setEntity(errorMessage); } }