diff --git a/java/code/src/com/redhat/rhn/frontend/strings/nav/StringResource_en_US.xml b/java/code/src/com/redhat/rhn/frontend/strings/nav/StringResource_en_US.xml index 0722a1926ddc..a100ecbe07d0 100644 --- a/java/code/src/com/redhat/rhn/frontend/strings/nav/StringResource_en_US.xml +++ b/java/code/src/com/redhat/rhn/frontend/strings/nav/StringResource_en_US.xml @@ -809,6 +809,12 @@ Navigation Menu + + Clients + + Navigation Menu + + Activation diff --git a/java/code/src/com/redhat/rhn/manager/system/SystemManager.java b/java/code/src/com/redhat/rhn/manager/system/SystemManager.java index 2330c1bf8905..05ab8a05a859 100644 --- a/java/code/src/com/redhat/rhn/manager/system/SystemManager.java +++ b/java/code/src/com/redhat/rhn/manager/system/SystemManager.java @@ -116,7 +116,8 @@ import com.redhat.rhn.manager.system.entitling.SystemEntitlementManager; import com.redhat.rhn.manager.system.entitling.SystemEntitler; import com.redhat.rhn.manager.system.entitling.SystemUnentitler; -import com.redhat.rhn.manager.system.proxycontainerconfig.ProxyContainerConfigCreate; +import com.redhat.rhn.manager.system.proxycontainerconfig.ProxyContainerConfigCreateFacade; +import com.redhat.rhn.manager.system.proxycontainerconfig.ProxyContainerConfigCreateFacadeImpl; import com.redhat.rhn.manager.user.UserManager; import com.redhat.rhn.taskomatic.task.systems.SystemsOverviewUpdateDriver; import com.redhat.rhn.taskomatic.task.systems.SystemsOverviewUpdateWorker; @@ -192,6 +193,7 @@ public class SystemManager extends BaseManager { private SaltApi saltApi; private ServerFactory serverFactory; private ServerGroupFactory serverGroupFactory; + private ProxyContainerConfigCreateFacade proxyContainerConfigCreateFacade; /** * Instantiates a new system manager. @@ -211,6 +213,7 @@ public SystemManager(ServerFactory serverFactoryIn, ServerGroupFactory serverGro new SystemUnentitler(monitoringManager, serverGroupManager), new SystemEntitler(saltApiIn, monitoringManager, serverGroupManager) ); + this.proxyContainerConfigCreateFacade = new ProxyContainerConfigCreateFacadeImpl(); } /** @@ -2156,7 +2159,7 @@ public byte[] createProxyContainerConfig(User user, String proxyName, Integer pr SSLCertManager certManager) throws SSLCertGenerationException { - return new ProxyContainerConfigCreate().create( + return proxyContainerConfigCreateFacade.create( saltApi, systemEntitlementManager, user, server, proxyName, proxyPort, maxCache, email, rootCA, intermediateCAs, proxyCertKey, caPair, caPassword, certData, certManager); } @@ -2191,9 +2194,10 @@ public Map createProxyContainerConfigFiles( SSLCertPair caPair, String caPassword, SSLCertData certData, SSLCertManager certManager ) throws SSLCertGenerationException { - return new ProxyContainerConfigCreate().createFiles( + return this.proxyContainerConfigCreateFacade.createFiles( saltApi, systemEntitlementManager, user, server, proxyName, proxyPort, maxCache, email, - rootCA, intermediateCAs, proxyCertKey, caPair, caPassword, certData, certManager); + rootCA, intermediateCAs, proxyCertKey, caPair, caPassword, certData, certManager + ); } /** diff --git a/java/code/src/com/redhat/rhn/manager/system/proxycontainerconfig/ProxyContainerConfigCreateFacade.java b/java/code/src/com/redhat/rhn/manager/system/proxycontainerconfig/ProxyContainerConfigCreateFacade.java new file mode 100644 index 000000000000..61db45b91c31 --- /dev/null +++ b/java/code/src/com/redhat/rhn/manager/system/proxycontainerconfig/ProxyContainerConfigCreateFacade.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2025 SUSE LLC + * + * This software is licensed to you under the GNU General Public License, + * version 2 (GPLv2). There is NO WARRANTY for this software, express or + * implied, including the implied warranties of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 + * along with this software; if not, see + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * Red Hat trademarks are not licensed under GPLv2. No permission is + * granted to use or replicate Red Hat trademarks that are incorporated + * in this software or its documentation. + */ + +package com.redhat.rhn.manager.system.proxycontainerconfig; + +import com.redhat.rhn.domain.user.User; +import com.redhat.rhn.manager.system.entitling.SystemEntitlementManager; + +import com.suse.manager.ssl.SSLCertData; +import com.suse.manager.ssl.SSLCertManager; +import com.suse.manager.ssl.SSLCertPair; +import com.suse.manager.webui.services.iface.SaltApi; + +import java.util.List; +import java.util.Map; + +public interface ProxyContainerConfigCreateFacade { + + /** + * Create and provide proxy container configuration. + * + * @param saltApi the Salt API instance + * @param systemEntitlementManager the system entitlement manager instance + * @param user the current user + * @param serverFqdn the FQDN of the server the proxy uses + * @param proxyFqdn the FQDN of the proxy + * @param proxyPort the SSH port the proxy listens on + * @param maxCache the maximum memory cache size + * @param email the email of proxy admin + * @param rootCA root CA used to sign the SSL certificate in PEM format + * @param intermediateCAs intermediate CAs used to sign the SSL certificate in PEM format + * @param proxyCertKey proxy CRT and key pair + * @param caPair the CA certificate and key used to sign the certificate to generate. + * Can be omitted if proxyCertKey is not provided + * @param caPassword the CA private key password. + * Can be omitted if proxyCertKey is not provided + * @param certData the data needed to generate the new proxy SSL certificate. + * Can be omitted if proxyCertKey is not provided + * @param certManager the SSLCertManager to use + * @return the tarball configuration file as a byte array + */ + byte[] create( + SaltApi saltApi, SystemEntitlementManager systemEntitlementManager, User user, + String serverFqdn, String proxyFqdn, Integer proxyPort, Long maxCache, String email, + String rootCA, List intermediateCAs, SSLCertPair proxyCertKey, + SSLCertPair caPair, String caPassword, SSLCertData certData, SSLCertManager certManager + ); + + /** + * Create and provide proxy container configuration files. + * + * @param saltApi the Salt API instance + * @param systemEntitlementManager the system entitlement manager instance + * @param user the current user + * @param serverFqdn the FQDN of the server the proxy uses + * @param proxyFqdn the FQDN of the proxy + * @param proxyPort the SSH port the proxy listens on + * @param maxCache the maximum memory cache size + * @param email the email of proxy admin + * @param rootCA root CA used to sign the SSL certificate in PEM format + * @param intermediateCAs intermediate CAs used to sign the SSL certificate in PEM format + * @param proxyCertKey proxy CRT and key pair + * @param caPair the CA certificate and key used to sign the certificate to generate. + * Can be omitted if proxyCertKey is not provided + * @param caPassword the CA private key password. + * Can be omitted if proxyCertKey is not provided + * @param certData the data needed to generate the new proxy SSL certificate. + * Can be omitted if proxyCertKey is not provided + * @param certManager the SSLCertManager to use + * @return the configuration files as a map + */ + Map createFiles( + SaltApi saltApi, SystemEntitlementManager systemEntitlementManager, User user, + String serverFqdn, String proxyFqdn, Integer proxyPort, Long maxCache, String email, + String rootCA, List intermediateCAs, SSLCertPair proxyCertKey, + SSLCertPair caPair, String caPassword, SSLCertData certData, SSLCertManager certManager + ); + +} diff --git a/java/code/src/com/redhat/rhn/manager/system/proxycontainerconfig/ProxyContainerConfigCreate.java b/java/code/src/com/redhat/rhn/manager/system/proxycontainerconfig/ProxyContainerConfigCreateFacadeImpl.java similarity index 93% rename from java/code/src/com/redhat/rhn/manager/system/proxycontainerconfig/ProxyContainerConfigCreate.java rename to java/code/src/com/redhat/rhn/manager/system/proxycontainerconfig/ProxyContainerConfigCreateFacadeImpl.java index 0d866e8333d5..9c6c0342951b 100644 --- a/java/code/src/com/redhat/rhn/manager/system/proxycontainerconfig/ProxyContainerConfigCreate.java +++ b/java/code/src/com/redhat/rhn/manager/system/proxycontainerconfig/ProxyContainerConfigCreateFacadeImpl.java @@ -33,24 +33,23 @@ /** * Main handler for creating proxy container configuration files. * Three files should be created and compressed into a tarball: - * - config.yaml : yaml configuration file that contains the server FQDN, max cache size, email, server version, - * proxy FQDN, and root CA - * - httpd.yaml : yaml file containing the system ID, server certificate, and server key - * - ssh.yaml : yaml file containing the server SSH public key, proxy SSH key, and proxy SSH public key - * + * - config.yaml : yaml configuration file that contains the server FQDN, max cache size, email, server version, + * proxy FQDN, and root CA + * - httpd.yaml : yaml file containing the system ID, server certificate, and server key + * - ssh.yaml : yaml file containing the server SSH public key, proxy SSH key, and proxy SSH public key + *

* This flow is divided into three main steps: * - Acquire and validate all necessary data * - Compute contents for files * - Create tar archive with all necessary files - * */ -public class ProxyContainerConfigCreate { +public class ProxyContainerConfigCreateFacadeImpl implements ProxyContainerConfigCreateFacade { private final List contextHandlerChain = new ArrayList<>(); /** * Constructor */ - public ProxyContainerConfigCreate() { + public ProxyContainerConfigCreateFacadeImpl() { this.contextHandlerChain.addAll(asList( new ProxyContainerConfigCreateAcquisitor(), new ProxyContainerConfigCreateGenerateFileMaps(), @@ -81,6 +80,7 @@ public ProxyContainerConfigCreate() { * @param certManager the SSLCertManager to use * @return the tarball configuration file as a byte array */ + @Override public byte[] create( SaltApi saltApi, SystemEntitlementManager systemEntitlementManager, User user, String serverFqdn, String proxyFqdn, Integer proxyPort, Long maxCache, String email, @@ -120,6 +120,7 @@ public byte[] create( * @param certManager the SSLCertManager to use * @return the configuration files as a map */ + @Override public Map createFiles( SaltApi saltApi, SystemEntitlementManager systemEntitlementManager, User user, String serverFqdn, String proxyFqdn, Integer proxyPort, Long maxCache, String email, diff --git a/java/code/src/com/suse/manager/webui/controllers/ProxyConfigurationController.java b/java/code/src/com/suse/manager/webui/controllers/ProxyConfigurationController.java index 1c25a34ebc1f..9991337c1956 100644 --- a/java/code/src/com/suse/manager/webui/controllers/ProxyConfigurationController.java +++ b/java/code/src/com/suse/manager/webui/controllers/ProxyConfigurationController.java @@ -26,37 +26,26 @@ import static spark.Spark.get; import static spark.Spark.post; -import com.redhat.rhn.GlobalInstanceHolder; import com.redhat.rhn.common.RhnGeneralException; import com.redhat.rhn.common.RhnRuntimeException; -import com.redhat.rhn.common.conf.Config; -import com.redhat.rhn.common.conf.ConfigDefaults; -import com.redhat.rhn.common.db.datasource.DataResult; -import com.redhat.rhn.common.validator.ValidatorResult; import com.redhat.rhn.domain.server.Server; -import com.redhat.rhn.domain.server.ServerFactory; import com.redhat.rhn.domain.user.User; -import com.redhat.rhn.frontend.dto.ShortSystemInfo; -import com.redhat.rhn.manager.entitlement.EntitlementManager; import com.redhat.rhn.manager.system.SystemManager; -import com.redhat.rhn.manager.system.entitling.SystemEntitlementManager; import com.suse.manager.api.ParseException; import com.suse.manager.reactor.utils.LocalDateTimeISOAdapter; import com.suse.manager.reactor.utils.OptionalTypeAdapterFactory; -import com.suse.manager.utils.MinionServerUtils; import com.suse.manager.webui.services.iface.SaltApi; import com.suse.manager.webui.utils.gson.ProxyConfigUpdateJson; import com.suse.manager.webui.utils.gson.ResultJson; -import com.suse.manager.webui.utils.gson.SimpleMinionJson; -import com.suse.proxy.ProxyConfigUtils; import com.suse.proxy.ProxyContainerImagesEnum; import com.suse.proxy.ProxyRegistryUtils; import com.suse.proxy.ProxyRegistryUtilsImpl; import com.suse.proxy.RegistryUrl; -import com.suse.proxy.get.ProxyConfigGet; -import com.suse.proxy.update.ProxyConfigUpdate; -import com.suse.utils.Json; +import com.suse.proxy.get.ProxyConfigGetFacade; +import com.suse.proxy.get.ProxyConfigGetFacadeImpl; +import com.suse.proxy.update.ProxyConfigUpdateFacade; +import com.suse.proxy.update.ProxyConfigUpdateFacadeImpl; import com.google.gson.Gson; import com.google.gson.GsonBuilder; @@ -69,14 +58,10 @@ import java.net.URISyntaxException; import java.time.LocalDateTime; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; -import java.util.HashMap; import java.util.HashSet; import java.util.List; -import java.util.Map; import java.util.Set; -import java.util.stream.Collectors; import spark.ModelAndView; import spark.Request; @@ -95,8 +80,9 @@ public class ProxyConfigurationController { private final SystemManager systemManager; private final SaltApi saltApi; - private SystemEntitlementManager systemEntitlementManager = GlobalInstanceHolder.SYSTEM_ENTITLEMENT_MANAGER; - private ProxyRegistryUtils proxyRegistryUtils = new ProxyRegistryUtilsImpl(); + private final ProxyRegistryUtils proxyRegistryUtils; + private final ProxyConfigUpdateFacade proxyConfigUpdateFacade; + private final ProxyConfigGetFacade proxyConfigGetFacade; private static final Gson GSON = new GsonBuilder() .registerTypeAdapter(LocalDateTime.class, new LocalDateTimeISOAdapter()) @@ -105,14 +91,42 @@ public class ProxyConfigurationController { .create(); /** - * Create a new controller instance + * Create a new controller instance with default facades implementations * * @param systemManagerIn the system manager * @param saltApiIn the salt API */ public ProxyConfigurationController(SystemManager systemManagerIn, SaltApi saltApiIn) { + this( + systemManagerIn, + saltApiIn, + new ProxyRegistryUtilsImpl(), + new ProxyConfigUpdateFacadeImpl(), + new ProxyConfigGetFacadeImpl() + ); + } + + /** + * Create a new controller instance + * + * @param systemManagerIn the system manager + * @param saltApiIn the salt API + * @param proxyRegistryUtilsIn the proxy registry utils + * @param proxyConfigUpdateFacadeIn the proxy config update facade + * @param proxyConfigGetFacadeIn the proxy config get facade + */ + public ProxyConfigurationController( + SystemManager systemManagerIn, + SaltApi saltApiIn, + ProxyRegistryUtils proxyRegistryUtilsIn, + ProxyConfigUpdateFacade proxyConfigUpdateFacadeIn, + ProxyConfigGetFacade proxyConfigGetFacadeIn + ) { this.systemManager = systemManagerIn; this.saltApi = saltApiIn; + this.proxyRegistryUtils = proxyRegistryUtilsIn; + this.proxyConfigUpdateFacade = proxyConfigUpdateFacadeIn; + this.proxyConfigGetFacade = proxyConfigGetFacadeIn; } /** @@ -123,7 +137,7 @@ public ProxyConfigurationController(SystemManager systemManagerIn, SaltApi saltA */ public void initRoutes(ProxyConfigurationController proxyController, JadeTemplateEngine jade) { get("/manager/systems/details/proxy-config", - withCsrfToken(withDocsLocale(withUserAndServer(this::proxyConfig))), + withCsrfToken(withDocsLocale(withUserAndServer(this::getProxyConfiguration))), jade ); post("/manager/systems/details/proxy-config", withUser(this::updateProxyConfiguration)); @@ -139,70 +153,8 @@ public void initRoutes(ProxyConfigurationController proxyController, JadeTemplat * @param server the current server * @return the ModelAndView object to render the page */ - public ModelAndView proxyConfig(Request request, Response response, User user, Server server) { - Map data = new HashMap<>(); - - // Handle the "Convert to Proxy" button: if server is convertible to proxy and doesn't have the proxy - // entitlement, add it - if (server.isConvertibleToProxy() && !server.hasProxyEntitlement()) { - user.getOrg().getValidAddOnEntitlementsForOrg().stream() - .filter(e -> e.getLabel().equalsIgnoreCase(EntitlementManager.PROXY_ENTITLED)) - .findFirst() - .ifPresentOrElse(f -> { - ValidatorResult vr = systemEntitlementManager.addEntitlementToServer(server, f); - if (!vr.getErrors().isEmpty()) { - LOG.error("Failed to add proxy entitlement to server. Server ID: {}, " + - "hasProxyEntitlement: {}, isConvertibleToProxy: {}, errors: {}", - server.getId(), - server.hasProxyEntitlement(), - server.isConvertibleToProxy(), - vr.getErrors() - ); - data.put("initFailMessage", "Failed to automatically add proxy entitlement to server."); - } - }, () -> { - }); - } - - Map proxyConfigDataMap = - ProxyConfigUtils.safeDataMapFromProxyConfig(new ProxyConfigGet().get(server)); - data.put("currentConfig", Json.GSON.toJson(proxyConfigDataMap)); - data.put("parents", Json.GSON.toJson(getElectableParents(user))); - data.put("isUyuni", ConfigDefaults.get().isUyuni()); - return new ModelAndView(data, "templates/minion/proxy-config.jade"); - } - - /** - * Get the list of electable parents to use as parent. - * - * @param user the current user - * @return the list of electable parents - */ - public List getElectableParents(User user) { - DataResult dr = SystemManager.systemListShort(user, null); - dr.elaborate(); - Set systems = Arrays.stream(dr.toArray()) - .map(system -> ((ShortSystemInfo) system).getId()). - collect(Collectors.toSet()); - - List electableParentsServers = - ServerFactory.lookupByIdsAndOrg(systems, user.getOrg()).stream().filter(Server::isProxy).toList(); - List electableParentsAsSimpleMinionJson = new ArrayList<>( - MinionServerUtils.filterSaltMinions(electableParentsServers) - .map(SimpleMinionJson::fromMinionServer) - .toList() - ); - - String localManagerFqdn = Config.get().getString(ConfigDefaults.SERVER_HOSTNAME); - if (isAbsent(localManagerFqdn)) { - if (LOG.isErrorEnabled()) { - LOG.error("Could not determine the Server FQDN. Skipping it as a parent."); - } - return electableParentsAsSimpleMinionJson; - } - - electableParentsAsSimpleMinionJson.add(new SimpleMinionJson(-1L, localManagerFqdn)); - return electableParentsAsSimpleMinionJson; + public ModelAndView getProxyConfiguration(Request request, Response response, User user, Server server) { + return new ModelAndView(proxyConfigGetFacade.getFormData(user, server), "templates/minion/proxy-config.jade"); } /** @@ -330,7 +282,7 @@ public String updateProxyConfiguration(Request request, Response response, User GSON.fromJson(request.body(), new TypeToken() { }.getType()); try { - new ProxyConfigUpdate().update(data, systemManager, saltApi, user); + proxyConfigUpdateFacade.update(data, systemManager, saltApi, user); return result(response, ResultJson.success("Proxy configuration applied")); } catch (RhnRuntimeException e) { diff --git a/java/code/src/com/suse/manager/webui/services/SaltServerActionService.java b/java/code/src/com/suse/manager/webui/services/SaltServerActionService.java index 621f967f448a..554332f60ae6 100644 --- a/java/code/src/com/suse/manager/webui/services/SaltServerActionService.java +++ b/java/code/src/com/suse/manager/webui/services/SaltServerActionService.java @@ -221,7 +221,7 @@ public class SaltServerActionService { public static final String APPSTREAMS_CONFIGURE = "appstreams.configure"; public static final String PARAM_APPSTREAMS_ENABLE = "param_appstreams_enable"; public static final String PARAM_APPSTREAMS_DISABLE = "param_appstreams_disable"; - public static final String APPLY_PROXY_CONFIG = "apply_proxy_config"; + public static final String APPLY_PROXY_CONFIG = "proxy.apply_proxy_config"; /** SLS pillar parameter name for the list of update stack patch names. */ public static final String PARAM_UPDATE_STACK_PATCHES = "param_update_stack_patches"; diff --git a/java/code/src/com/suse/manager/webui/utils/gson/ProxyConfigUpdateJson.java b/java/code/src/com/suse/manager/webui/utils/gson/ProxyConfigUpdateJson.java index 31a41099fafc..275ef3109d9f 100644 --- a/java/code/src/com/suse/manager/webui/utils/gson/ProxyConfigUpdateJson.java +++ b/java/code/src/com/suse/manager/webui/utils/gson/ProxyConfigUpdateJson.java @@ -19,7 +19,7 @@ import java.util.List; /** - * Represents the data sent from the UI to convert a minion into a proxy container configuration + * Represents the data received from the UI to convert a minion into a proxy container configuration */ public class ProxyConfigUpdateJson { diff --git a/java/code/src/com/suse/proxy/ProxyConfigUtils.java b/java/code/src/com/suse/proxy/ProxyConfigUtils.java index f9d0a8bbf53c..bca58d079171 100644 --- a/java/code/src/com/suse/proxy/ProxyConfigUtils.java +++ b/java/code/src/com/suse/proxy/ProxyConfigUtils.java @@ -30,20 +30,25 @@ import com.suse.proxy.model.ProxyConfig; import com.suse.proxy.model.ProxyConfigImage; +import java.util.Arrays; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; /** * Utility class for handling Proxy Config * Includes relevant constants and mappings from DTO / Pillar + * Pillar entries for the registry URLs will follow the example format: + * { ..., "registries": { "proxy-httpd": { "url": "https://.../proxy-httpd", "tag": "latest" }, ... } } + * names for the registry entries are defined in ProxyContainerImagesEnum image names */ public class ProxyConfigUtils { - private static final String SAFE_SUFFIX = "_safe"; - private static final String CERTIFICATE_HEADER = "-----BEGIN CERTIFICATE-----\n"; - - private ProxyConfigUtils() { throw new UnsupportedOperationException(NOT_INSTANTIABLE); } @@ -74,16 +79,11 @@ private ProxyConfigUtils() { public static final String REGISTRY_BASE_URL = "registryBaseURL"; public static final String REGISTRY_BASE_TAG = "registryBaseTag"; - - // Pillar entries - // The pillar entries for the registry URLs will follow the example format: - // { ..., "registries": { "proxy-httpd": { "url": "https://.../proxy-httpd", "tag": "latest" }, ... } } - // names for the registry entries are defined in ProxyContainerImagesEnum image names + // Registry entries public static final String PILLAR_REGISTRY_ENTRY = "registries"; public static final String PILLAR_REGISTRY_URL_ENTRY = "url"; public static final String PILLAR_REGISTRY_TAG_ENTRY = "tag"; - /** * Maps a minion pillar ProxyConfig * @@ -91,20 +91,23 @@ private ProxyConfigUtils() { * @return the ProxyConfig */ public static ProxyConfig proxyConfigFromPillar(Pillar rootPillar) { - Map pillar = rootPillar.getPillar(); ProxyConfig proxyConfig = new ProxyConfig(); - proxyConfig.setServerId((Long) pillar.get(SERVER_ID_FIELD)); - proxyConfig.setProxyFqdn(String.valueOf(pillar.get(PROXY_FQDN_FIELD))); + if (rootPillar == null || rootPillar.getPillar() == null) { + return proxyConfig; + } + Map pillar = rootPillar.getPillar(); - proxyConfig.setParentFqdn(String.valueOf(pillar.get(PARENT_FQDN_FIELD))); + proxyConfig.setServerId((Long) pillar.get(SERVER_ID_FIELD)); + proxyConfig.setProxyFqdn(Objects.toString(pillar.get(PROXY_FQDN_FIELD), null)); + proxyConfig.setParentFqdn(Objects.toString(pillar.get(PARENT_FQDN_FIELD), null)); proxyConfig.setProxyPort((Integer) pillar.get(PROXY_PORT_FIELD)); proxyConfig.setMaxCache((Integer) pillar.get(MAX_CACHE_FIELD)); - proxyConfig.setEmail(String.valueOf(pillar.get(EMAIL_FIELD))); - proxyConfig.setRootCA(String.valueOf(pillar.get(ROOT_CA_FIELD))); + proxyConfig.setEmail(Objects.toString(pillar.get(EMAIL_FIELD), null)); + proxyConfig.setRootCA(Objects.toString(pillar.get(ROOT_CA_FIELD), null)); proxyConfig.setIntermediateCAs((List) pillar.get(INTERMEDIATE_CAS_FIELD)); - proxyConfig.setProxyCert(String.valueOf(pillar.get(PROXY_CERT_FIELD))); - proxyConfig.setProxyKey(String.valueOf(pillar.get(PROXY_KEY_FIELD))); + proxyConfig.setProxyCert(Objects.toString(pillar.get(PROXY_CERT_FIELD), null)); + proxyConfig.setProxyKey(Objects.toString(pillar.get(PROXY_KEY_FIELD), null)); Map registries = (Map) pillar.get(PILLAR_REGISTRY_ENTRY); @@ -162,12 +165,12 @@ public static ProxyConfig proxyConfigFromPillar(Pillar rootPillar) { } /** - * Maps a ProxyConfig to a safe data map + * Maps a ProxyConfig * * @param proxyConfig the ProxyConfig - * @return the safe data map + * @return the data map */ - public static Map safeDataMapFromProxyConfig(ProxyConfig proxyConfig) { + public static Map dataMapFromProxyConfig(ProxyConfig proxyConfig) { Map data = new HashMap<>(); if (isAbsent(proxyConfig)) { @@ -180,56 +183,69 @@ public static Map safeDataMapFromProxyConfig(ProxyConfig proxyCo data.put(PROXY_PORT_FIELD, proxyConfig.getProxyPort()); data.put(MAX_CACHE_FIELD, proxyConfig.getMaxCache()); data.put(EMAIL_FIELD, proxyConfig.getEmail()); - data.put(ROOT_CA_FIELD + SAFE_SUFFIX, getSafeCertInput(proxyConfig.getRootCA())); - data.put(PROXY_CERT_FIELD + SAFE_SUFFIX, getSafeCertInput(proxyConfig.getProxyCert())); - data.put(PROXY_KEY_FIELD + SAFE_SUFFIX, getSafeCertInput(proxyConfig.getProxyKey())); - - List intermediateCAs = proxyConfig.getIntermediateCAs(); - if (isProvided(intermediateCAs)) { - data.put(INTERMEDIATE_CAS_FIELD + SAFE_SUFFIX, - intermediateCAs.stream() - .map(ProxyConfigUtils::getSafeCertInput) - .toList()); - } + + data.put(USE_CERTS_MODE_FIELD, USE_CERTS_MODE_KEEP); ProxyConfigImage httpdImage = proxyConfig.getHttpdImage(); + ProxyConfigImage saltBrokerImage = proxyConfig.getSaltBrokerImage(); + ProxyConfigImage squidImage = proxyConfig.getSquidImage(); + ProxyConfigImage sshImage = proxyConfig.getSshImage(); + ProxyConfigImage tftpdImage = proxyConfig.getTftpdImage(); + + // If all images are absent, we assume the source mode is RPM + if (allAbsent(httpdImage, saltBrokerImage, squidImage, sshImage, tftpdImage)) { + data.put(SOURCE_MODE_FIELD, ProxyConfigUtils.SOURCE_MODE_RPM); + return data; + } + + // Otherwise we assume the source mode is registry + data.put(SOURCE_MODE_FIELD, ProxyConfigUtils.SOURCE_MODE_REGISTRY); + + // Check if all images have the same tag and prefix + boolean isRegistryModeSimple = + ProxyConfigUtils.getCommonTag(httpdImage, saltBrokerImage, squidImage, sshImage, tftpdImage) + .map(tag -> + ProxyConfigUtils.getCommonPrefix(httpdImage, saltBrokerImage, squidImage, sshImage, tftpdImage) + .map(prefix -> { + data.put(REGISTRY_MODE, ProxyConfigUtils.REGISTRY_MODE_SIMPLE); + data.put(REGISTRY_BASE_TAG, tag); + data.put(REGISTRY_BASE_URL, prefix); + return true; + }) + .orElse(false)) + .orElse(false); + + if (isRegistryModeSimple) { + return data; + } + + // Otherwise registry mode is advanced + data.put(REGISTRY_MODE, ProxyConfigUtils.REGISTRY_MODE_ADVANCED); if (isProvided(httpdImage)) { data.put(PROXY_HTTPD.getUrlField(), httpdImage.getUrl()); data.put(PROXY_HTTPD.getTagField(), httpdImage.getTag()); } - ProxyConfigImage saltBrokerImage = proxyConfig.getSaltBrokerImage(); if (isProvided(saltBrokerImage)) { data.put(PROXY_SALT_BROKER.getUrlField(), saltBrokerImage.getUrl()); data.put(PROXY_SALT_BROKER.getTagField(), saltBrokerImage.getTag()); } - ProxyConfigImage squidImage = proxyConfig.getSquidImage(); if (isProvided(squidImage)) { data.put(PROXY_SQUID.getUrlField(), squidImage.getUrl()); data.put(PROXY_SQUID.getTagField(), squidImage.getTag()); } - ProxyConfigImage sshImage = proxyConfig.getSshImage(); if (isProvided(sshImage)) { data.put(PROXY_SSH.getUrlField(), sshImage.getUrl()); data.put(PROXY_SSH.getTagField(), sshImage.getTag()); } - ProxyConfigImage tftpdImage = proxyConfig.getTftpdImage(); if (isProvided(tftpdImage)) { data.put(PROXY_TFTPD.getUrlField(), tftpdImage.getUrl()); data.put(PROXY_TFTPD.getTagField(), tftpdImage.getTag()); } - if (allAbsent(httpdImage, saltBrokerImage, squidImage, sshImage, tftpdImage)) { - data.put(SOURCE_MODE_FIELD, ProxyConfigUtils.SOURCE_MODE_RPM); - } - else { - data.put(SOURCE_MODE_FIELD, ProxyConfigUtils.SOURCE_MODE_REGISTRY); - data.put(REGISTRY_MODE, ProxyConfigUtils.REGISTRY_MODE_ADVANCED); - } - return data; } @@ -241,9 +257,13 @@ public static Map safeDataMapFromProxyConfig(ProxyConfig proxyCo * @return a map of the data for the apply_proxy_config salt state file */ public static Map applyProxyConfigDataFromPillar(Pillar rootPillar) { - Map pillar = rootPillar.getPillar(); Map data = new HashMap<>(); + if (rootPillar == null || rootPillar.getPillar() == null || rootPillar.getPillar().isEmpty()) { + return data; + } + Map pillar = rootPillar.getPillar(); + data.put(PARENT_FQDN_FIELD, pillar.get(PARENT_FQDN_FIELD)); data.put(PROXY_PORT_FIELD, pillar.get(PROXY_PORT_FIELD)); data.put(MAX_CACHE_FIELD, pillar.get(MAX_CACHE_FIELD)); @@ -274,17 +294,75 @@ public static Map applyProxyConfigDataFromPillar(Pillar rootPill /** - * Returns a preview of the certificate to be used as a (safe) preview - * Truncates the input to the 10 characters. + * Verifies if all the images have the same (non-nullable) tag * - * @param cert the input string - * @return the safe certificate input + * @param images the images to be verified + * @return the common tag if all images have the same tag, otherwise empty */ - public static String getSafeCertInput(String cert) { - if (isAbsent(cert)) { - return null; + public static Optional getCommonTag(ProxyConfigImage... images) { + if (isAbsent(images)) { + return Optional.empty(); } - String content = cert.startsWith(CERTIFICATE_HEADER) ? cert.substring(CERTIFICATE_HEADER.length()) : cert; - return content.length() <= 10 ? content : content.substring(0, 10) + "..."; + + Set tags = new HashSet<>(); + for (ProxyConfigImage image : images) { + if (image == null || image.getTag() == null) { + return Optional.empty(); + } + tags.add(image.getTag()); + } + + return tags.size() == 1 ? Optional.of(tags.iterator().next()) : Optional.empty(); } + + /** + * Verifies if all the images url have a common prefix + * + * @param images the images to be verified + * @return the common prefix if all images have the same prefix, otherwise empty + */ + public static Optional getCommonPrefix(ProxyConfigImage... images) { + if (isAbsent(images)) { + return Optional.empty(); + } + + Set allowedImageNames = Arrays.stream(ProxyContainerImagesEnum.values()) + .map(ProxyContainerImagesEnum::getImageName) + .collect(Collectors.toSet()); + + Set imageUrlPrefixes = new HashSet<>(); + + for (ProxyConfigImage image : images) { + if (image == null || image.getUrl() == null) { + return Optional.empty(); + } + + String url = image.getUrl(); + int lastSlash = url.lastIndexOf('/'); + + // If there is no slash, the image name is already invalid + if (lastSlash == -1) { + return Optional.empty(); + } + + // If the image name not provided or not in the allowed image names, then no common prefix + String imageName = url.substring(lastSlash + 1); + if (isAbsent(imageName) || !allowedImageNames.contains(imageName)) { + return Optional.empty(); + } + + // If the prefix is not provided, then no common prefix + String urlPrefix = url.substring(0, lastSlash + 1); + if (isAbsent(urlPrefix)) { + return Optional.empty(); + } + + // Add the prefix to a set + imageUrlPrefixes.add(urlPrefix); + } + + // If the set does not contain exactly one entry, then no common prefix + return imageUrlPrefixes.size() == 1 ? Optional.of(imageUrlPrefixes.iterator().next()) : Optional.empty(); + } + } diff --git a/java/code/src/com/suse/proxy/get/ProxyConfigGet.java b/java/code/src/com/suse/proxy/get/ProxyConfigGetFacade.java similarity index 60% rename from java/code/src/com/suse/proxy/get/ProxyConfigGet.java rename to java/code/src/com/suse/proxy/get/ProxyConfigGetFacade.java index 3738903ec274..273cc82b67fa 100644 --- a/java/code/src/com/suse/proxy/get/ProxyConfigGet.java +++ b/java/code/src/com/suse/proxy/get/ProxyConfigGetFacade.java @@ -15,29 +15,31 @@ package com.suse.proxy.get; -import static com.suse.proxy.ProxyConfigUtils.PROXY_PILLAR_CATEGORY; -import static com.suse.utils.Predicates.isAbsent; - import com.redhat.rhn.domain.server.Server; +import com.redhat.rhn.domain.user.User; -import com.suse.proxy.ProxyConfigUtils; import com.suse.proxy.model.ProxyConfig; -public class ProxyConfigGet { +import java.util.Map; + +/** + * Interface for operations that retrieve proxy configuration data. + */ +public interface ProxyConfigGetFacade { /** * Get the proxy configuration * @param server the server * @return the proxy configuration */ - public ProxyConfig get(Server server) { - if (isAbsent(server)) { - return null; - } - return server.asMinionServer() - .flatMap(minionServer -> minionServer - .getPillarByCategory(PROXY_PILLAR_CATEGORY) - .map(ProxyConfigUtils::proxyConfigFromPillar)) - .orElse(null); - } + ProxyConfig getProxyConfig(Server server); + + /** + * Get the data to be rendered in the form + * @param user the user + * @param server the server + * @return the form data + */ + Map getFormData(User user, Server server); + } diff --git a/java/code/src/com/suse/proxy/get/ProxyConfigGetFacadeImpl.java b/java/code/src/com/suse/proxy/get/ProxyConfigGetFacadeImpl.java new file mode 100644 index 000000000000..6a2c9a3b1019 --- /dev/null +++ b/java/code/src/com/suse/proxy/get/ProxyConfigGetFacadeImpl.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2025 SUSE LLC + * + * This software is licensed to you under the GNU General Public License, + * version 2 (GPLv2). There is NO WARRANTY for this software, express or + * implied, including the implied warranties of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 + * along with this software; if not, see + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * Red Hat trademarks are not licensed under GPLv2. No permission is + * granted to use or replicate Red Hat trademarks that are incorporated + * in this software or its documentation. + */ + +package com.suse.proxy.get; + +import static com.suse.proxy.ProxyConfigUtils.PROXY_PILLAR_CATEGORY; +import static com.suse.utils.Predicates.isAbsent; +import static java.util.Arrays.asList; + +import com.redhat.rhn.common.conf.ConfigDefaults; +import com.redhat.rhn.domain.server.Server; +import com.redhat.rhn.domain.user.User; + +import com.suse.proxy.ProxyConfigUtils; +import com.suse.proxy.get.formdata.ProxyConfigGetFormDataAcquisitor; +import com.suse.proxy.get.formdata.ProxyConfigGetFormDataContext; +import com.suse.proxy.get.formdata.ProxyConfigGetFormDataContextHandler; +import com.suse.proxy.get.formdata.ProxyConfigGetFormDataProxyInitializer; +import com.suse.proxy.model.ProxyConfig; +import com.suse.utils.Json; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Class responsible for getting proxy configurations + */ +public class ProxyConfigGetFacadeImpl implements ProxyConfigGetFacade { + private final List getFormDataContextHandlerChain = new ArrayList<>(); + + /** + * Constructor + */ + public ProxyConfigGetFacadeImpl() { + this.getFormDataContextHandlerChain.addAll(asList( + new ProxyConfigGetFormDataProxyInitializer(), + new ProxyConfigGetFormDataAcquisitor() + )); + } + + /** + * Get the proxy configuration + * + * @param server the server + * @return the proxy configuration + */ + @Override + public ProxyConfig getProxyConfig(Server server) { + if (isAbsent(server)) { + return null; + } + return server.asMinionServer() + .flatMap(minionServer -> minionServer + .getPillarByCategory(PROXY_PILLAR_CATEGORY) + .map(ProxyConfigUtils::proxyConfigFromPillar)) + .orElse(null); + } + + /** + * Get the data to be rendered in the form + * + * @param user the user + * @param server the server + * @return the form data + */ + @Override + public Map getFormData(User user, Server server) { + ProxyConfigGetFormDataContext context = new ProxyConfigGetFormDataContext(user, server, this.getProxyConfig(server)); + + for (ProxyConfigGetFormDataContextHandler handler : getFormDataContextHandlerChain) { + handler.handle(context); + } + + Map data = new HashMap<>(); + data.put("currentConfig", Json.GSON.toJson(context.getProxyConfigAsMap())); + data.put("parents", Json.GSON.toJson(context.getElectableParentsFqdn())); + data.put("isUyuni", context.isUyuni()); + data.put("initFailMessage", context.getInitFailMessage()); + + return data; + } + + + +} diff --git a/java/code/src/com/suse/proxy/get/formdata/ProxyConfigGetFormDataAcquisitor.java b/java/code/src/com/suse/proxy/get/formdata/ProxyConfigGetFormDataAcquisitor.java new file mode 100644 index 000000000000..f8a1306fcf82 --- /dev/null +++ b/java/code/src/com/suse/proxy/get/formdata/ProxyConfigGetFormDataAcquisitor.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2025 SUSE LLC + * + * This software is licensed to you under the GNU General Public License, + * version 2 (GPLv2). There is NO WARRANTY for this software, express or + * implied, including the implied warranties of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 + * along with this software; if not, see + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * Red Hat trademarks are not licensed under GPLv2. No permission is + * granted to use or replicate Red Hat trademarks that are incorporated + * in this software or its documentation. + */ + +package com.suse.proxy.get.formdata; + +import static com.suse.utils.Predicates.isAbsent; + +import com.redhat.rhn.common.conf.Config; +import com.redhat.rhn.common.conf.ConfigDefaults; +import com.redhat.rhn.common.db.datasource.DataResult; +import com.redhat.rhn.frontend.dto.OrgProxyServer; +import com.redhat.rhn.manager.system.SystemManager; + +import com.suse.proxy.ProxyConfigUtils; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * This step acquired the data required for the proxy configuration form + * But also sets a few defaults + */ +public class ProxyConfigGetFormDataAcquisitor implements ProxyConfigGetFormDataContextHandler { + private static final Logger LOG = LogManager.getLogger(ProxyConfigGetFormDataAcquisitor.class); + + @Override + public void handle(ProxyConfigGetFormDataContext context) { + context.setProxyConfigAsMap(ProxyConfigUtils.dataMapFromProxyConfig(context.getProxyConfig())); + retrieveElectableParentsFqdn(context); + } + + /** + * Retrieves the electable parents FQDNs + * Electable parents are all the proxy in the organization (except the current server) and also the local manager + * + * @param context the context + */ + private void retrieveElectableParentsFqdn(ProxyConfigGetFormDataContext context) { + String localManagerFqdn = Config.get().getString(ConfigDefaults.SERVER_HOSTNAME); + + DataResult orgProxyServers = SystemManager.listProxies(context.getUser().getOrg()); + Set electableParents = orgProxyServers.stream() + .filter(s -> !Objects.equals(s.getId(), context.getServer().getId())) + .map(OrgProxyServer::getName) + .collect(Collectors.toSet()); + + if (isAbsent(localManagerFqdn)) { + LOG.error("Could not determine the Server FQDN. Skipping it as a parent."); + } + else { + electableParents.add(localManagerFqdn); + } + + context.setElectableParentsFqdn(electableParents.stream().sorted().toList()); + } +} diff --git a/java/code/src/com/suse/proxy/get/formdata/ProxyConfigGetFormDataContext.java b/java/code/src/com/suse/proxy/get/formdata/ProxyConfigGetFormDataContext.java new file mode 100644 index 000000000000..4abca9aa8597 --- /dev/null +++ b/java/code/src/com/suse/proxy/get/formdata/ProxyConfigGetFormDataContext.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2025 SUSE LLC + * + * This software is licensed to you under the GNU General Public License, + * version 2 (GPLv2). There is NO WARRANTY for this software, express or + * implied, including the implied warranties of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 + * along with this software; if not, see + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * Red Hat trademarks are not licensed under GPLv2. No permission is + * granted to use or replicate Red Hat trademarks that are incorporated + * in this software or its documentation. + */ + +package com.suse.proxy.get.formdata; + +import com.redhat.rhn.common.conf.ConfigDefaults; +import com.redhat.rhn.domain.server.Server; +import com.redhat.rhn.domain.user.User; + +import com.suse.proxy.model.ProxyConfig; + +import java.util.List; +import java.util.Map; + +/** + * This class holds relevant data through the steps for acquiding the form data for the proxy config. + */ +public class ProxyConfigGetFormDataContext { + + private final User user; + private final Server server; + private final ProxyConfig proxyConfig; + + private Map proxyConfigAsMap; + private List electableParentsFqdn; + private String initFailMessage; + + /** + * Constructor + * + * @param userIn the user + * @param serverIn the server + * @param proxyConfigIn the current proxy configuration + */ + public ProxyConfigGetFormDataContext(User userIn, Server serverIn, ProxyConfig proxyConfigIn) { + this.user = userIn; + this.server = serverIn; + this.proxyConfig = proxyConfigIn; + } + + public User getUser() { + return user; + } + + public Server getServer() { + return server; + } + + public Map getProxyConfigAsMap() { + return proxyConfigAsMap; + } + + public void setProxyConfigAsMap(Map proxyConfigAsMapIn) { + proxyConfigAsMap = proxyConfigAsMapIn; + } + + public List getElectableParentsFqdn() { + return electableParentsFqdn; + } + + public void setElectableParentsFqdn(List electableParentsFqdnIn) { + electableParentsFqdn = electableParentsFqdnIn; + } + + public boolean isUyuni() { + return ConfigDefaults.get().isUyuni(); + + } + + public void setInitFailMessage(String initFailMessageIn) { + this.initFailMessage = initFailMessageIn; + } + + public ProxyConfig getProxyConfig() { + return proxyConfig; + } + + public String getInitFailMessage() { + return initFailMessage; + } +} \ No newline at end of file diff --git a/java/code/src/com/suse/proxy/get/formdata/ProxyConfigGetFormDataContextHandler.java b/java/code/src/com/suse/proxy/get/formdata/ProxyConfigGetFormDataContextHandler.java new file mode 100644 index 000000000000..9de38aa22f97 --- /dev/null +++ b/java/code/src/com/suse/proxy/get/formdata/ProxyConfigGetFormDataContextHandler.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2025 SUSE LLC + * + * This software is licensed to you under the GNU General Public License, + * version 2 (GPLv2). There is NO WARRANTY for this software, express or + * implied, including the implied warranties of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 + * along with this software; if not, see + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * Red Hat trademarks are not licensed under GPLv2. No permission is + * granted to use or replicate Red Hat trademarks that are incorporated + * in this software or its documentation. + */ + +package com.suse.proxy.get.formdata; + +public interface ProxyConfigGetFormDataContextHandler { + /** + * Handles a step in saving a proxy configuration + * @param context the context + */ + void handle(ProxyConfigGetFormDataContext context); +} diff --git a/java/code/src/com/suse/proxy/get/formdata/ProxyConfigGetFormDataProxyInitializer.java b/java/code/src/com/suse/proxy/get/formdata/ProxyConfigGetFormDataProxyInitializer.java new file mode 100644 index 000000000000..4a6dde1a478e --- /dev/null +++ b/java/code/src/com/suse/proxy/get/formdata/ProxyConfigGetFormDataProxyInitializer.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2025 SUSE LLC + * + * This software is licensed to you under the GNU General Public License, + * version 2 (GPLv2). There is NO WARRANTY for this software, express or + * implied, including the implied warranties of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 + * along with this software; if not, see + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * Red Hat trademarks are not licensed under GPLv2. No permission is + * granted to use or replicate Red Hat trademarks that are incorporated + * in this software or its documentation. + */ + +package com.suse.proxy.get.formdata; + +import com.redhat.rhn.GlobalInstanceHolder; +import com.redhat.rhn.common.validator.ValidatorResult; +import com.redhat.rhn.domain.server.ProxyInfo; +import com.redhat.rhn.domain.server.Server; +import com.redhat.rhn.manager.entitlement.EntitlementManager; +import com.redhat.rhn.manager.system.SystemManager; +import com.redhat.rhn.manager.system.entitling.SystemEntitlementManager; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +/** + * Ensures the correct behavior of the "Convert to Proxy" button. + * If the server is convertible to a proxy and: + * a) Does not have the proxy entitlement, it is added. + * b) Does not have a {@link ProxyInfo}, it is created. + */ +public class ProxyConfigGetFormDataProxyInitializer implements ProxyConfigGetFormDataContextHandler { + private static final Logger LOG = LogManager.getLogger(ProxyConfigGetFormDataProxyInitializer.class); + private static final SystemEntitlementManager SYSTEM_ENTITLEMENT_MANAGER = + GlobalInstanceHolder.SYSTEM_ENTITLEMENT_MANAGER; + + @Override + public void handle(ProxyConfigGetFormDataContext context) { + Server server = context.getServer(); + if (!server.isConvertibleToProxy()) { + return; + } + + ensureServerHasProxyInfo(server); + if (!ensureServerHasProxyEntitlement(context)) { + context.setInitFailMessage("Failed to add proxy entitlement to server."); + } + } + + /** + * Ensures that the server has a {@link ProxyInfo}. + * + * @param server the server + */ + public void ensureServerHasProxyInfo(Server server) { + if (server.getProxyInfo() != null) { + return; + } + + ProxyInfo proxyInfo = new ProxyInfo(); + proxyInfo.setServer(server); + server.setProxyInfo(proxyInfo); + SystemManager.updateSystemOverview(server.getId()); + } + + private boolean ensureServerHasProxyEntitlement(ProxyConfigGetFormDataContext context) { + Server server = context.getServer(); + if (server.hasProxyEntitlement()) { + return true; + } + + if (!SYSTEM_ENTITLEMENT_MANAGER.canEntitleServer(server, EntitlementManager.PROXY)) { + LOG.error("Server is not entitleable for proxy entitlement. ID: {}", server.getId()); + return false; + } + + ValidatorResult result = SYSTEM_ENTITLEMENT_MANAGER.addEntitlementToServer(server, EntitlementManager.PROXY); + if (!result.getErrors().isEmpty()) { + LOG.error("Failed to add proxy entitlement to server. ID: {}, Errors: {}", + server.getId(), result.getErrors()); + return false; + } + + return true; + } + +} diff --git a/java/code/src/com/suse/proxy/model/ProxyConfig.java b/java/code/src/com/suse/proxy/model/ProxyConfig.java index a1c300b1290d..23a1a3a973c0 100644 --- a/java/code/src/com/suse/proxy/model/ProxyConfig.java +++ b/java/code/src/com/suse/proxy/model/ProxyConfig.java @@ -17,6 +17,9 @@ import java.util.List; +/** + * Class representing the proxy configuration + */ public class ProxyConfig { private Long serverId; diff --git a/java/code/src/com/suse/proxy/model/ProxyConfigImage.java b/java/code/src/com/suse/proxy/model/ProxyConfigImage.java index d07426b4b1c3..506c4fade78e 100644 --- a/java/code/src/com/suse/proxy/model/ProxyConfigImage.java +++ b/java/code/src/com/suse/proxy/model/ProxyConfigImage.java @@ -15,6 +15,9 @@ package com.suse.proxy.model; +/** + * Class representing the proxy configuration image + */ public class ProxyConfigImage { private String url; diff --git a/java/code/src/com/suse/proxy/test/ProxyConfigUpdateAcquisitorTest.java b/java/code/src/com/suse/proxy/test/ProxyConfigUpdateAcquisitorTest.java index c22797b23291..18ebd6bf7556 100644 --- a/java/code/src/com/suse/proxy/test/ProxyConfigUpdateAcquisitorTest.java +++ b/java/code/src/com/suse/proxy/test/ProxyConfigUpdateAcquisitorTest.java @@ -15,5 +15,518 @@ package com.suse.proxy.test; -public class ProxyConfigUpdateAcquisitorTest { +import static com.suse.proxy.ProxyConfigUtils.REGISTRY_MODE_SIMPLE; +import static com.suse.proxy.ProxyConfigUtils.SOURCE_MODE_REGISTRY; +import static com.suse.proxy.test.ProxyConfigUpdateTestUtils.DUMMY_ADMIN_MAIL; +import static com.suse.proxy.test.ProxyConfigUpdateTestUtils.DUMMY_INTERMEDIATE_CA_1; +import static com.suse.proxy.test.ProxyConfigUpdateTestUtils.DUMMY_INTERMEDIATE_CA_2; +import static com.suse.proxy.test.ProxyConfigUpdateTestUtils.DUMMY_MAX_CACHE; +import static com.suse.proxy.test.ProxyConfigUpdateTestUtils.DUMMY_PARENT_FQDN; +import static com.suse.proxy.test.ProxyConfigUpdateTestUtils.DUMMY_PROXY_CERT; +import static com.suse.proxy.test.ProxyConfigUpdateTestUtils.DUMMY_PROXY_FQDN; +import static com.suse.proxy.test.ProxyConfigUpdateTestUtils.DUMMY_PROXY_KEY; +import static com.suse.proxy.test.ProxyConfigUpdateTestUtils.DUMMY_PROXY_PORT; +import static com.suse.proxy.test.ProxyConfigUpdateTestUtils.DUMMY_ROOT_CA; +import static com.suse.proxy.test.ProxyConfigUpdateTestUtils.DUMMY_SERVER_ID; +import static com.suse.proxy.test.ProxyConfigUpdateTestUtils.DUMMY_TAG; +import static com.suse.proxy.test.ProxyConfigUpdateTestUtils.DUMMY_URL_PREFIX; +import static com.suse.proxy.test.ProxyConfigUpdateTestUtils.assertExpectedErrors; +import static com.suse.proxy.test.ProxyConfigUpdateTestUtils.getDummyTag; +import static com.suse.proxy.test.ProxyConfigUpdateTestUtils.getDummyUrl; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import com.redhat.rhn.domain.server.MinionServer; +import com.redhat.rhn.domain.server.Pillar; +import com.redhat.rhn.domain.server.Server; +import com.redhat.rhn.domain.server.ServerConstants; +import com.redhat.rhn.domain.server.ServerFactory; +import com.redhat.rhn.domain.server.test.MinionServerFactoryTest; +import com.redhat.rhn.domain.server.test.ServerFactoryTest; +import com.redhat.rhn.manager.entitlement.EntitlementManager; +import com.redhat.rhn.manager.formula.FormulaMonitoringManager; +import com.redhat.rhn.manager.system.ServerGroupManager; +import com.redhat.rhn.manager.system.entitling.SystemEntitlementManager; +import com.redhat.rhn.manager.system.entitling.SystemEntitler; +import com.redhat.rhn.manager.system.entitling.SystemUnentitler; +import com.redhat.rhn.testing.BaseTestCaseWithUser; +import com.redhat.rhn.testing.TestUtils; + +import com.suse.manager.webui.services.iface.MonitoringManager; +import com.suse.manager.webui.services.iface.SaltApi; +import com.suse.manager.webui.services.test.TestSaltApi; +import com.suse.manager.webui.utils.gson.ProxyConfigUpdateJson; +import com.suse.proxy.ProxyConfigUtils; +import com.suse.proxy.ProxyContainerImagesEnum; +import com.suse.proxy.RegistryUrl; +import com.suse.proxy.model.ProxyConfig; +import com.suse.proxy.update.ProxyConfigUpdateAcquisitor; +import com.suse.proxy.update.ProxyConfigUpdateContext; +import com.suse.utils.Json; + +import org.jmock.imposters.ByteBuddyClassImposteriser; +import org.jmock.junit5.JUnit5Mockery; +import org.jmock.lib.concurrent.Synchroniser; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.extension.RegisterExtension; + +import java.util.HashMap; +import java.util.List; + +/** + * Tests for the {@link ProxyConfigUpdateAcquisitor} class + */ +@ExtendWith(JUnit5Mockery.class) +public class ProxyConfigUpdateAcquisitorTest extends BaseTestCaseWithUser { + + public static final String DUMMY_REPLACE_ROOT_CA = "replace_rootCA"; + public static final String DUMMY_REPLACE_INTERMEDIATE_CA_1 = "replace_intermediateCA1"; + public static final String DUMMY_REPLACE_INTERMEDIATE_CA_2 = "replace_intermediateCA2"; + public static final String DUMMY_REPLACE_PROXY_CERT = "replace_proxyCert"; + public static final String DUMMY_REPLACE_PROXY_KEY = "replace_proxyKey"; + + private final SaltApi saltApi = new TestSaltApi(); + private final ServerGroupManager serverGroupManager = new ServerGroupManager(saltApi); + private final MonitoringManager monitoringManager = new FormulaMonitoringManager(saltApi); + private final SystemEntitlementManager systemEntitlementManager = new SystemEntitlementManager( + new SystemUnentitler(monitoringManager, serverGroupManager), + new SystemEntitler(saltApi, monitoringManager, serverGroupManager) + ); + + @SuppressWarnings({"java:S1171", "java:S3599"}) + @RegisterExtension + protected final JUnit5Mockery context = new JUnit5Mockery() {{ + setThreadingPolicy(new Synchroniser()); + }}; + + @Override + @BeforeEach + public void setUp() throws Exception { + super.setUp(); + context.setImposteriser(ByteBuddyClassImposteriser.INSTANCE); + } + + /** + * Test a scenario where provided {@link ProxyConfigUpdateJson} request is empty + */ + @Test + public void testBlankRequest() { + ProxyConfigUpdateJson request = Json.GSON.fromJson("{}", ProxyConfigUpdateJson.class); + ProxyConfigUpdateContext proxyConfigUpdateContext = new ProxyConfigUpdateContext(request, null, null, null); + + // execution + new ProxyConfigUpdateAcquisitor().handle(proxyConfigUpdateContext); + + //assertions + assertFalse(proxyConfigUpdateContext.getErrorReport().hasErrors()); + // acquireProxyMinion + assertNull(proxyConfigUpdateContext.getProxyMinion()); + assertNull(proxyConfigUpdateContext.getProxyFqdn()); + assertNull(proxyConfigUpdateContext.getProxyConfig()); + // acquireCertificates + assertNull(proxyConfigUpdateContext.getProxyCert()); + assertNull(proxyConfigUpdateContext.getIntermediateCAs()); + assertNull(proxyConfigUpdateContext.getProxyCert()); + assertNull(proxyConfigUpdateContext.getProxyKey()); + // acquireParentServer + assertNull(proxyConfigUpdateContext.getParentServer()); + // buildRegistryUrls + assertTrue(proxyConfigUpdateContext.getRegistryUrls().isEmpty()); + + + } + + /** + * Test scenario with following conditions: + * - {@link ProxyConfigUpdateJson} request is provided with all fields filled; + * - No data is acquired. + */ + @Test + public void testFullRequestNoAcquisitions() { + ProxyConfigUpdateJson request = new ProxyConfigUpdateJsonBuilder() + .serverId(DUMMY_SERVER_ID) + .parentFqdn(DUMMY_ADMIN_MAIL) + .proxyPort(DUMMY_PROXY_PORT) + .maxCache(DUMMY_MAX_CACHE) + .email(DUMMY_ADMIN_MAIL) + .replaceCerts( + DUMMY_ROOT_CA, + List.of(DUMMY_INTERMEDIATE_CA_1, DUMMY_INTERMEDIATE_CA_2), + DUMMY_PROXY_CERT, + DUMMY_PROXY_KEY + ) + .sourceRegistryAdvanced( + getDummyUrl(ProxyContainerImagesEnum.PROXY_HTTPD), + getDummyTag(ProxyContainerImagesEnum.PROXY_HTTPD), + getDummyUrl(ProxyContainerImagesEnum.PROXY_SALT_BROKER), + getDummyTag(ProxyContainerImagesEnum.PROXY_SALT_BROKER), + getDummyUrl(ProxyContainerImagesEnum.PROXY_SQUID), + getDummyTag(ProxyContainerImagesEnum.PROXY_SQUID), + getDummyUrl(ProxyContainerImagesEnum.PROXY_SSH), + getDummyTag(ProxyContainerImagesEnum.PROXY_SSH), + getDummyUrl(ProxyContainerImagesEnum.PROXY_TFTPD), + getDummyTag(ProxyContainerImagesEnum.PROXY_TFTPD) + ) + .build(); + ProxyConfigUpdateContext proxyConfigUpdateContext = new ProxyConfigUpdateContext(request, null, null, null); + + // execution + new ProxyConfigUpdateAcquisitor().handle(proxyConfigUpdateContext); + + //assertions + assertFalse(proxyConfigUpdateContext.getErrorReport().hasErrors()); + // acquireProxyMinion + assertNull(proxyConfigUpdateContext.getProxyMinion()); + assertNull(proxyConfigUpdateContext.getProxyFqdn()); + assertNull(proxyConfigUpdateContext.getProxyConfig()); + // acquireCertificates + assertEquals(DUMMY_PROXY_CERT, proxyConfigUpdateContext.getProxyCert()); + assertEquals(DUMMY_ROOT_CA, proxyConfigUpdateContext.getRootCA()); + assertEquals( + List.of(DUMMY_INTERMEDIATE_CA_1, DUMMY_INTERMEDIATE_CA_2), + proxyConfigUpdateContext.getIntermediateCAs() + ); + assertEquals(DUMMY_PROXY_CERT, proxyConfigUpdateContext.getProxyCert()); + // acquireParentServer + assertNull(proxyConfigUpdateContext.getParentServer()); + // buildRegistryUrls + assertEquals(ProxyContainerImagesEnum.values().length, proxyConfigUpdateContext.getRegistryUrls().size()); + for (ProxyContainerImagesEnum image : ProxyContainerImagesEnum.values()) { + assertTrue(proxyConfigUpdateContext.getRegistryUrls().containsKey(image)); + RegistryUrl registryUrl = proxyConfigUpdateContext.getRegistryUrls().get(image); + assertEquals(DUMMY_TAG + "_" + image.getImageName(), registryUrl.getTag()); + assertEquals(DUMMY_URL_PREFIX + image.getImageName(), registryUrl.getUrl()); + } + } + + /** + * Test acquireProxyMinion in a scenario with following conditions: + * - {@link ProxyConfigUpdateJson} request provides required data; + * - All minion data is acquirable. + */ + @Test + public void testAcquireProxyMinionWhenSuccessfulAcquisitions() { + // minion setup + MinionServer minion = MinionServerFactoryTest.createTestMinionServer(user); + minion.setServerArch(ServerFactory.lookupServerArchByLabel("x86_64-redhat-linux")); + minion.addFqdn(DUMMY_PROXY_FQDN); + systemEntitlementManager.addEntitlementToServer(minion, EntitlementManager.PROXY); + Pillar pillar = new Pillar(ProxyConfigUtils.PROXY_PILLAR_CATEGORY, new HashMap<>(), minion); + pillar.add(ProxyConfigUtils.PROXY_FQDN_FIELD, DUMMY_PROXY_FQDN); + pillar.add(ProxyConfigUtils.PARENT_FQDN_FIELD, DUMMY_PARENT_FQDN); + minion.addPillar(pillar); + TestUtils.saveAndFlush(minion); + + ProxyConfigUpdateJson request = new ProxyConfigUpdateJsonBuilder().serverId(minion.getId()).build(); + ProxyConfigUpdateContext proxyConfigUpdateContext = new ProxyConfigUpdateContext(request, null, null, null); + + // execution + new ProxyConfigUpdateAcquisitor().handle(proxyConfigUpdateContext); + + //assertions + assertFalse(proxyConfigUpdateContext.getErrorReport().hasErrors()); + + // acquireProxyMinion + assertNotNull(proxyConfigUpdateContext.getProxyMinion()); + assertEquals(DUMMY_PROXY_FQDN, proxyConfigUpdateContext.getProxyFqdn()); + ProxyConfig proxyConfig = proxyConfigUpdateContext.getProxyConfig(); + assertNotNull(proxyConfig); + assertEquals(DUMMY_PROXY_FQDN, proxyConfig.getProxyFqdn()); + assertEquals(DUMMY_PARENT_FQDN, proxyConfig.getParentFqdn()); + } + + /** + * Test acquireCertificates in a scenario with following conditions: + * - {@link ProxyConfigUpdateJson} request provides required data, indicating we want to keep existing certificates; + * - Minion has certificates saved in its pillar. + * Expects the {@link ProxyConfigUpdateContext} to keep the existing ones in the pillars, discarding certificates + * data provided in {@link ProxyConfigUpdateJson}. + */ + @Test + public void testAcquireCertificatesKeepWhenSuccessfulRetrieveCertificates() { + // minion setup + MinionServer minion = MinionServerFactoryTest.createTestMinionServer(user); + systemEntitlementManager.addEntitlementToServer(minion, EntitlementManager.PROXY); + Pillar pillar = new Pillar(ProxyConfigUtils.PROXY_PILLAR_CATEGORY, new HashMap<>(), minion); + pillar.add(ProxyConfigUtils.ROOT_CA_FIELD, DUMMY_ROOT_CA); + pillar.add(ProxyConfigUtils.INTERMEDIATE_CAS_FIELD, List.of(DUMMY_INTERMEDIATE_CA_1, DUMMY_INTERMEDIATE_CA_2)); + pillar.add(ProxyConfigUtils.PROXY_CERT_FIELD, DUMMY_PROXY_CERT); + pillar.add(ProxyConfigUtils.PROXY_KEY_FIELD, DUMMY_PROXY_KEY); + minion.addPillar(pillar); + TestUtils.saveAndFlush(minion); + + ProxyConfigUpdateJson request = new ProxyConfigUpdateJsonBuilder() + .serverId(minion.getId()) + .keepCerts( + DUMMY_REPLACE_ROOT_CA, + List.of(DUMMY_REPLACE_INTERMEDIATE_CA_1, DUMMY_REPLACE_INTERMEDIATE_CA_2), + DUMMY_REPLACE_PROXY_CERT, + DUMMY_REPLACE_PROXY_KEY + ).build(); + ProxyConfigUpdateContext proxyConfigUpdateContext = new ProxyConfigUpdateContext(request, null, null, null); + + // execution + new ProxyConfigUpdateAcquisitor().handle(proxyConfigUpdateContext); + + //assertions + assertFalse(proxyConfigUpdateContext.getErrorReport().hasErrors()); + + // acquireCertificates + assertEquals(DUMMY_ROOT_CA, proxyConfigUpdateContext.getRootCA()); + assertEquals( + List.of(DUMMY_INTERMEDIATE_CA_1, DUMMY_INTERMEDIATE_CA_2), + proxyConfigUpdateContext.getIntermediateCAs() + ); + assertEquals(DUMMY_PROXY_CERT, proxyConfigUpdateContext.getProxyCert()); + assertEquals(DUMMY_PROXY_KEY, proxyConfigUpdateContext.getProxyKey()); + } + + /** + * Test acquireCertificates in a scenario with following conditions: + * - {@link ProxyConfigUpdateJson} request provides required data, indicating we want to keep existing certificates; + * - Minion does NOT have proxy pillars in DB. + * Expects the {@link ProxyConfigUpdateContext} certificates data to be null. + */ + @Test + public void testAcquireCertificatesKeepWhenFailRetrieveCertificates() { + // minion setup + MinionServer minion = MinionServerFactoryTest.createTestMinionServer(user); + systemEntitlementManager.addEntitlementToServer(minion, EntitlementManager.PROXY); + TestUtils.saveAndFlush(minion); + + ProxyConfigUpdateJson request = new ProxyConfigUpdateJsonBuilder() + .serverId(minion.getId()) + .keepCerts( + DUMMY_REPLACE_ROOT_CA, + List.of(DUMMY_REPLACE_INTERMEDIATE_CA_1, DUMMY_REPLACE_INTERMEDIATE_CA_2), + DUMMY_REPLACE_PROXY_CERT, + DUMMY_REPLACE_PROXY_KEY + ).build(); + ProxyConfigUpdateContext proxyConfigUpdateContext = new ProxyConfigUpdateContext(request, null, null, null); + + // execution + new ProxyConfigUpdateAcquisitor().handle(proxyConfigUpdateContext); + + //assertions + assertFalse(proxyConfigUpdateContext.getErrorReport().hasErrors()); + + // acquireCertificates + assertNull(proxyConfigUpdateContext.getRootCA()); + assertNull(proxyConfigUpdateContext.getIntermediateCAs()); + assertNull(proxyConfigUpdateContext.getProxyCert()); + assertNull(proxyConfigUpdateContext.getProxyKey()); + } + + /** + * Test acquireCertificates in a scenario with following conditions: + * - {@link ProxyConfigUpdateJson} request provides required data, indicating we want to replace certificates; + * - Minion has certificates saved in its pillar. + * Expects the {@link ProxyConfigUpdateContext} to replace certificates data. + */ + @Test + public void testAcquireCertificatesReplaceWhenSuccessfulRetrieveCertificates() { + // minion setup + MinionServer minion = MinionServerFactoryTest.createTestMinionServer(user); + systemEntitlementManager.addEntitlementToServer(minion, EntitlementManager.PROXY); + Pillar pillar = new Pillar(ProxyConfigUtils.PROXY_PILLAR_CATEGORY, new HashMap<>(), minion); + pillar.add(ProxyConfigUtils.ROOT_CA_FIELD, DUMMY_ROOT_CA); + pillar.add(ProxyConfigUtils.INTERMEDIATE_CAS_FIELD, List.of(DUMMY_INTERMEDIATE_CA_1, DUMMY_INTERMEDIATE_CA_2)); + pillar.add(ProxyConfigUtils.PROXY_CERT_FIELD, DUMMY_PROXY_CERT); + pillar.add(ProxyConfigUtils.PROXY_KEY_FIELD, DUMMY_PROXY_KEY); + minion.addPillar(pillar); + TestUtils.saveAndFlush(minion); + + ProxyConfigUpdateJson request = new ProxyConfigUpdateJsonBuilder() + .serverId(minion.getId()) + .replaceCerts( + DUMMY_REPLACE_ROOT_CA, + List.of(DUMMY_REPLACE_INTERMEDIATE_CA_1, DUMMY_REPLACE_INTERMEDIATE_CA_2), + DUMMY_REPLACE_PROXY_CERT, + DUMMY_REPLACE_PROXY_KEY + ).build(); + ProxyConfigUpdateContext proxyConfigUpdateContext = new ProxyConfigUpdateContext(request, null, null, null); + + // execution + new ProxyConfigUpdateAcquisitor().handle(proxyConfigUpdateContext); + + //assertions + assertFalse(proxyConfigUpdateContext.getErrorReport().hasErrors()); + + // acquireCertificates + assertEquals(DUMMY_REPLACE_ROOT_CA, proxyConfigUpdateContext.getRootCA()); + assertEquals( + List.of(DUMMY_REPLACE_INTERMEDIATE_CA_1, DUMMY_REPLACE_INTERMEDIATE_CA_2), + proxyConfigUpdateContext.getIntermediateCAs() + ); + assertEquals(DUMMY_REPLACE_PROXY_CERT, proxyConfigUpdateContext.getProxyCert()); + assertEquals(DUMMY_REPLACE_PROXY_KEY, proxyConfigUpdateContext.getProxyKey()); + } + + + /** + * Test acquireParentServer in a scenario with following conditions: + * - {@link ProxyConfigUpdateJson} request provides required data (ie. parent fqdn); + * - Parent server is reachable using the provided fqdn. + */ + @Test + public void testAcquireParentServerWhenSuccessfulRetrieveServer() { + // parent server setup + Server parent = ServerFactoryTest.createTestServer(user, true, + ServerConstants.getServerGroupTypeSaltEntitled(), + ServerFactoryTest.TYPE_SERVER_MGR); + parent.addFqdn(DUMMY_PARENT_FQDN); + + ProxyConfigUpdateJson request = new ProxyConfigUpdateJsonBuilder().parentFqdn(DUMMY_PARENT_FQDN).build(); + ProxyConfigUpdateContext proxyConfigUpdateContext = new ProxyConfigUpdateContext(request, null, null, null); + + // execution + new ProxyConfigUpdateAcquisitor().handle(proxyConfigUpdateContext); + + //assertions + assertFalse(proxyConfigUpdateContext.getErrorReport().hasErrors()); + + // acquireParentServer + assertEquals(parent, proxyConfigUpdateContext.getParentServer()); + } + + /** + * Test acquireParentServer in a scenario with following conditions: + * - {@link ProxyConfigUpdateJson} request provides required data (ie. parent fqdn); + * - Parent server is not found using the provided fqdn. + */ + @Test + public void testAcquireParentServerWhenFailRetrieveServer() { + // parent server setup + Server parent = ServerFactoryTest.createTestServer(user, true, + ServerConstants.getServerGroupTypeSaltEntitled(), + ServerFactoryTest.TYPE_SERVER_MGR); + parent.addFqdn(DUMMY_PARENT_FQDN); + + ProxyConfigUpdateJson request = new ProxyConfigUpdateJsonBuilder().parentFqdn("not.existent.com").build(); + ProxyConfigUpdateContext proxyConfigUpdateContext = new ProxyConfigUpdateContext(request, null, null, null); + + // execution + new ProxyConfigUpdateAcquisitor().handle(proxyConfigUpdateContext); + + //assertions + assertFalse(proxyConfigUpdateContext.getErrorReport().hasErrors()); + + // acquireParentServer + assertNull(proxyConfigUpdateContext.getParentServer()); + } + + /** + * Test buildRegistryUrls in a scenario with following conditions: + * - {@link ProxyConfigUpdateJson} request provides required data, indicating we want to use registries, + * providing a common registry and tag for all images. + */ + @Test + public void testBuildRegistryUrlsWhenSimpleRegistry() { + ProxyConfigUpdateJson request = new ProxyConfigUpdateJsonBuilder() + .sourceMode(SOURCE_MODE_REGISTRY) + .registryMode(REGISTRY_MODE_SIMPLE) + .registryBaseURL("http://suse.com/common/image") + .registryBaseTag(DUMMY_TAG) + .build(); + + ProxyConfigUpdateContext proxyConfigUpdateContext = new ProxyConfigUpdateContext(request, null, null, null); + + // execution + new ProxyConfigUpdateAcquisitor().handle(proxyConfigUpdateContext); + + //assertions + assertFalse(proxyConfigUpdateContext.getErrorReport().hasErrors()); + + // buildRegistryUrls + assertEquals(ProxyContainerImagesEnum.values().length, proxyConfigUpdateContext.getRegistryUrls().size()); + for (ProxyContainerImagesEnum image : ProxyContainerImagesEnum.values()) { + assertTrue(proxyConfigUpdateContext.getRegistryUrls().containsKey(image)); + RegistryUrl registryUrl = proxyConfigUpdateContext.getRegistryUrls().get(image); + assertEquals(DUMMY_TAG, registryUrl.getTag()); + assertEquals("http://suse.com/common/image/" + image.getImageName(), registryUrl.getUrl()); + } + } + + /** + * Test buildRegistryUrls in a scenario with following conditions: + * - {@link ProxyConfigUpdateJson} request provides required data, indicating we want to use registries, + * providing a common registry and tag for all images. + */ + @Test + public void testFailBuildRegistryUrlsWhenSimpleRegistryWithBadUrl() { + final String[] expectedErrorMessages = {"Invalid Registry URL"}; + ProxyConfigUpdateJson request = new ProxyConfigUpdateJsonBuilder() + .sourceMode(SOURCE_MODE_REGISTRY) + .registryMode(REGISTRY_MODE_SIMPLE) + .registryBaseURL("http://invalid-url^") // This should cause URISyntaxException + .registryBaseTag(DUMMY_TAG) + .build(); + + ProxyConfigUpdateContext proxyConfigUpdateContext = new ProxyConfigUpdateContext(request, null, null, null); + + // + new ProxyConfigUpdateAcquisitor().handle(proxyConfigUpdateContext); + assertExpectedErrors(expectedErrorMessages, proxyConfigUpdateContext); + } + + /** + * Test buildRegistryUrls in a scenario with following conditions: + * - {@link ProxyConfigUpdateJson} request provides required data, indicating we want to use registries and + * specifying for each one its url and tag. + */ + @Test + public void testBuildRegistryUrlsWhenAdvancedRegistry() { + ProxyConfigUpdateJson request = getFullRequest().build(); + + ProxyConfigUpdateContext proxyConfigUpdateContext = new ProxyConfigUpdateContext(request, null, null, null); + + // execution + new ProxyConfigUpdateAcquisitor().handle(proxyConfigUpdateContext); + + //assertions + assertFalse(proxyConfigUpdateContext.getErrorReport().hasErrors()); + + // buildRegistryUrls + assertEquals(ProxyContainerImagesEnum.values().length, proxyConfigUpdateContext.getRegistryUrls().size()); + for (ProxyContainerImagesEnum image : ProxyContainerImagesEnum.values()) { + assertTrue(proxyConfigUpdateContext.getRegistryUrls().containsKey(image)); + RegistryUrl registryUrl = proxyConfigUpdateContext.getRegistryUrls().get(image); + assertEquals(image.getImageName() + "-latest", registryUrl.getTag()); + assertEquals("http://suse.com/" + image.getImageName(), registryUrl.getUrl()); + } + } + + + /** + * Creates a request with all fields filled. + * Considers replacing certs and using registries. + * + * @return the request builder + */ + private ProxyConfigUpdateJsonBuilder getFullRequest() { + return new ProxyConfigUpdateJsonBuilder() + .serverId(DUMMY_SERVER_ID) + .parentFqdn(DUMMY_PARENT_FQDN) + .proxyPort(DUMMY_PROXY_PORT) + .maxCache(DUMMY_MAX_CACHE) + .email(DUMMY_ADMIN_MAIL) + .replaceCerts( + DUMMY_ROOT_CA, + List.of(DUMMY_INTERMEDIATE_CA_1, DUMMY_INTERMEDIATE_CA_2), + DUMMY_PROXY_CERT, + DUMMY_PROXY_KEY + ).sourceRegistryAdvanced( + "http://suse.com/proxy-httpd", "proxy-httpd-latest", + "http://suse.com/proxy-salt-broker", "proxy-salt-broker-latest", + "http://suse.com/proxy-squid", "proxy-squid-latest", + "http://suse.com/proxy-ssh", "proxy-ssh-latest", + "http://suse.com/proxy-tftpd", "proxy-tftpd-latest" + ); + } + } diff --git a/java/code/src/com/suse/proxy/test/ProxyConfigUpdateFacadeImplTest.java b/java/code/src/com/suse/proxy/test/ProxyConfigUpdateFacadeImplTest.java new file mode 100644 index 000000000000..19590822ae2c --- /dev/null +++ b/java/code/src/com/suse/proxy/test/ProxyConfigUpdateFacadeImplTest.java @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2025 SUSE LLC + * + * This software is licensed to you under the GNU General Public License, + * version 2 (GPLv2). There is NO WARRANTY for this software, express or + * implied, including the implied warranties of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 + * along with this software; if not, see + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * Red Hat trademarks are not licensed under GPLv2. No permission is + * granted to use or replicate Red Hat trademarks that are incorporated + * in this software or its documentation. + */ + +package com.suse.proxy.test; + +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +import com.redhat.rhn.common.RhnGeneralException; +import com.redhat.rhn.testing.MockObjectTestCase; + +import com.suse.proxy.update.ProxyConfigUpdateFacadeImpl; +import com.suse.proxy.update.ProxyConfigUpdateContext; +import com.suse.proxy.update.ProxyConfigUpdateContextHandler; + +import org.jmock.junit5.JUnit5Mockery; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.extension.ExtendWith; + +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.List; + +/** + * Tests for the ProxyConfigUpdate class + */ +@ExtendWith(JUnit5Mockery.class) +public class ProxyConfigUpdateFacadeImplTest extends MockObjectTestCase { + + /** + * Tests the success case when all handlers are successful + */ + @Test + public void testSuccessWhenUpdate() throws NoSuchFieldException, IllegalAccessException { + ProxyConfigUpdateContextHandler okHandler1 = new OkHandler(); + ProxyConfigUpdateContextHandler okHandler2 = new OkHandler(); + ProxyConfigUpdateContextHandler okHandler3 = new OkHandler(); + + ProxyConfigUpdateFacadeImpl proxyConfigUpdate = new ProxyConfigUpdateFacadeImpl(); + replaceHandlers(proxyConfigUpdate, List.of(okHandler1, okHandler2, okHandler3)); + + proxyConfigUpdate.update(null, null, null, null); + } + + /** + * Tests a scenario where there are 3 handlers. + * The first one is successful; + * The second one registers with 3 errors; + * The third one registers with 2 errors. + * It is expected that the process halts after the second handler and the errors are reported in a + * {@link RhnGeneralException} with the expected error messages. + */ + @Test + public void testFailWhenUpdateWithError() throws NoSuchFieldException, IllegalAccessException { + final String[] expectedErrorMessages = {"oops", "three", "errors?"}; + + ProxyConfigUpdateContextHandler okHandler = new OkHandler(); + ProxyConfigUpdateContextHandler failingHandler = new FailingHandler(); + ProxyConfigUpdateContextHandler anotherFailingHandler = new AnotherFailingHandler(); + + ProxyConfigUpdateFacadeImpl proxyConfigUpdate = new ProxyConfigUpdateFacadeImpl(); + replaceHandlers(proxyConfigUpdate, List.of(okHandler, failingHandler, anotherFailingHandler)); + + try { + proxyConfigUpdate.update(null, null, null, null); + fail("Expected RhnGeneralException to be thrown"); + } + catch (RhnGeneralException e) { + Assertions.assertEquals(expectedErrorMessages.length, e.getErrorMessages().length); + for (String expectedErrorMessage : expectedErrorMessages) { + assertTrue(Arrays.asList(e.getErrorMessages()).contains(expectedErrorMessage)); + } + } + } + + /** + * A handler that does nothing, mocking a valid step + */ + public static class OkHandler implements ProxyConfigUpdateContextHandler { + @Override + public void handle(ProxyConfigUpdateContext context) { + // does nothing + } + } + + /** + * A handler that registers three errors, mocking an invalid step + */ + public static class FailingHandler implements ProxyConfigUpdateContextHandler { + @Override + public void handle(ProxyConfigUpdateContext context) { + context.getErrorReport().register("oops"); + context.getErrorReport().register("three"); + context.getErrorReport().register("errors?"); + } + } + + /** + * Another handler that registers errors, mocking an invalid step + */ + public static class AnotherFailingHandler implements ProxyConfigUpdateContextHandler { + @Override + public void handle(ProxyConfigUpdateContext context) { + context.getErrorReport().register("more"); + context.getErrorReport().register("errors!"); + } + } + + /** + * Replaces the handlers in the ProxyConfigUpdate chain of responsibility private field + * @param proxyConfigUpdate the ProxyConfigUpdate instance + * @param handlers the new handlers + * @throws NoSuchFieldException if the field is not found + * @throws IllegalAccessException if the field cannot be accessed + */ + @SuppressWarnings("squid:S3011") + private void replaceHandlers(ProxyConfigUpdateFacadeImpl proxyConfigUpdate, List handlers) + throws NoSuchFieldException, IllegalAccessException { + Field field = ProxyConfigUpdateFacadeImpl.class.getDeclaredField("contextHandlerChain"); + field.setAccessible(true); + field.set(proxyConfigUpdate, handlers); + field.get(proxyConfigUpdate); + } +} diff --git a/java/code/src/com/suse/proxy/test/ProxyConfigUpdateJsonBuilder.java b/java/code/src/com/suse/proxy/test/ProxyConfigUpdateJsonBuilder.java index 072ab4a5fd79..eadb476de056 100644 --- a/java/code/src/com/suse/proxy/test/ProxyConfigUpdateJsonBuilder.java +++ b/java/code/src/com/suse/proxy/test/ProxyConfigUpdateJsonBuilder.java @@ -15,12 +15,30 @@ package com.suse.proxy.test; +import static com.suse.proxy.ProxyConfigUtils.EMAIL_FIELD; +import static com.suse.proxy.ProxyConfigUtils.INTERMEDIATE_CAS_FIELD; +import static com.suse.proxy.ProxyConfigUtils.MAX_CACHE_FIELD; +import static com.suse.proxy.ProxyConfigUtils.PARENT_FQDN_FIELD; +import static com.suse.proxy.ProxyConfigUtils.PROXY_CERT_FIELD; +import static com.suse.proxy.ProxyConfigUtils.PROXY_KEY_FIELD; +import static com.suse.proxy.ProxyConfigUtils.PROXY_PORT_FIELD; +import static com.suse.proxy.ProxyConfigUtils.REGISTRY_BASE_TAG; +import static com.suse.proxy.ProxyConfigUtils.REGISTRY_BASE_URL; +import static com.suse.proxy.ProxyConfigUtils.REGISTRY_MODE; import static com.suse.proxy.ProxyConfigUtils.REGISTRY_MODE_ADVANCED; -import static com.suse.proxy.ProxyConfigUtils.REGISTRY_MODE_SIMPLE; +import static com.suse.proxy.ProxyConfigUtils.ROOT_CA_FIELD; +import static com.suse.proxy.ProxyConfigUtils.SERVER_ID_FIELD; +import static com.suse.proxy.ProxyConfigUtils.SOURCE_MODE_FIELD; import static com.suse.proxy.ProxyConfigUtils.SOURCE_MODE_REGISTRY; import static com.suse.proxy.ProxyConfigUtils.SOURCE_MODE_RPM; +import static com.suse.proxy.ProxyConfigUtils.USE_CERTS_MODE_FIELD; import static com.suse.proxy.ProxyConfigUtils.USE_CERTS_MODE_KEEP; import static com.suse.proxy.ProxyConfigUtils.USE_CERTS_MODE_REPLACE; +import static com.suse.proxy.ProxyContainerImagesEnum.PROXY_HTTPD; +import static com.suse.proxy.ProxyContainerImagesEnum.PROXY_SALT_BROKER; +import static com.suse.proxy.ProxyContainerImagesEnum.PROXY_SQUID; +import static com.suse.proxy.ProxyContainerImagesEnum.PROXY_SSH; +import static com.suse.proxy.ProxyContainerImagesEnum.PROXY_TFTPD; import static com.suse.utils.Predicates.isProvided; import com.suse.manager.webui.utils.gson.ProxyConfigUpdateJson; @@ -85,7 +103,12 @@ public ProxyConfigUpdateJsonBuilder email(String emailIn) { return this; } - public ProxyConfigUpdateJsonBuilder replaceCerts(String rootCAIn, List intermediateCAsIn, String proxyCertIn, String proxyKeyIn) { + public ProxyConfigUpdateJsonBuilder replaceCerts( + String rootCAIn, + List intermediateCAsIn, + String proxyCertIn, + String proxyKeyIn + ) { useCertsMode = USE_CERTS_MODE_REPLACE; rootCA = rootCAIn; intermediateCAs = intermediateCAsIn; @@ -94,7 +117,12 @@ public ProxyConfigUpdateJsonBuilder replaceCerts(String rootCAIn, List i return this; } - public ProxyConfigUpdateJsonBuilder keepCerts(String rootCAIn, List intermediateCAsIn, String proxyCertIn, String proxyKeyIn) { + public ProxyConfigUpdateJsonBuilder keepCerts( + String rootCAIn, + List intermediateCAsIn, + String proxyCertIn, + String proxyKeyIn + ) { useCertsMode = USE_CERTS_MODE_KEEP; rootCA = rootCAIn; intermediateCAs = intermediateCAsIn; @@ -128,6 +156,7 @@ public ProxyConfigUpdateJsonBuilder registryBaseTag(String registryBaseTagIn) { return this; } + @SuppressWarnings("java:S107") public ProxyConfigUpdateJsonBuilder sourceRegistryAdvanced( String registryHttpdURLIn, String registryHttpdTagIn, String registrySaltbrokerURLIn, String registrySaltbrokerTagIn, @@ -152,36 +181,36 @@ public ProxyConfigUpdateJsonBuilder sourceRegistryAdvanced( public ProxyConfigUpdateJson build() { JsonObject requestJsonObject = new JsonObject(); - requestJsonObject.addProperty("serverId", this.serverId); - requestJsonObject.addProperty("parentFQDN", this.parentFqdn); - requestJsonObject.addProperty("proxyPort", this.proxyPort); - requestJsonObject.addProperty("maxSquidCacheSize", this.maxCache); - requestJsonObject.addProperty("proxyAdminEmail", this.email); - requestJsonObject.addProperty("useCertsMode", this.useCertsMode); - requestJsonObject.addProperty("rootCA", this.rootCA); + requestJsonObject.addProperty(SERVER_ID_FIELD, this.serverId); + requestJsonObject.addProperty(PARENT_FQDN_FIELD, this.parentFqdn); + requestJsonObject.addProperty(PROXY_PORT_FIELD, this.proxyPort); + requestJsonObject.addProperty(MAX_CACHE_FIELD, this.maxCache); + requestJsonObject.addProperty(EMAIL_FIELD, this.email); + requestJsonObject.addProperty(USE_CERTS_MODE_FIELD, this.useCertsMode); + requestJsonObject.addProperty(ROOT_CA_FIELD, this.rootCA); JsonArray intermediateCAsArray = new JsonArray(); if (isProvided(this.intermediateCAs)) { for (String ca : this.intermediateCAs) { intermediateCAsArray.add(ca); } } - requestJsonObject.add("intermediateCAs", intermediateCAsArray); - requestJsonObject.addProperty("proxyCertificate", this.proxyCert); - requestJsonObject.addProperty("proxyKey", this.proxyKey); - requestJsonObject.addProperty("sourceMode", this.sourceMode); - requestJsonObject.addProperty("registryMode", this.registryMode); - requestJsonObject.addProperty("registryBaseURL", this.registryBaseURL); - requestJsonObject.addProperty("registryBaseTag", this.registryBaseTag); - requestJsonObject.addProperty("registryHttpdURL", this.registryHttpdURL); - requestJsonObject.addProperty("registryHttpdTag", this.registryHttpdTag); - requestJsonObject.addProperty("registrySaltbrokerURL", this.registrySaltbrokerURL); - requestJsonObject.addProperty("registrySaltbrokerTag", this.registrySaltbrokerTag); - requestJsonObject.addProperty("registrySquidURL", this.registrySquidURL); - requestJsonObject.addProperty("registrySquidTag", this.registrySquidTag); - requestJsonObject.addProperty("registrySshURL", this.registrySshURL); - requestJsonObject.addProperty("registrySshTag", this.registrySshTag); - requestJsonObject.addProperty("registryTftpdURL", this.registryTftpdURL); - requestJsonObject.addProperty("registryTftpdTag", this.registryTftpdTag); + requestJsonObject.add(INTERMEDIATE_CAS_FIELD, intermediateCAsArray); + requestJsonObject.addProperty(PROXY_CERT_FIELD, this.proxyCert); + requestJsonObject.addProperty(PROXY_KEY_FIELD, this.proxyKey); + requestJsonObject.addProperty(SOURCE_MODE_FIELD, this.sourceMode); + requestJsonObject.addProperty(REGISTRY_MODE, this.registryMode); + requestJsonObject.addProperty(REGISTRY_BASE_URL, this.registryBaseURL); + requestJsonObject.addProperty(REGISTRY_BASE_TAG, this.registryBaseTag); + requestJsonObject.addProperty(PROXY_HTTPD.getUrlField(), this.registryHttpdURL); + requestJsonObject.addProperty(PROXY_HTTPD.getTagField(), this.registryHttpdTag); + requestJsonObject.addProperty(PROXY_SALT_BROKER.getUrlField(), this.registrySaltbrokerURL); + requestJsonObject.addProperty(PROXY_SALT_BROKER.getTagField(), this.registrySaltbrokerTag); + requestJsonObject.addProperty(PROXY_SQUID.getUrlField(), this.registrySquidURL); + requestJsonObject.addProperty(PROXY_SQUID.getTagField(), this.registrySquidTag); + requestJsonObject.addProperty(PROXY_SSH.getUrlField(), this.registrySshURL); + requestJsonObject.addProperty(PROXY_SSH.getTagField(), this.registrySshTag); + requestJsonObject.addProperty(PROXY_TFTPD.getUrlField(), this.registryTftpdURL); + requestJsonObject.addProperty(PROXY_TFTPD.getTagField(), this.registryTftpdTag); return Json.GSON.fromJson(requestJsonObject, ProxyConfigUpdateJson.class); } diff --git a/java/code/src/com/suse/proxy/test/ProxyConfigUpdateRegistryPreConditionsTest.java b/java/code/src/com/suse/proxy/test/ProxyConfigUpdateRegistryPreConditionsTest.java index 78c9ac88e5eb..bf691a7a27f8 100644 --- a/java/code/src/com/suse/proxy/test/ProxyConfigUpdateRegistryPreConditionsTest.java +++ b/java/code/src/com/suse/proxy/test/ProxyConfigUpdateRegistryPreConditionsTest.java @@ -21,7 +21,7 @@ import static com.suse.proxy.ProxyContainerImagesEnum.PROXY_SQUID; import static com.suse.proxy.ProxyContainerImagesEnum.PROXY_SSH; import static com.suse.proxy.ProxyContainerImagesEnum.PROXY_TFTPD; -import static com.suse.proxy.test.ProxyConfigUpdateUtils.assertExpectedErrors; +import static com.suse.proxy.test.ProxyConfigUpdateTestUtils.assertExpectedErrors; import static org.junit.jupiter.api.Assertions.assertFalse; import com.redhat.rhn.testing.MockObjectTestCase; @@ -42,7 +42,6 @@ import org.junit.Test; import org.junit.jupiter.api.extension.ExtendWith; -import java.util.ArrayList; import java.util.EnumMap; import java.util.Map; @@ -51,6 +50,7 @@ * These will assume the previous step in the chain of responsibility {@link ProxyConfigUpdateAcquisitor} and * {@link ProxyConfigUpdateValidation} have been executed and, no errors have been added to the context. */ +@SuppressWarnings({"java:S1171", "java:S3599"}) @ExtendWith(JUnit5Mockery.class) public class ProxyConfigUpdateRegistryPreConditionsTest extends MockObjectTestCase { @@ -76,7 +76,8 @@ public void testSuccessWhenSourceModeIsRpm() { } /** - * Test a scenario when sourceMode is set to "Registry" but proxy RegistryUrls failed to be created (on previous steps) + * Test a scenario when sourceMode is set to "Registry" but proxy RegistryUrls failed to be created + * (on previous steps) */ @Test public void testFailWhenRegistryUrlNotProvided() { @@ -97,6 +98,7 @@ public void testFailWhenRegistryUrlNotProvided() { assertExpectedErrors(expectedErrorMessages, proxyConfigUpdateContext); } + @SuppressWarnings("java:S1130") // Suppress the ParseException warning (due to the mocked getTags() method) @Test public void testWhenGetTagsThrowsParseException() throws ParseException { final String[] expectedErrorMessages = { @@ -137,35 +139,4 @@ public void testWhenGetTagsThrowsParseException() throws ParseException { assertExpectedErrors(expectedErrorMessages, proxyConfigUpdateContext); } - @Test - public void testSuccess() throws ParseException { - setImposteriser(ByteBuddyClassImposteriser.INSTANCE); - ProxyConfigUpdateJson request = new ProxyConfigUpdateJsonBuilder().sourceMode(SOURCE_MODE_REGISTRY).build(); - ProxyConfigUpdateContext proxyConfigUpdateContext = - new ProxyConfigUpdateContext(request, null, null, null); - - Map registryUrls = new EnumMap<>(ProxyContainerImagesEnum.class); - RegistryUrl registryUrl = context.mock(RegistryUrl.class); - registryUrls.put(PROXY_HTTPD, registryUrl); - registryUrls.put(PROXY_SALT_BROKER, registryUrl); - registryUrls.put(PROXY_SQUID, registryUrl); - registryUrls.put(PROXY_SSH, registryUrl); - registryUrls.put(PROXY_TFTPD, registryUrl); - proxyConfigUpdateContext.getRegistryUrls().putAll(registryUrls); - - // Inject the mock service so registryUtils.getTags() will not throw an exception - ProxyRegistryUtils proxyRegistryUtils = context.mock(ProxyRegistryUtils.class); - ProxyConfigUpdateRegistryPreConditions preConditions = - new ProxyConfigUpdateRegistryPreConditions(proxyRegistryUtils); - - context.checking(new Expectations() {{ - exactly(5).of(proxyRegistryUtils).getTags(with(any(RegistryUrl.class))); - will(returnValue(new ArrayList<>())); - }}); - - preConditions.handle(proxyConfigUpdateContext); - - assertFalse(proxyConfigUpdateContext.getErrorReport().hasErrors()); - } - } diff --git a/java/code/src/com/suse/proxy/test/ProxyConfigUpdateTest.java b/java/code/src/com/suse/proxy/test/ProxyConfigUpdateTest.java deleted file mode 100644 index 963106a24563..000000000000 --- a/java/code/src/com/suse/proxy/test/ProxyConfigUpdateTest.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2025 SUSE LLC - * - * This software is licensed to you under the GNU General Public License, - * version 2 (GPLv2). There is NO WARRANTY for this software, express or - * implied, including the implied warranties of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 - * along with this software; if not, see - * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * Red Hat trademarks are not licensed under GPLv2. No permission is - * granted to use or replicate Red Hat trademarks that are incorporated - * in this software or its documentation. - */ - -package com.suse.proxy.test; - -import static org.junit.Assert.assertEquals; - -import com.redhat.rhn.domain.user.User; -import com.redhat.rhn.manager.system.SystemManager; -import com.redhat.rhn.testing.MockObjectTestCase; -import com.redhat.rhn.testing.RhnBaseTestCase; - -import com.suse.manager.webui.services.iface.SaltApi; -import com.suse.manager.webui.utils.gson.ProxyConfigUpdateJson; -import com.suse.proxy.update.ProxyConfigUpdate; -import com.suse.proxy.update.ProxyConfigUpdateContext; -import com.suse.proxy.update.ProxyConfigUpdateContextHandler; - -import org.jmock.Expectations; -import org.jmock.junit5.JUnit5Mockery; -import org.junit.Before; -import org.junit.Test; -import org.junit.jupiter.api.extension.ExtendWith; - -import java.util.List; - -@ExtendWith(JUnit5Mockery.class) -public class ProxyConfigUpdateTest extends MockObjectTestCase { - - private ProxyConfigUpdate proxyConfigUpdate; - private ProxyConfigUpdateJson request; - private SystemManager systemManager; - private SaltApi saltApi; - private User user; - private ProxyConfigUpdateContextHandler handler1; - private ProxyConfigUpdateContextHandler handler2; - - @Before - public void setUp() { - request = new ProxyConfigUpdateJson(); - systemManager = context.mock(SystemManager.class); - saltApi = context.mock(SaltApi.class); - user = context.mock(User.class); - handler1 = context.mock(ProxyConfigUpdateContextHandler.class, "handler1"); - handler2 = context.mock(ProxyConfigUpdateContextHandler.class, "handler2"); - - proxyConfigUpdate = null; // new ProxyConfigUpdate(List.of(handler1, handler2)); - } - - @Test - public void testUpdate() { - context.checking(new Expectations() {{ - oneOf(handler1).handle(with(any(ProxyConfigUpdateContext.class))); - oneOf(handler2).handle(with(any(ProxyConfigUpdateContext.class))); - }}); - - proxyConfigUpdate.update(request, systemManager, saltApi, user); - } - - @Test - public void testUpdateWithError() { - context.checking(new Expectations() {{ - oneOf(handler1).handle(with(any(ProxyConfigUpdateContext.class))); - will(throwException(new RuntimeException("Handler error"))); - }}); - - try { - proxyConfigUpdate.update(request, systemManager, saltApi, user); - } catch (RuntimeException e) { - assertEquals("Handler error", e.getMessage()); - } - - context.assertIsSatisfied(); - } -} \ No newline at end of file diff --git a/java/code/src/com/suse/proxy/test/ProxyConfigUpdateTestUtils.java b/java/code/src/com/suse/proxy/test/ProxyConfigUpdateTestUtils.java new file mode 100644 index 000000000000..f05b4dbc9a45 --- /dev/null +++ b/java/code/src/com/suse/proxy/test/ProxyConfigUpdateTestUtils.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2025 SUSE LLC + * + * This software is licensed to you under the GNU General Public License, + * version 2 (GPLv2). There is NO WARRANTY for this software, express or + * implied, including the implied warranties of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 + * along with this software; if not, see + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * Red Hat trademarks are not licensed under GPLv2. No permission is + * granted to use or replicate Red Hat trademarks that are incorporated + * in this software or its documentation. + */ + +package com.suse.proxy.test; + +import static com.redhat.rhn.common.ExceptionMessage.NOT_INSTANTIABLE; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import com.redhat.rhn.common.RhnError; + +import com.suse.proxy.ProxyContainerImagesEnum; +import com.suse.proxy.update.ProxyConfigUpdateContext; + +import java.util.Set; +import java.util.stream.Collectors; + +/** + * Utils for ProxyConfigUpdate tests + */ +public class ProxyConfigUpdateTestUtils { + + public static final String DUMMY_PROXY_FQDN = "proxy.fqdn.com"; + public static final String DUMMY_PARENT_FQDN = "parent.fqdn.com"; + public static final String DUMMY_ROOT_CA = "rootCA"; + public static final String DUMMY_INTERMEDIATE_CA_1 = "intermediateCA1"; + public static final String DUMMY_INTERMEDIATE_CA_2 = "intermediateCA2"; + public static final String DUMMY_PROXY_CERT = "proxyCert"; + public static final String DUMMY_PROXY_KEY = "proxyKey"; + public static final String DUMMY_TAG = "tag"; + public static final String DUMMY_ADMIN_MAIL = "admin@suse.com"; + public static final String DUMMY_URL_PREFIX = "http://suse.com/images/"; + + public static final long DUMMY_SERVER_ID = 123L; + public static final int DUMMY_PROXY_PORT = 8080; + public static final int DUMMY_MAX_CACHE = 1024; + + private ProxyConfigUpdateTestUtils() { + throw new UnsupportedOperationException(NOT_INSTANTIABLE); + } + + /** + * Asserts the expected error messages are present in the context + * + * @param expectedErrorMessages the expected error messages array string + * @param context the context + */ + public static void assertExpectedErrors(String[] expectedErrorMessages, ProxyConfigUpdateContext context) { + assertTrue(context.getErrorReport().hasErrors()); + assertEquals(expectedErrorMessages.length, context.getErrorReport().getErrors().size()); + + Set actualErrorMessages = + context.getErrorReport().getErrors().stream().map(RhnError::getMessage).collect(Collectors.toSet()); + assertTrue(actualErrorMessages.containsAll(Set.of(expectedErrorMessages))); + } + + /** + * Generates well-formed dummy URL for the given image. + * @param proxyContainerImagesEnum the image + * @return the dummy URL + */ + public static String getDummyUrl(ProxyContainerImagesEnum proxyContainerImagesEnum) { + return DUMMY_URL_PREFIX + proxyContainerImagesEnum.getImageName(); + } + + /** + * Generates a dynamic dummy tag for the given image. + * @param proxyContainerImagesEnum the image + * @return the dummy tag + */ + public static String getDummyTag(ProxyContainerImagesEnum proxyContainerImagesEnum) { + return DUMMY_TAG + "_" + proxyContainerImagesEnum.getImageName(); + } + +} diff --git a/java/code/src/com/suse/proxy/test/ProxyConfigUpdateUtils.java b/java/code/src/com/suse/proxy/test/ProxyConfigUpdateUtils.java deleted file mode 100644 index 9b23afb0b6df..000000000000 --- a/java/code/src/com/suse/proxy/test/ProxyConfigUpdateUtils.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2025 SUSE LLC - * - * This software is licensed to you under the GNU General Public License, - * version 2 (GPLv2). There is NO WARRANTY for this software, express or - * implied, including the implied warranties of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 - * along with this software; if not, see - * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * Red Hat trademarks are not licensed under GPLv2. No permission is - * granted to use or replicate Red Hat trademarks that are incorporated - * in this software or its documentation. - */ - -package com.suse.proxy.test; - -import static com.redhat.rhn.common.ExceptionMessage.NOT_INSTANTIABLE; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import com.redhat.rhn.common.RhnError; - -import com.suse.proxy.update.ProxyConfigUpdateContext; - -import java.util.List; - -public class ProxyConfigUpdateUtils { - - private ProxyConfigUpdateUtils() { - throw new UnsupportedOperationException(NOT_INSTANTIABLE); - } - - /** - * Asserts the expected error messages are present in the context - * - * @param expectedErrorMessages the expected error messages array string - * @param context the context - */ - public static void assertExpectedErrors(String[] expectedErrorMessages, ProxyConfigUpdateContext context) { - assertTrue(context.getErrorReport().hasErrors()); - assertEquals(expectedErrorMessages.length, context.getErrorReport().getErrors().size()); - - List actualErrorMessages = - context.getErrorReport().getErrors().stream().map(RhnError::getMessage).toList(); - assertTrue(actualErrorMessages.containsAll(List.of(expectedErrorMessages))); - } - -} diff --git a/java/code/src/com/suse/proxy/test/ProxyConfigUpdateValidationTest.java b/java/code/src/com/suse/proxy/test/ProxyConfigUpdateValidationTest.java index f9cbd6325ad2..3a9cba869189 100644 --- a/java/code/src/com/suse/proxy/test/ProxyConfigUpdateValidationTest.java +++ b/java/code/src/com/suse/proxy/test/ProxyConfigUpdateValidationTest.java @@ -18,7 +18,17 @@ import static com.suse.proxy.ProxyConfigUtils.REGISTRY_MODE_ADVANCED; import static com.suse.proxy.ProxyConfigUtils.REGISTRY_MODE_SIMPLE; import static com.suse.proxy.ProxyConfigUtils.SOURCE_MODE_REGISTRY; -import static com.suse.proxy.test.ProxyConfigUpdateUtils.assertExpectedErrors; +import static com.suse.proxy.test.ProxyConfigUpdateTestUtils.DUMMY_ADMIN_MAIL; +import static com.suse.proxy.test.ProxyConfigUpdateTestUtils.DUMMY_MAX_CACHE; +import static com.suse.proxy.test.ProxyConfigUpdateTestUtils.DUMMY_PARENT_FQDN; +import static com.suse.proxy.test.ProxyConfigUpdateTestUtils.DUMMY_PROXY_CERT; +import static com.suse.proxy.test.ProxyConfigUpdateTestUtils.DUMMY_PROXY_FQDN; +import static com.suse.proxy.test.ProxyConfigUpdateTestUtils.DUMMY_PROXY_KEY; +import static com.suse.proxy.test.ProxyConfigUpdateTestUtils.DUMMY_PROXY_PORT; +import static com.suse.proxy.test.ProxyConfigUpdateTestUtils.DUMMY_ROOT_CA; +import static com.suse.proxy.test.ProxyConfigUpdateTestUtils.DUMMY_SERVER_ID; +import static com.suse.proxy.test.ProxyConfigUpdateTestUtils.DUMMY_TAG; +import static com.suse.proxy.test.ProxyConfigUpdateTestUtils.assertExpectedErrors; import static org.junit.jupiter.api.Assertions.assertFalse; import com.redhat.rhn.domain.server.Server; @@ -43,6 +53,8 @@ @ExtendWith(JUnit5Mockery.class) public class ProxyConfigUpdateValidationTest extends MockObjectTestCase { + public static final String UNKNOWN = "unknown"; + /** * Test a scenario where ProxyConfigUpdateJson is resolved as being empty */ @@ -84,19 +96,19 @@ public void testFailureWhenProxyFqdnNotResolvedAndParentFqdnIsInvalid() { }; ProxyConfigUpdateJson request = new ProxyConfigUpdateJsonBuilder() - .serverId(123L) + .serverId(DUMMY_SERVER_ID) .parentFqdn("invalid@fqdn") - .proxyPort(3182) - .maxCache(1000) - .email("admin@suse.com") + .proxyPort(DUMMY_PROXY_PORT) + .maxCache(DUMMY_MAX_CACHE) + .email(DUMMY_ADMIN_MAIL) .sourceRPM() .build(); ProxyConfigUpdateContext proxyConfigUpdateContext = new ProxyConfigUpdateContext(request, null, null, null); // certificate content is handled in {@link ProxyConfigUpdateAcquisitor} and set directly in the context - proxyConfigUpdateContext.setRootCA("rootCA"); - proxyConfigUpdateContext.setProxyCert("proxyCert"); - proxyConfigUpdateContext.setProxyKey("proxyKey"); + proxyConfigUpdateContext.setRootCA(DUMMY_ROOT_CA); + proxyConfigUpdateContext.setProxyCert(DUMMY_PROXY_CERT); + proxyConfigUpdateContext.setProxyKey(DUMMY_PROXY_KEY); // new ProxyConfigUpdateValidation().handle(proxyConfigUpdateContext); @@ -114,11 +126,11 @@ public void testSuccessWhenReplaceCerts() { ProxyConfigUpdateContext proxyConfigUpdateContext = new ProxyConfigUpdateContext(request, null, null, null); // certificate content is handled in {@link ProxyConfigUpdateAcquisitor} and set directly in the context - proxyConfigUpdateContext.setRootCA("rootCA"); - proxyConfigUpdateContext.setProxyCert("proxyCert"); - proxyConfigUpdateContext.setProxyKey("proxyKey"); - proxyConfigUpdateContext.setParentServer(new Server(123L, "parent.fqdn.com")); - proxyConfigUpdateContext.setProxyFqdn("proxy.fqdn.com"); + proxyConfigUpdateContext.setRootCA(DUMMY_ROOT_CA); + proxyConfigUpdateContext.setProxyCert(DUMMY_PROXY_CERT); + proxyConfigUpdateContext.setProxyKey(DUMMY_PROXY_KEY); + proxyConfigUpdateContext.setParentServer(new Server(DUMMY_SERVER_ID, DUMMY_PARENT_FQDN)); + proxyConfigUpdateContext.setProxyFqdn(DUMMY_PROXY_FQDN); // new ProxyConfigUpdateValidation().handle(proxyConfigUpdateContext); @@ -156,8 +168,8 @@ public void testFailWhenKeepCertsButNoExistingProxyConfig() { .build(); ProxyConfigUpdateContext proxyConfigUpdateContext = new ProxyConfigUpdateContext(request, null, null, null); - proxyConfigUpdateContext.setParentServer(new Server(123L, "parent.fqdn.com")); - proxyConfigUpdateContext.setProxyFqdn("proxy.fqdn.com"); + proxyConfigUpdateContext.setParentServer(new Server(DUMMY_SERVER_ID, DUMMY_PARENT_FQDN)); + proxyConfigUpdateContext.setProxyFqdn(DUMMY_PROXY_FQDN); // new ProxyConfigUpdateValidation().handle(proxyConfigUpdateContext); @@ -181,8 +193,8 @@ public void testFailWhenKeepCertsButNoExistingCertificates() { .build(); ProxyConfigUpdateContext proxyConfigUpdateContext = new ProxyConfigUpdateContext(request, null, null, null); - proxyConfigUpdateContext.setParentServer(new Server(123L, "parent.fqdn.com")); - proxyConfigUpdateContext.setProxyFqdn("proxy.fqdn.com"); + proxyConfigUpdateContext.setParentServer(new Server(DUMMY_SERVER_ID, DUMMY_PARENT_FQDN)); + proxyConfigUpdateContext.setProxyFqdn(DUMMY_PROXY_FQDN); proxyConfigUpdateContext.setProxyConfig(new ProxyConfig()); // @@ -202,7 +214,7 @@ public void testFailWhenInvalidSourceMode() { }; ProxyConfigUpdateJson request = getBaseRequestWithReplaceCerts() - .sourceMode("unknown") + .sourceMode(UNKNOWN) .build(); ProxyConfigUpdateContext proxyConfigUpdateContext = getProxyConfigUpdateContext(request); @@ -225,7 +237,7 @@ public void testFailWhenInvalidRegistryMode() { ProxyConfigUpdateJson request = getBaseRequestWithReplaceCerts() .sourceMode(SOURCE_MODE_REGISTRY) - .registryMode("unknown") + .registryMode(UNKNOWN) .build(); ProxyConfigUpdateContext proxyConfigUpdateContext = getProxyConfigUpdateContext(request); @@ -267,7 +279,7 @@ public void testSuccessWhenSimpleRegistryMode() { .sourceMode(SOURCE_MODE_REGISTRY) .registryMode(REGISTRY_MODE_SIMPLE) .registryBaseURL("http://registry.suse.com") - .registryBaseTag("latest") + .registryBaseTag(DUMMY_TAG) .build(); ProxyConfigUpdateContext proxyConfigUpdateContext = getProxyConfigUpdateContext(request); @@ -315,11 +327,11 @@ public void testFailWhenAdvancedRegistryModeButNoUrlsOrTagsProvided() { public void testSuccessWhenAdvancedRegistryMode() { ProxyConfigUpdateJson request = getBaseRequestWithReplaceCerts() .sourceRegistryAdvanced( - "http://registry.suse.com/httpd", "latest", - "http://registry.suse.com/saltbroker", "latest", - "http://registry.suse.com/squid", "latest", - "http://registry.suse.com/ssh", "latest", - "http://registry.suse.com/tftpd", "latest" + "http://registry.suse.com/httpd", DUMMY_TAG, + "http://registry.suse.com/saltbroker", DUMMY_TAG, + "http://registry.suse.com/squid", DUMMY_TAG, + "http://registry.suse.com/ssh", DUMMY_TAG, + "http://registry.suse.com/tftpd", DUMMY_TAG ) .build(); @@ -340,13 +352,13 @@ public void testSuccessWhenAdvancedRegistryMode() { */ private static ProxyConfigUpdateContext getProxyConfigUpdateContext(ProxyConfigUpdateJson request) { ProxyConfigUpdateContext proxyConfigUpdateContext = new ProxyConfigUpdateContext(request, null, null, null); - proxyConfigUpdateContext.setParentServer(new Server(123L, "parent.fqdn.com")); - proxyConfigUpdateContext.setProxyFqdn("proxy.fqdn.com"); + proxyConfigUpdateContext.setParentServer(new Server(DUMMY_SERVER_ID, DUMMY_PARENT_FQDN)); + proxyConfigUpdateContext.setProxyFqdn(DUMMY_PROXY_FQDN); // certificate content is handled in {@link ProxyConfigUpdateAcquisitor} and set directly in the context proxyConfigUpdateContext.setProxyConfig(new ProxyConfig()); - proxyConfigUpdateContext.setRootCA("rootCA"); - proxyConfigUpdateContext.setProxyCert("proxyCert"); - proxyConfigUpdateContext.setProxyKey("proxyKey"); + proxyConfigUpdateContext.setRootCA(DUMMY_ROOT_CA); + proxyConfigUpdateContext.setProxyCert(DUMMY_PROXY_CERT); + proxyConfigUpdateContext.setProxyKey(DUMMY_PROXY_KEY); return proxyConfigUpdateContext; } @@ -357,11 +369,11 @@ private static ProxyConfigUpdateContext getProxyConfigUpdateContext(ProxyConfigU */ private ProxyConfigUpdateJsonBuilder getBaseRequestWithRpm() { return new ProxyConfigUpdateJsonBuilder() - .serverId(123L) - .parentFqdn("proxy.suse.com") - .proxyPort(3182) - .maxCache(1000) - .email("admin@suse.com") + .serverId(DUMMY_SERVER_ID) + .parentFqdn(DUMMY_PARENT_FQDN) + .proxyPort(DUMMY_PROXY_PORT) + .maxCache(DUMMY_MAX_CACHE) + .email(DUMMY_ADMIN_MAIL) .sourceRPM(); } @@ -372,11 +384,11 @@ private ProxyConfigUpdateJsonBuilder getBaseRequestWithRpm() { */ private ProxyConfigUpdateJsonBuilder getBaseRequestWithReplaceCerts() { return new ProxyConfigUpdateJsonBuilder() - .serverId(123L) - .parentFqdn("proxy.suse.com") - .proxyPort(3182) - .maxCache(1000) - .email("admin@suse.com") + .serverId(DUMMY_SERVER_ID) + .parentFqdn(DUMMY_PARENT_FQDN) + .proxyPort(DUMMY_PROXY_PORT) + .maxCache(DUMMY_MAX_CACHE) + .email(DUMMY_ADMIN_MAIL) .replaceCerts(null, null, null, null); } } diff --git a/java/code/src/com/suse/proxy/test/ProxyConfigUtilsTest.java b/java/code/src/com/suse/proxy/test/ProxyConfigUtilsTest.java new file mode 100644 index 000000000000..448ba673ccb5 --- /dev/null +++ b/java/code/src/com/suse/proxy/test/ProxyConfigUtilsTest.java @@ -0,0 +1,778 @@ +/* + * Copyright (c) 2025 SUSE LLC + * + * This software is licensed to you under the GNU General Public License, + * version 2 (GPLv2). There is NO WARRANTY for this software, express or + * implied, including the implied warranties of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 + * along with this software; if not, see + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * Red Hat trademarks are not licensed under GPLv2. No permission is + * granted to use or replicate Red Hat trademarks that are incorporated + * in this software or its documentation. + */ + +package com.suse.proxy.test; + +import static com.suse.proxy.ProxyConfigUtils.EMAIL_FIELD; +import static com.suse.proxy.ProxyConfigUtils.INTERMEDIATE_CAS_FIELD; +import static com.suse.proxy.ProxyConfigUtils.MAX_CACHE_FIELD; +import static com.suse.proxy.ProxyConfigUtils.PARENT_FQDN_FIELD; +import static com.suse.proxy.ProxyConfigUtils.PILLAR_REGISTRY_ENTRY; +import static com.suse.proxy.ProxyConfigUtils.PILLAR_REGISTRY_TAG_ENTRY; +import static com.suse.proxy.ProxyConfigUtils.PILLAR_REGISTRY_URL_ENTRY; +import static com.suse.proxy.ProxyConfigUtils.PROXY_CERT_FIELD; +import static com.suse.proxy.ProxyConfigUtils.PROXY_FQDN_FIELD; +import static com.suse.proxy.ProxyConfigUtils.PROXY_KEY_FIELD; +import static com.suse.proxy.ProxyConfigUtils.PROXY_PORT_FIELD; +import static com.suse.proxy.ProxyConfigUtils.ROOT_CA_FIELD; +import static com.suse.proxy.ProxyConfigUtils.SERVER_ID_FIELD; +import static com.suse.proxy.test.ProxyConfigUpdateTestUtils.DUMMY_ADMIN_MAIL; +import static com.suse.proxy.test.ProxyConfigUpdateTestUtils.DUMMY_INTERMEDIATE_CA_1; +import static com.suse.proxy.test.ProxyConfigUpdateTestUtils.DUMMY_INTERMEDIATE_CA_2; +import static com.suse.proxy.test.ProxyConfigUpdateTestUtils.DUMMY_MAX_CACHE; +import static com.suse.proxy.test.ProxyConfigUpdateTestUtils.DUMMY_PARENT_FQDN; +import static com.suse.proxy.test.ProxyConfigUpdateTestUtils.DUMMY_PROXY_CERT; +import static com.suse.proxy.test.ProxyConfigUpdateTestUtils.DUMMY_PROXY_FQDN; +import static com.suse.proxy.test.ProxyConfigUpdateTestUtils.DUMMY_PROXY_KEY; +import static com.suse.proxy.test.ProxyConfigUpdateTestUtils.DUMMY_PROXY_PORT; +import static com.suse.proxy.test.ProxyConfigUpdateTestUtils.DUMMY_ROOT_CA; +import static com.suse.proxy.test.ProxyConfigUpdateTestUtils.DUMMY_SERVER_ID; +import static com.suse.proxy.test.ProxyConfigUpdateTestUtils.DUMMY_TAG; +import static com.suse.proxy.test.ProxyConfigUpdateTestUtils.DUMMY_URL_PREFIX; +import static com.suse.proxy.test.ProxyConfigUpdateTestUtils.getDummyTag; +import static com.suse.proxy.test.ProxyConfigUpdateTestUtils.getDummyUrl; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import com.redhat.rhn.domain.server.Pillar; +import com.redhat.rhn.testing.MockObjectTestCase; + +import com.suse.proxy.ProxyConfigUtils; +import com.suse.proxy.ProxyContainerImagesEnum; +import com.suse.proxy.model.ProxyConfig; +import com.suse.proxy.model.ProxyConfigImage; + +import org.jmock.Expectations; +import org.jmock.imposters.ByteBuddyClassImposteriser; +import org.jmock.junit5.JUnit5Mockery; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +/** + * Test class for {@link ProxyConfigUtils} + */ +@SuppressWarnings({"squid:S3599", "java:S1171"}) //jmock +@ExtendWith(JUnit5Mockery.class) +public class ProxyConfigUtilsTest extends MockObjectTestCase { + public static final String DUMMY_TAG_2 = "anotherTag"; + + private Pillar mockPillar; + + @BeforeEach + public void setUp() { + setImposteriser(ByteBuddyClassImposteriser.INSTANCE); + mockPillar = context.mock(Pillar.class); + } + + /** + * Tests the {@link ProxyConfigUtils#proxyConfigFromPillar(Pillar)} method when the pillar returns null. + **/ + @Test + public void testProxyConfigWhenNoPillar() { + context.checking(new Expectations() {{ + oneOf(mockPillar).getPillar(); + will(returnValue(null)); + }}); + + ProxyConfig proxyConfig = ProxyConfigUtils.proxyConfigFromPillar(mockPillar); + + assertNull(proxyConfig.getServerId()); + assertNull(proxyConfig.getProxyFqdn()); + assertNull(proxyConfig.getParentFqdn()); + assertNull(proxyConfig.getProxyPort()); + assertNull(proxyConfig.getMaxCache()); + assertNull(proxyConfig.getEmail()); + assertNull(proxyConfig.getRootCA()); + assertNull(proxyConfig.getProxyCert()); + assertNull(proxyConfig.getProxyKey()); + assertNull(proxyConfig.getIntermediateCAs()); + assertNull(proxyConfig.getHttpdImage()); + assertNull(proxyConfig.getSaltBrokerImage()); + assertNull(proxyConfig.getSquidImage()); + assertNull(proxyConfig.getSshImage()); + assertNull(proxyConfig.getTftpdImage()); + } + + /** + * Tests the {@link ProxyConfigUtils#proxyConfigFromPillar(Pillar)} method when the pillar is returns no data. + */ + @Test + public void testProxyConfigWhenBlankPillar() { + context.checking(new Expectations() {{ + allowing(mockPillar).getPillar(); + will(returnValue(new HashMap<>())); + }}); + + ProxyConfig proxyConfig = ProxyConfigUtils.proxyConfigFromPillar(mockPillar); + + assertNull(proxyConfig.getServerId()); + assertNull(proxyConfig.getProxyFqdn()); + assertNull(proxyConfig.getParentFqdn()); + assertNull(proxyConfig.getProxyPort()); + assertNull(proxyConfig.getMaxCache()); + assertNull(proxyConfig.getEmail()); + assertNull(proxyConfig.getRootCA()); + assertNull(proxyConfig.getProxyCert()); + assertNull(proxyConfig.getProxyKey()); + assertNull(proxyConfig.getIntermediateCAs()); + assertNull(proxyConfig.getHttpdImage()); + assertNull(proxyConfig.getSaltBrokerImage()); + assertNull(proxyConfig.getSquidImage()); + assertNull(proxyConfig.getSshImage()); + assertNull(proxyConfig.getTftpdImage()); + } + + /** + * Tests the {@link ProxyConfigUtils#proxyConfigFromPillar(Pillar)} method when the pillar returns full data + * with registries. + */ + @Test + public void testProxyConfigFromPillarWithRegistries() { + final String expectedHttpdUrl = getDummyUrl(ProxyContainerImagesEnum.PROXY_HTTPD); + final String expectedSaltBrokerUrl = getDummyUrl(ProxyContainerImagesEnum.PROXY_SALT_BROKER); + final String expectedSquidUrl = getDummyUrl(ProxyContainerImagesEnum.PROXY_SQUID); + final String expectedSshUrl = getDummyUrl(ProxyContainerImagesEnum.PROXY_SSH); + final String expectedTftpdUrl = getDummyUrl(ProxyContainerImagesEnum.PROXY_TFTPD); + + final String expectedHttpdTag = getDummyTag(ProxyContainerImagesEnum.PROXY_HTTPD); + final String expectedSaltBrokerTag = getDummyTag(ProxyContainerImagesEnum.PROXY_SALT_BROKER); + final String expectedSquidTag = getDummyTag(ProxyContainerImagesEnum.PROXY_SQUID); + final String expectedSshTag = getDummyTag(ProxyContainerImagesEnum.PROXY_SSH); + final String expectedTftpdTag = getDummyTag(ProxyContainerImagesEnum.PROXY_TFTPD); + + context.checking(new Expectations() {{ + allowing(mockPillar).getPillar(); + will(returnValue(createPillarMapWithRegistryAdvancedMode())); + }}); + + // + ProxyConfig proxyConfig = ProxyConfigUtils.proxyConfigFromPillar(mockPillar); + + assertEquals(DUMMY_SERVER_ID, proxyConfig.getServerId()); + assertEquals(DUMMY_PROXY_FQDN, proxyConfig.getProxyFqdn()); + assertEquals(DUMMY_PARENT_FQDN, proxyConfig.getParentFqdn()); + assertEquals(DUMMY_PROXY_PORT, proxyConfig.getProxyPort()); + assertEquals(DUMMY_MAX_CACHE, proxyConfig.getMaxCache()); + assertEquals(DUMMY_ADMIN_MAIL, proxyConfig.getEmail()); + assertEquals(DUMMY_ROOT_CA, proxyConfig.getRootCA()); + assertEquals(DUMMY_PROXY_CERT, proxyConfig.getProxyCert()); + assertEquals(DUMMY_PROXY_KEY, proxyConfig.getProxyKey()); + assertTrue(proxyConfig.getIntermediateCAs().contains(DUMMY_INTERMEDIATE_CA_1)); + assertTrue(proxyConfig.getIntermediateCAs().contains(DUMMY_INTERMEDIATE_CA_2)); + + ProxyConfigImage httpdImage = proxyConfig.getHttpdImage(); + assertNotNull(httpdImage); + assertEquals(expectedHttpdUrl, httpdImage.getUrl()); + assertEquals(expectedHttpdTag, httpdImage.getTag()); + + ProxyConfigImage saltBrokerImage = proxyConfig.getSaltBrokerImage(); + assertNotNull(saltBrokerImage); + assertEquals(expectedSaltBrokerUrl, saltBrokerImage.getUrl()); + assertEquals(expectedSaltBrokerTag, saltBrokerImage.getTag()); + + ProxyConfigImage squidImage = proxyConfig.getSquidImage(); + assertNotNull(squidImage); + assertEquals(expectedSquidUrl, squidImage.getUrl()); + assertEquals(expectedSquidTag, squidImage.getTag()); + + ProxyConfigImage sshImage = proxyConfig.getSshImage(); + assertNotNull(sshImage); + assertEquals(expectedSshUrl, sshImage.getUrl()); + assertEquals(expectedSshTag, sshImage.getTag()); + + ProxyConfigImage tftpdImage = proxyConfig.getTftpdImage(); + assertNotNull(tftpdImage); + assertEquals(expectedTftpdUrl, tftpdImage.getUrl()); + assertEquals(expectedTftpdTag, tftpdImage.getTag()); + } + + /** + * Tests the {@link ProxyConfigUtils#getCommonTag} method when the images have a common tag. + */ + @Test + public void testGetCommonTagWhenCommonTag() { + ProxyConfigImage image1 = new ProxyConfigImage(DUMMY_URL_PREFIX, DUMMY_TAG); + ProxyConfigImage image2 = new ProxyConfigImage(DUMMY_URL_PREFIX, DUMMY_TAG); + + Optional commonTag = ProxyConfigUtils.getCommonTag(image1, image2); + + assertTrue(commonTag.isPresent()); + assertEquals(DUMMY_TAG, commonTag.get()); + } + + /** + * Tests the {@link ProxyConfigUtils#getCommonTag} method when the images have no common tag. + */ + @Test + public void testGetCommonTagWhenNoCommonTag() { + ProxyConfigImage image1 = new ProxyConfigImage(DUMMY_URL_PREFIX, DUMMY_TAG); + ProxyConfigImage image2 = new ProxyConfigImage(DUMMY_URL_PREFIX, DUMMY_TAG_2); + + Optional commonTag = ProxyConfigUtils.getCommonTag(image1, image2); + + assertFalse(commonTag.isPresent()); + } + + /** + * Tests the {@link ProxyConfigUtils#getCommonPrefix} method when the images have a common prefix. + */ + @Test + public void testGetCommonPrefixWhenCommonPrefixAndImageNamesMatch() { + ProxyConfigImage httpdImage = + new ProxyConfigImage(getDummyUrl(ProxyContainerImagesEnum.PROXY_HTTPD), DUMMY_TAG); + ProxyConfigImage squidImage = + new ProxyConfigImage(getDummyUrl(ProxyContainerImagesEnum.PROXY_SQUID), DUMMY_TAG_2); + + Optional commonPrefix = ProxyConfigUtils.getCommonPrefix(httpdImage, squidImage); + + assertTrue(commonPrefix.isPresent()); + assertEquals(DUMMY_URL_PREFIX, commonPrefix.get()); + } + + /** + * Tests the {@link ProxyConfigUtils#getCommonPrefix} method when the images have no common prefix. + */ + @Test + public void testGetCommonPrefixWhenNoCommonPrefixAndImageNamesMatch() { + ProxyConfigImage httpdImage = new ProxyConfigImage( + "http://not.suse.com/images/" + ProxyContainerImagesEnum.PROXY_HTTPD.getImageName(), DUMMY_TAG + ); + ProxyConfigImage squidImage = + new ProxyConfigImage(getDummyUrl(ProxyContainerImagesEnum.PROXY_SQUID), DUMMY_TAG_2); + + Optional commonPrefix = ProxyConfigUtils.getCommonPrefix(httpdImage, squidImage); + + assertFalse(commonPrefix.isPresent()); + } + + /** + * Tests the {@link ProxyConfigUtils#getCommonPrefix} method when the images have a common prefix but the images + * names do not match the expected ones at {@link ProxyContainerImagesEnum}. + */ + @Test + public void testGetCommonPrefixWhenCommonPrefixAndImageNamesDoNotMatch() { + ProxyConfigImage image = + new ProxyConfigImage(DUMMY_URL_PREFIX + "not-fitting-image-name", DUMMY_TAG); + ProxyConfigImage squidImage = + new ProxyConfigImage(getDummyUrl(ProxyContainerImagesEnum.PROXY_SQUID), DUMMY_TAG); + + Optional commonPrefix = ProxyConfigUtils.getCommonPrefix(image, squidImage); + + assertFalse(commonPrefix.isPresent()); + } + + @Test + public void testGetCommonPrefixWhenInvalidScenarios() { + ProxyConfigImage nullImage = null; + ProxyConfigImage emptyImage = new ProxyConfigImage(); + ProxyConfigImage emptyUrlAndTagImage = new ProxyConfigImage("", ""); + ProxyConfigImage emptyUrlImage = new ProxyConfigImage("", DUMMY_TAG); + ProxyConfigImage noImageUrlImage = + new ProxyConfigImage("https://suse.com", ""); + ProxyConfigImage invalidUrlImage = new ProxyConfigImage("something@not.valid", DUMMY_TAG); + + Optional nullImageCommonPrefix = ProxyConfigUtils.getCommonPrefix(nullImage); + Optional emptyImageCommonPrefix = ProxyConfigUtils.getCommonPrefix(emptyImage); + Optional emptyUrlAndTagImageCommonPrefix = ProxyConfigUtils.getCommonPrefix(emptyUrlAndTagImage); + Optional emptyUrlImageCommonPrefix = ProxyConfigUtils.getCommonPrefix(emptyUrlImage); + Optional noImageUrlImageCommonPrefix = ProxyConfigUtils.getCommonPrefix(noImageUrlImage); + Optional invalidUrlImageCommonPrefix = ProxyConfigUtils.getCommonPrefix(invalidUrlImage); + + assertFalse(nullImageCommonPrefix.isPresent()); + assertFalse(emptyImageCommonPrefix.isPresent()); + assertFalse(emptyUrlAndTagImageCommonPrefix.isPresent()); + assertFalse(emptyUrlImageCommonPrefix.isPresent()); + assertFalse(noImageUrlImageCommonPrefix.isPresent()); + assertFalse(invalidUrlImageCommonPrefix.isPresent()); + } + + + /** + * Tests the {@link ProxyConfigUtils#dataMapFromProxyConfig} method when the proxy config is empty. + */ + @Test + public void testDataMapFromProxyConfigWhenEmpty() { + Map dataMap = ProxyConfigUtils.dataMapFromProxyConfig(new ProxyConfig()); + + assertNull(dataMap.get(ProxyConfigUtils.SERVER_ID_FIELD)); + assertNull(dataMap.get(ProxyConfigUtils.PROXY_FQDN_FIELD)); + assertNull(dataMap.get(ProxyConfigUtils.PARENT_FQDN_FIELD)); + assertNull(dataMap.get(ProxyConfigUtils.PROXY_PORT_FIELD)); + assertNull(dataMap.get(ProxyConfigUtils.MAX_CACHE_FIELD)); + assertNull(dataMap.get(ProxyConfigUtils.EMAIL_FIELD)); + } + + /** + * Tests the {@link ProxyConfigUtils#dataMapFromProxyConfig} method when the proxy config is null. + */ + @Test + public void testDataMapFromProxyConfigWhenNull() { + Map dataMap = ProxyConfigUtils.dataMapFromProxyConfig(null); + + assertNull(dataMap.get(ProxyConfigUtils.SERVER_ID_FIELD)); + assertNull(dataMap.get(ProxyConfigUtils.PROXY_FQDN_FIELD)); + assertNull(dataMap.get(ProxyConfigUtils.PARENT_FQDN_FIELD)); + assertNull(dataMap.get(ProxyConfigUtils.PROXY_PORT_FIELD)); + assertNull(dataMap.get(ProxyConfigUtils.MAX_CACHE_FIELD)); + assertNull(dataMap.get(ProxyConfigUtils.EMAIL_FIELD)); + assertNull(dataMap.get(ProxyConfigUtils.SOURCE_MODE_FIELD)); + assertNull(dataMap.get(ProxyConfigUtils.REGISTRY_MODE)); + assertNull(dataMap.get(ProxyConfigUtils.REGISTRY_BASE_URL)); + assertNull(dataMap.get(ProxyConfigUtils.REGISTRY_BASE_TAG)); + assertNull(dataMap.get(ProxyContainerImagesEnum.PROXY_HTTPD.getUrlField())); + assertNull(dataMap.get(ProxyContainerImagesEnum.PROXY_HTTPD.getTagField())); + assertNull(dataMap.get(ProxyContainerImagesEnum.PROXY_SALT_BROKER.getUrlField())); + assertNull(dataMap.get(ProxyContainerImagesEnum.PROXY_SALT_BROKER.getTagField())); + assertNull(dataMap.get(ProxyContainerImagesEnum.PROXY_SQUID.getUrlField())); + assertNull(dataMap.get(ProxyContainerImagesEnum.PROXY_SQUID.getTagField())); + assertNull(dataMap.get(ProxyContainerImagesEnum.PROXY_SSH.getUrlField())); + assertNull(dataMap.get(ProxyContainerImagesEnum.PROXY_SSH.getTagField())); + assertNull(dataMap.get(ProxyContainerImagesEnum.PROXY_TFTPD.getUrlField())); + assertNull(dataMap.get(ProxyContainerImagesEnum.PROXY_TFTPD.getTagField())); + } + + /** + * Tests the {@link ProxyConfigUtils#dataMapFromProxyConfig} method in a scenario of using RPM as the source mode. + */ + @Test + public void testDataMapFromProxyConfigWhenRpm() { + ProxyConfig proxyConfig = new ProxyConfig(); + + proxyConfig.setServerId(DUMMY_SERVER_ID); + proxyConfig.setProxyFqdn(DUMMY_PROXY_FQDN); + proxyConfig.setParentFqdn(DUMMY_PARENT_FQDN); + proxyConfig.setProxyPort(DUMMY_PROXY_PORT); + proxyConfig.setMaxCache(DUMMY_MAX_CACHE); + proxyConfig.setEmail(DUMMY_ADMIN_MAIL); + + // + Map dataMap = ProxyConfigUtils.dataMapFromProxyConfig(proxyConfig); + + // + assertEquals(DUMMY_SERVER_ID, dataMap.get(ProxyConfigUtils.SERVER_ID_FIELD)); + assertEquals(DUMMY_PROXY_FQDN, dataMap.get(ProxyConfigUtils.PROXY_FQDN_FIELD)); + assertEquals(DUMMY_PARENT_FQDN, dataMap.get(ProxyConfigUtils.PARENT_FQDN_FIELD)); + assertEquals(DUMMY_PROXY_PORT, dataMap.get(ProxyConfigUtils.PROXY_PORT_FIELD)); + assertEquals(DUMMY_MAX_CACHE, dataMap.get(ProxyConfigUtils.MAX_CACHE_FIELD)); + assertEquals(DUMMY_ADMIN_MAIL, dataMap.get(ProxyConfigUtils.EMAIL_FIELD)); + + assertEquals(ProxyConfigUtils.SOURCE_MODE_RPM, dataMap.get(ProxyConfigUtils.SOURCE_MODE_FIELD)); + assertNull(dataMap.get(ProxyConfigUtils.REGISTRY_MODE)); + assertNull(dataMap.get(ProxyConfigUtils.REGISTRY_BASE_URL)); + assertNull(dataMap.get(ProxyConfigUtils.REGISTRY_BASE_TAG)); + + assertNull(dataMap.get(ProxyContainerImagesEnum.PROXY_HTTPD.getUrlField())); + assertNull(dataMap.get(ProxyContainerImagesEnum.PROXY_HTTPD.getTagField())); + assertNull(dataMap.get(ProxyContainerImagesEnum.PROXY_SALT_BROKER.getUrlField())); + assertNull(dataMap.get(ProxyContainerImagesEnum.PROXY_SALT_BROKER.getTagField())); + assertNull(dataMap.get(ProxyContainerImagesEnum.PROXY_SQUID.getUrlField())); + assertNull(dataMap.get(ProxyContainerImagesEnum.PROXY_SQUID.getTagField())); + assertNull(dataMap.get(ProxyContainerImagesEnum.PROXY_SSH.getUrlField())); + assertNull(dataMap.get(ProxyContainerImagesEnum.PROXY_SSH.getTagField())); + assertNull(dataMap.get(ProxyContainerImagesEnum.PROXY_TFTPD.getUrlField())); + assertNull(dataMap.get(ProxyContainerImagesEnum.PROXY_TFTPD.getTagField())); + } + + /** + * Tests the {@link ProxyConfigUtils#dataMapFromProxyConfig} method in a scenario of using the registry in + * in simple mode. + */ + @Test + public void testDataMapFromProxyConfigWhenRegistrySimpleMode() { + final String expectedHttpdUrl = getDummyUrl(ProxyContainerImagesEnum.PROXY_HTTPD); + final String expectedSaltBrokerUrl = getDummyUrl(ProxyContainerImagesEnum.PROXY_SALT_BROKER); + final String expectedSquidUrl = getDummyUrl(ProxyContainerImagesEnum.PROXY_SQUID); + final String expectedSshUrl = getDummyUrl(ProxyContainerImagesEnum.PROXY_SSH); + final String expectedTftpdUrl = getDummyUrl(ProxyContainerImagesEnum.PROXY_TFTPD); + + // + ProxyConfig proxyConfig = new ProxyConfig(); + + proxyConfig.setServerId(DUMMY_SERVER_ID); + proxyConfig.setProxyFqdn(DUMMY_PROXY_FQDN); + proxyConfig.setParentFqdn(DUMMY_PARENT_FQDN); + proxyConfig.setProxyPort(DUMMY_PROXY_PORT); + proxyConfig.setMaxCache(DUMMY_MAX_CACHE); + proxyConfig.setEmail(DUMMY_ADMIN_MAIL); + proxyConfig.setHttpdImage(new ProxyConfigImage(expectedHttpdUrl, DUMMY_TAG)); + proxyConfig.setSaltBrokerImage(new ProxyConfigImage(expectedSaltBrokerUrl, DUMMY_TAG)); + proxyConfig.setSquidImage(new ProxyConfigImage(expectedSquidUrl, DUMMY_TAG)); + proxyConfig.setSshImage(new ProxyConfigImage(expectedSshUrl, DUMMY_TAG)); + proxyConfig.setTftpdImage(new ProxyConfigImage(expectedTftpdUrl, DUMMY_TAG)); + + // + Map dataMap = ProxyConfigUtils.dataMapFromProxyConfig(proxyConfig); + + // + assertEquals(DUMMY_SERVER_ID, dataMap.get(ProxyConfigUtils.SERVER_ID_FIELD)); + assertEquals(DUMMY_PROXY_FQDN, dataMap.get(ProxyConfigUtils.PROXY_FQDN_FIELD)); + assertEquals(DUMMY_PARENT_FQDN, dataMap.get(ProxyConfigUtils.PARENT_FQDN_FIELD)); + assertEquals(DUMMY_PROXY_PORT, dataMap.get(ProxyConfigUtils.PROXY_PORT_FIELD)); + assertEquals(DUMMY_MAX_CACHE, dataMap.get(ProxyConfigUtils.MAX_CACHE_FIELD)); + assertEquals(DUMMY_ADMIN_MAIL, dataMap.get(ProxyConfigUtils.EMAIL_FIELD)); + + assertEquals(ProxyConfigUtils.SOURCE_MODE_REGISTRY, dataMap.get(ProxyConfigUtils.SOURCE_MODE_FIELD)); + assertEquals(ProxyConfigUtils.REGISTRY_MODE_SIMPLE, dataMap.get(ProxyConfigUtils.REGISTRY_MODE)); + assertEquals(DUMMY_URL_PREFIX, dataMap.get(ProxyConfigUtils.REGISTRY_BASE_URL)); + assertEquals(DUMMY_TAG, dataMap.get(ProxyConfigUtils.REGISTRY_BASE_TAG)); + + assertNull(dataMap.get(ProxyContainerImagesEnum.PROXY_HTTPD.getUrlField())); + assertNull(dataMap.get(ProxyContainerImagesEnum.PROXY_HTTPD.getTagField())); + assertNull(dataMap.get(ProxyContainerImagesEnum.PROXY_SALT_BROKER.getUrlField())); + assertNull(dataMap.get(ProxyContainerImagesEnum.PROXY_SALT_BROKER.getTagField())); + assertNull(dataMap.get(ProxyContainerImagesEnum.PROXY_SQUID.getUrlField())); + assertNull(dataMap.get(ProxyContainerImagesEnum.PROXY_SQUID.getTagField())); + assertNull(dataMap.get(ProxyContainerImagesEnum.PROXY_SSH.getUrlField())); + assertNull(dataMap.get(ProxyContainerImagesEnum.PROXY_SSH.getTagField())); + assertNull(dataMap.get(ProxyContainerImagesEnum.PROXY_TFTPD.getUrlField())); + assertNull(dataMap.get(ProxyContainerImagesEnum.PROXY_TFTPD.getTagField())); + } + + /** + * Tests the {@link ProxyConfigUtils#dataMapFromProxyConfig} method in a scenario of using the registry in + * advanced mode. + */ + @Test + public void testDataMapFromProxyConfigWhenRegistryAdvancedMode() { + final String expectedHttpdUrl = getDummyUrl(ProxyContainerImagesEnum.PROXY_HTTPD); + final String expectedSaltBrokerUrl = getDummyUrl(ProxyContainerImagesEnum.PROXY_SALT_BROKER); + final String expectedSquidUrl = getDummyUrl(ProxyContainerImagesEnum.PROXY_SQUID); + final String expectedSshUrl = getDummyUrl(ProxyContainerImagesEnum.PROXY_SSH); + final String expectedTftpdUrl = getDummyUrl(ProxyContainerImagesEnum.PROXY_TFTPD); + + final String expectedHttpdTag = getDummyTag(ProxyContainerImagesEnum.PROXY_HTTPD); + final String expectedSaltBrokerTag = getDummyTag(ProxyContainerImagesEnum.PROXY_SALT_BROKER); + final String expectedSquidTag = getDummyTag(ProxyContainerImagesEnum.PROXY_SQUID); + final String expectedSshTag = getDummyTag(ProxyContainerImagesEnum.PROXY_SSH); + final String expectedTftpdTag = getDummyTag(ProxyContainerImagesEnum.PROXY_TFTPD); + + // + ProxyConfig proxyConfig = new ProxyConfig(); + + proxyConfig.setServerId(DUMMY_SERVER_ID); + proxyConfig.setProxyFqdn(DUMMY_PROXY_FQDN); + proxyConfig.setParentFqdn(DUMMY_PARENT_FQDN); + proxyConfig.setProxyPort(DUMMY_PROXY_PORT); + proxyConfig.setMaxCache(DUMMY_MAX_CACHE); + proxyConfig.setEmail(DUMMY_ADMIN_MAIL); + proxyConfig.setHttpdImage(new ProxyConfigImage(expectedHttpdUrl, expectedHttpdTag)); + proxyConfig.setSaltBrokerImage(new ProxyConfigImage(expectedSaltBrokerUrl, expectedSaltBrokerTag)); + proxyConfig.setSquidImage(new ProxyConfigImage(expectedSquidUrl, expectedSquidTag)); + proxyConfig.setSshImage(new ProxyConfigImage(expectedSshUrl, expectedSshTag)); + proxyConfig.setTftpdImage(new ProxyConfigImage(expectedTftpdUrl, expectedTftpdTag)); + + // + Map dataMap = ProxyConfigUtils.dataMapFromProxyConfig(proxyConfig); + + // + assertEquals(DUMMY_SERVER_ID, dataMap.get(ProxyConfigUtils.SERVER_ID_FIELD)); + assertEquals(DUMMY_PROXY_FQDN, dataMap.get(ProxyConfigUtils.PROXY_FQDN_FIELD)); + assertEquals(DUMMY_PARENT_FQDN, dataMap.get(ProxyConfigUtils.PARENT_FQDN_FIELD)); + assertEquals(DUMMY_PROXY_PORT, dataMap.get(ProxyConfigUtils.PROXY_PORT_FIELD)); + assertEquals(DUMMY_MAX_CACHE, dataMap.get(ProxyConfigUtils.MAX_CACHE_FIELD)); + assertEquals(DUMMY_ADMIN_MAIL, dataMap.get(ProxyConfigUtils.EMAIL_FIELD)); + + assertEquals(ProxyConfigUtils.SOURCE_MODE_REGISTRY, dataMap.get(ProxyConfigUtils.SOURCE_MODE_FIELD)); + assertEquals(ProxyConfigUtils.REGISTRY_MODE_ADVANCED, dataMap.get(ProxyConfigUtils.REGISTRY_MODE)); + assertNull(dataMap.get(ProxyConfigUtils.REGISTRY_BASE_URL)); + assertNull(dataMap.get(ProxyConfigUtils.REGISTRY_BASE_TAG)); + + assertEquals(expectedHttpdUrl, dataMap.get(ProxyContainerImagesEnum.PROXY_HTTPD.getUrlField())); + assertEquals(expectedHttpdTag, dataMap.get(ProxyContainerImagesEnum.PROXY_HTTPD.getTagField())); + assertEquals(expectedSaltBrokerUrl, dataMap.get(ProxyContainerImagesEnum.PROXY_SALT_BROKER.getUrlField())); + assertEquals(expectedSaltBrokerTag, dataMap.get(ProxyContainerImagesEnum.PROXY_SALT_BROKER.getTagField())); + assertEquals(expectedSquidUrl, dataMap.get(ProxyContainerImagesEnum.PROXY_SQUID.getUrlField())); + assertEquals(expectedSquidTag, dataMap.get(ProxyContainerImagesEnum.PROXY_SQUID.getTagField())); + assertEquals(expectedSshUrl, dataMap.get(ProxyContainerImagesEnum.PROXY_SSH.getUrlField())); + assertEquals(expectedSshTag, dataMap.get(ProxyContainerImagesEnum.PROXY_SSH.getTagField())); + assertEquals(expectedTftpdUrl, dataMap.get(ProxyContainerImagesEnum.PROXY_TFTPD.getUrlField())); + assertEquals(expectedTftpdTag, dataMap.get(ProxyContainerImagesEnum.PROXY_TFTPD.getTagField())); + } + + /** + * Tests the {@link ProxyConfigUtils#applyProxyConfigDataFromPillar(Pillar)} method when the pillar returns null. + */ + @Test + public void testApplyProxyConfigDataFromPillarWhenNoPillar() { + context.checking(new Expectations() {{ + allowing(mockPillar).getPillar(); + will(returnValue(null)); + }}); + + Map dataMap = ProxyConfigUtils.applyProxyConfigDataFromPillar(mockPillar); + + assertNotNull(dataMap); + assertTrue(dataMap.isEmpty()); + } + + /** + * Tests the {@link ProxyConfigUtils#applyProxyConfigDataFromPillar(Pillar)} method when the pillar returns empty + */ + @Test + public void testApplyProxyConfigDataFromPillarWhenEmptyPillar() { + context.checking(new Expectations() {{ + allowing(mockPillar).getPillar(); + will(returnValue(new HashMap<>())); + }}); + + Map dataMap = ProxyConfigUtils.applyProxyConfigDataFromPillar(mockPillar); + + assertNotNull(dataMap); + assertTrue(dataMap.isEmpty()); + } + + /** + * Tests the {@link ProxyConfigUtils#applyProxyConfigDataFromPillar(Pillar)} method when the pillar returns + * full data in scope of registry advanced mode. + */ + @Test + public void testApplyProxyConfigDataFromPillarWhenRegistryAdvancedMode() { + final String expectedHttpdUrl = getDummyUrl(ProxyContainerImagesEnum.PROXY_HTTPD); + final String expectedSaltBrokerUrl = getDummyUrl(ProxyContainerImagesEnum.PROXY_SALT_BROKER); + final String expectedSquidUrl = getDummyUrl(ProxyContainerImagesEnum.PROXY_SQUID); + final String expectedSshUrl = getDummyUrl(ProxyContainerImagesEnum.PROXY_SSH); + final String expectedTftpdUrl = getDummyUrl(ProxyContainerImagesEnum.PROXY_TFTPD); + + final String expectedHttpdTag = getDummyTag(ProxyContainerImagesEnum.PROXY_HTTPD); + final String expectedSaltBrokerTag = getDummyTag(ProxyContainerImagesEnum.PROXY_SALT_BROKER); + final String expectedSquidTag = getDummyTag(ProxyContainerImagesEnum.PROXY_SQUID); + final String expectedSshTag = getDummyTag(ProxyContainerImagesEnum.PROXY_SSH); + final String expectedTftpdTag = getDummyTag(ProxyContainerImagesEnum.PROXY_TFTPD); + + context.checking(new Expectations() {{ + allowing(mockPillar).getPillar(); + will(returnValue(createPillarMapWithRegistryAdvancedMode())); + }}); + + // + Map dataMap = ProxyConfigUtils.applyProxyConfigDataFromPillar(mockPillar); + + // + assertEquals(DUMMY_PARENT_FQDN, dataMap.get(ProxyConfigUtils.PARENT_FQDN_FIELD)); + assertEquals(DUMMY_PROXY_PORT, dataMap.get(ProxyConfigUtils.PROXY_PORT_FIELD)); + assertEquals(DUMMY_MAX_CACHE, dataMap.get(ProxyConfigUtils.MAX_CACHE_FIELD)); + assertEquals(DUMMY_ADMIN_MAIL, dataMap.get(ProxyConfigUtils.EMAIL_FIELD)); + assertEquals(DUMMY_ROOT_CA, dataMap.get(ProxyConfigUtils.ROOT_CA_FIELD)); + assertEquals( + List.of(DUMMY_INTERMEDIATE_CA_1, DUMMY_INTERMEDIATE_CA_2), + dataMap.get(ProxyConfigUtils.INTERMEDIATE_CAS_FIELD) + ); + assertEquals(DUMMY_PROXY_CERT, dataMap.get(ProxyConfigUtils.PROXY_CERT_FIELD)); + assertEquals(DUMMY_PROXY_KEY, dataMap.get(ProxyConfigUtils.PROXY_KEY_FIELD)); + + assertEquals(ProxyConfigUtils.SOURCE_MODE_REGISTRY, dataMap.get(ProxyConfigUtils.SOURCE_MODE_FIELD)); + assertEquals(ProxyConfigUtils.REGISTRY_MODE_ADVANCED, dataMap.get(ProxyConfigUtils.REGISTRY_MODE)); + + assertNull(dataMap.get(ProxyConfigUtils.REGISTRY_BASE_URL)); + assertNull(dataMap.get(ProxyConfigUtils.REGISTRY_BASE_TAG)); + + assertEquals(expectedHttpdUrl, dataMap.get(ProxyContainerImagesEnum.PROXY_HTTPD.getPillarImageVariableName())); + assertEquals(expectedHttpdTag, dataMap.get(ProxyContainerImagesEnum.PROXY_HTTPD.getPillarTagVariableName())); + + assertEquals( + expectedSaltBrokerUrl, + dataMap.get(ProxyContainerImagesEnum.PROXY_SALT_BROKER.getPillarImageVariableName()) + ); + assertEquals( + expectedSaltBrokerTag, + dataMap.get(ProxyContainerImagesEnum.PROXY_SALT_BROKER.getPillarTagVariableName()) + ); + + assertEquals(expectedSquidUrl, dataMap.get(ProxyContainerImagesEnum.PROXY_SQUID.getPillarImageVariableName())); + assertEquals(expectedSquidTag, dataMap.get(ProxyContainerImagesEnum.PROXY_SQUID.getPillarTagVariableName())); + + assertEquals(expectedSshUrl, dataMap.get(ProxyContainerImagesEnum.PROXY_SSH.getPillarImageVariableName())); + assertEquals(expectedSshTag, dataMap.get(ProxyContainerImagesEnum.PROXY_SSH.getPillarTagVariableName())); + + assertEquals(expectedTftpdUrl, dataMap.get(ProxyContainerImagesEnum.PROXY_TFTPD.getPillarImageVariableName())); + assertEquals(expectedTftpdTag, dataMap.get(ProxyContainerImagesEnum.PROXY_TFTPD.getPillarTagVariableName())); + } + + /** + * Tests the {@link ProxyConfigUtils#applyProxyConfigDataFromPillar(Pillar)} method when the pillar returns + * full data in scope of registry simple mode. + */ + @Test + public void testApplyProxyConfigDataFromPillarWhenRegistrySimpleMode() { + final String expectedHttpdUrl = getDummyUrl(ProxyContainerImagesEnum.PROXY_HTTPD); + final String expectedSaltBrokerUrl = getDummyUrl(ProxyContainerImagesEnum.PROXY_SALT_BROKER); + final String expectedSquidUrl = getDummyUrl(ProxyContainerImagesEnum.PROXY_SQUID); + final String expectedSshUrl = getDummyUrl(ProxyContainerImagesEnum.PROXY_SSH); + final String expectedTftpdUrl = getDummyUrl(ProxyContainerImagesEnum.PROXY_TFTPD); + + context.checking(new Expectations() {{ + allowing(mockPillar).getPillar(); + will(returnValue(createPillarMapWithRegistrySimpleMode())); + }}); + + // + Map dataMap = ProxyConfigUtils.applyProxyConfigDataFromPillar(mockPillar); + + // + assertEquals(DUMMY_PARENT_FQDN, dataMap.get(ProxyConfigUtils.PARENT_FQDN_FIELD)); + assertEquals(DUMMY_PROXY_PORT, dataMap.get(ProxyConfigUtils.PROXY_PORT_FIELD)); + assertEquals(DUMMY_MAX_CACHE, dataMap.get(ProxyConfigUtils.MAX_CACHE_FIELD)); + assertEquals(DUMMY_ADMIN_MAIL, dataMap.get(ProxyConfigUtils.EMAIL_FIELD)); + assertEquals(DUMMY_ROOT_CA, dataMap.get(ProxyConfigUtils.ROOT_CA_FIELD)); + assertEquals( + List.of(DUMMY_INTERMEDIATE_CA_1, DUMMY_INTERMEDIATE_CA_2), + dataMap.get(ProxyConfigUtils.INTERMEDIATE_CAS_FIELD) + ); + assertEquals(DUMMY_PROXY_CERT, dataMap.get(ProxyConfigUtils.PROXY_CERT_FIELD)); + assertEquals(DUMMY_PROXY_KEY, dataMap.get(ProxyConfigUtils.PROXY_KEY_FIELD)); + + assertEquals(ProxyConfigUtils.SOURCE_MODE_REGISTRY, dataMap.get(ProxyConfigUtils.SOURCE_MODE_FIELD)); + assertEquals(ProxyConfigUtils.REGISTRY_MODE_ADVANCED, dataMap.get(ProxyConfigUtils.REGISTRY_MODE)); + + assertNull(dataMap.get(ProxyConfigUtils.REGISTRY_BASE_URL)); + assertNull(dataMap.get(ProxyConfigUtils.REGISTRY_BASE_TAG)); + + assertEquals(expectedHttpdUrl, dataMap.get(ProxyContainerImagesEnum.PROXY_HTTPD.getPillarImageVariableName())); + assertEquals(DUMMY_TAG, dataMap.get(ProxyContainerImagesEnum.PROXY_HTTPD.getPillarTagVariableName())); + + assertEquals( + expectedSaltBrokerUrl, + dataMap.get(ProxyContainerImagesEnum.PROXY_SALT_BROKER.getPillarImageVariableName()) + ); + assertEquals(DUMMY_TAG, dataMap.get(ProxyContainerImagesEnum.PROXY_SALT_BROKER.getPillarTagVariableName())); + + assertEquals(expectedSquidUrl, dataMap.get(ProxyContainerImagesEnum.PROXY_SQUID.getPillarImageVariableName())); + assertEquals(DUMMY_TAG, dataMap.get(ProxyContainerImagesEnum.PROXY_SQUID.getPillarTagVariableName())); + + assertEquals(expectedSshUrl, dataMap.get(ProxyContainerImagesEnum.PROXY_SSH.getPillarImageVariableName())); + assertEquals(DUMMY_TAG, dataMap.get(ProxyContainerImagesEnum.PROXY_SSH.getPillarTagVariableName())); + + assertEquals(expectedTftpdUrl, dataMap.get(ProxyContainerImagesEnum.PROXY_TFTPD.getPillarImageVariableName())); + assertEquals(DUMMY_TAG, dataMap.get(ProxyContainerImagesEnum.PROXY_TFTPD.getPillarTagVariableName())); + } + + /** + * Tests the {@link ProxyConfigUtils#applyProxyConfigDataFromPillar(Pillar)} method when the pillar returns + * data in scope of RPM mode. + */ + @Test + public void testApplyProxyConfigDataFromPillarWhenRpm() { + context.checking(new Expectations() {{ + allowing(mockPillar).getPillar(); + will(returnValue(createPillarMapWithRpm())); + }}); + + // + Map dataMap = ProxyConfigUtils.applyProxyConfigDataFromPillar(mockPillar); + + // + assertEquals(DUMMY_PARENT_FQDN, dataMap.get(ProxyConfigUtils.PARENT_FQDN_FIELD)); + assertEquals(DUMMY_PROXY_PORT, dataMap.get(ProxyConfigUtils.PROXY_PORT_FIELD)); + assertEquals(DUMMY_MAX_CACHE, dataMap.get(ProxyConfigUtils.MAX_CACHE_FIELD)); + assertEquals(DUMMY_ADMIN_MAIL, dataMap.get(ProxyConfigUtils.EMAIL_FIELD)); + assertEquals(DUMMY_ROOT_CA, dataMap.get(ProxyConfigUtils.ROOT_CA_FIELD)); + assertEquals( + List.of(DUMMY_INTERMEDIATE_CA_1, DUMMY_INTERMEDIATE_CA_2), + dataMap.get(ProxyConfigUtils.INTERMEDIATE_CAS_FIELD) + ); + assertEquals(DUMMY_PROXY_CERT, dataMap.get(ProxyConfigUtils.PROXY_CERT_FIELD)); + assertEquals(DUMMY_PROXY_KEY, dataMap.get(ProxyConfigUtils.PROXY_KEY_FIELD)); + + assertEquals(ProxyConfigUtils.SOURCE_MODE_RPM, dataMap.get(ProxyConfigUtils.SOURCE_MODE_FIELD)); + + assertNull(dataMap.get(ProxyConfigUtils.REGISTRY_MODE)); + assertNull(dataMap.get(ProxyConfigUtils.REGISTRY_BASE_URL)); + assertNull(dataMap.get(ProxyConfigUtils.REGISTRY_BASE_TAG)); + + assertNull(dataMap.get(ProxyContainerImagesEnum.PROXY_HTTPD.getPillarImageVariableName())); + assertNull(dataMap.get(ProxyContainerImagesEnum.PROXY_HTTPD.getPillarTagVariableName())); + + assertNull(dataMap.get(ProxyContainerImagesEnum.PROXY_SALT_BROKER.getPillarImageVariableName())); + assertNull(dataMap.get(ProxyContainerImagesEnum.PROXY_SALT_BROKER.getPillarTagVariableName())); + + assertNull(dataMap.get(ProxyContainerImagesEnum.PROXY_SQUID.getPillarImageVariableName())); + assertNull(dataMap.get(ProxyContainerImagesEnum.PROXY_SQUID.getPillarTagVariableName())); + + assertNull(dataMap.get(ProxyContainerImagesEnum.PROXY_SSH.getPillarImageVariableName())); + assertNull(dataMap.get(ProxyContainerImagesEnum.PROXY_SSH.getPillarTagVariableName())); + + assertNull(dataMap.get(ProxyContainerImagesEnum.PROXY_TFTPD.getPillarImageVariableName())); + assertNull(dataMap.get(ProxyContainerImagesEnum.PROXY_TFTPD.getPillarTagVariableName())); + } + + + /** + * Creates a dummy pillar map with RPM data (ie without registries). + * + * @return the dummy pillar map + */ + private Map createPillarMapWithRpm() { + Map pillarMap = new HashMap<>(); + pillarMap.put(SERVER_ID_FIELD, DUMMY_SERVER_ID); + pillarMap.put(PROXY_FQDN_FIELD, DUMMY_PROXY_FQDN); + pillarMap.put(PARENT_FQDN_FIELD, DUMMY_PARENT_FQDN); + pillarMap.put(PROXY_PORT_FIELD, DUMMY_PROXY_PORT); + pillarMap.put(MAX_CACHE_FIELD, DUMMY_MAX_CACHE); + pillarMap.put(EMAIL_FIELD, DUMMY_ADMIN_MAIL); + pillarMap.put(ROOT_CA_FIELD, DUMMY_ROOT_CA); + pillarMap.put(PROXY_CERT_FIELD, DUMMY_PROXY_CERT); + pillarMap.put(PROXY_KEY_FIELD, DUMMY_PROXY_KEY); + pillarMap.put(INTERMEDIATE_CAS_FIELD, List.of(DUMMY_INTERMEDIATE_CA_1, DUMMY_INTERMEDIATE_CA_2)); + return pillarMap; + } + + /** + * Creates a dummy pillar map with registry data in advanced mode. + * + * @return the dummy pillar map + */ + private Map createPillarMapWithRegistryAdvancedMode() { + Map pillarMap = createPillarMapWithRpm(); + + Map registriesList = new HashMap<>(); + for (ProxyContainerImagesEnum image : ProxyContainerImagesEnum.values()) { + Map imageMap = new HashMap<>(); + imageMap.put(PILLAR_REGISTRY_URL_ENTRY, getDummyUrl(image)); + imageMap.put(PILLAR_REGISTRY_TAG_ENTRY, getDummyTag(image)); + registriesList.put(image.getImageName(), imageMap); + } + pillarMap.put(PILLAR_REGISTRY_ENTRY, registriesList); + return pillarMap; + } + + /** + * Creates a dummy pillar map with registry data in simple mode. + * + * @return the dummy pillar map + */ + private Map createPillarMapWithRegistrySimpleMode() { + Map pillarMap = createPillarMapWithRpm(); + + Map registriesList = new HashMap<>(); + for (ProxyContainerImagesEnum image : ProxyContainerImagesEnum.values()) { + Map imageMap = new HashMap<>(); + imageMap.put(PILLAR_REGISTRY_URL_ENTRY, DUMMY_URL_PREFIX + image.getImageName()); + imageMap.put(PILLAR_REGISTRY_TAG_ENTRY, DUMMY_TAG); + registriesList.put(image.getImageName(), imageMap); + } + pillarMap.put(PILLAR_REGISTRY_ENTRY, registriesList); + return pillarMap; + } +} + diff --git a/java/code/src/com/suse/proxy/update/ProxyConfigUpdateAcquisitor.java b/java/code/src/com/suse/proxy/update/ProxyConfigUpdateAcquisitor.java index d86db1be484e..d65edca9c8ce 100644 --- a/java/code/src/com/suse/proxy/update/ProxyConfigUpdateAcquisitor.java +++ b/java/code/src/com/suse/proxy/update/ProxyConfigUpdateAcquisitor.java @@ -30,7 +30,6 @@ import com.suse.manager.webui.utils.gson.ProxyConfigUpdateJson; import com.suse.proxy.ProxyContainerImagesEnum; import com.suse.proxy.RegistryUrl; -import com.suse.proxy.get.ProxyConfigGet; import com.suse.proxy.model.ProxyConfig; import org.apache.logging.log4j.LogManager; @@ -39,7 +38,8 @@ import java.net.URISyntaxException; /** - * Acquires additional information from the request data + * Acquires information required for updating the proxy configuration + * Might these be just used for validation purposes or actually updating the proxy configuration */ public class ProxyConfigUpdateAcquisitor implements ProxyConfigUpdateContextHandler { private static final Logger LOG = LogManager.getLogger(ProxyConfigUpdateAcquisitor.class); @@ -66,7 +66,7 @@ private void acquireProxyMinion(ProxyConfigUpdateContext context) { context.setProxyFqdn(ofNullable(minionServer.findPrimaryFqdn()) .map(ServerFQDN::getName) .orElse(minionServer.getName())); - context.setProxyConfig(new ProxyConfigGet().get(minionServer)); + context.setProxyConfig(context.getProxyConfigGetFacade().getProxyConfig(minionServer)); } }); } @@ -74,7 +74,10 @@ private void acquireProxyMinion(ProxyConfigUpdateContext context) { /** * Acquires the certificates from the request or the current proxy configuration - * + * In case the request specifies to keep the current certificates, the current proxy configuration is used. + * Two main reasons for this: + * 1) We want to keep the exact same certificates we have stored; + * 2) WebUi is getting truncated certificates data, that's also what we'll get back. * @param context the context */ private void acquireCertificates(ProxyConfigUpdateContext context) { diff --git a/java/code/src/com/suse/proxy/update/ProxyConfigUpdateApplySaltState.java b/java/code/src/com/suse/proxy/update/ProxyConfigUpdateApplySaltState.java index 464903e8ea81..f757c18753ea 100644 --- a/java/code/src/com/suse/proxy/update/ProxyConfigUpdateApplySaltState.java +++ b/java/code/src/com/suse/proxy/update/ProxyConfigUpdateApplySaltState.java @@ -71,9 +71,10 @@ else if (applySaltStateResponse.size() != 1) { } JsonObject jsonObject = jsonElement.getAsJsonObject(); for (String key : jsonObject.keySet()) { - if (!jsonObject.get(key).getAsJsonObject().get("result").getAsBoolean()) { + JsonElement jsonElementChild = jsonObject.get(key); + if (!jsonElementChild.getAsJsonObject().get("result").getAsBoolean()) { context.getErrorReport().register(FAIL_APPLY_MESSAGE); - LOG.error(FAIL_APPLY_MESSAGE + " Failing entry: {}", jsonElement); + LOG.error(FAIL_APPLY_MESSAGE + " Failing entry: {}", jsonElementChild); } } diff --git a/java/code/src/com/suse/proxy/update/ProxyConfigUpdateContext.java b/java/code/src/com/suse/proxy/update/ProxyConfigUpdateContext.java index 78e5334cc404..b2c956f8e8f2 100644 --- a/java/code/src/com/suse/proxy/update/ProxyConfigUpdateContext.java +++ b/java/code/src/com/suse/proxy/update/ProxyConfigUpdateContext.java @@ -26,6 +26,8 @@ import com.suse.manager.webui.utils.gson.ProxyConfigUpdateJson; import com.suse.proxy.ProxyContainerImagesEnum; import com.suse.proxy.RegistryUrl; +import com.suse.proxy.get.ProxyConfigGetFacade; +import com.suse.proxy.get.ProxyConfigGetFacadeImpl; import com.suse.proxy.model.ProxyConfig; import java.util.EnumMap; @@ -33,8 +35,7 @@ import java.util.Map; /** - * This class the context that is passed through the chain of responsibility pattern. - * Its main purpose is to hold the relevant data through the steps of the proxy config update process. + * This class holds relevant data through the steps of the proxy config update process. */ public class ProxyConfigUpdateContext { @@ -46,6 +47,7 @@ public class ProxyConfigUpdateContext { private final SystemManager systemManager; private final User user; private final SaltApi saltApi; + private final ProxyConfigGetFacade proxyConfigGetFacade; // Acquired/computed data private String proxyFqdn; @@ -74,11 +76,31 @@ public ProxyConfigUpdateContext( SystemManager systemManagerIn, SaltApi saltApiIn, User userIn + ) { + this(requestIn, systemManagerIn, saltApiIn, userIn, new ProxyConfigGetFacadeImpl()); + } + + /** + * Full params constructor + * + * @param requestIn the request + * @param systemManagerIn the system manager + * @param saltApiIn the salt API + * @param userIn the user + * @param proxyConfigGetFacadeIn the proxy config get facade + */ + public ProxyConfigUpdateContext( + ProxyConfigUpdateJson requestIn, + SystemManager systemManagerIn, + SaltApi saltApiIn, + User userIn, + ProxyConfigGetFacade proxyConfigGetFacadeIn ) { this.request = requestIn; this.systemManager = systemManagerIn; this.saltApi = saltApiIn; this.user = userIn; + this.proxyConfigGetFacade = proxyConfigGetFacadeIn; } public ProxyConfigUpdateJson getRequest() { @@ -89,42 +111,42 @@ public RhnErrorReport getErrorReport() { return errorReport; } - public void setProxyFqdn(String proxyFqdnIn) { - this.proxyFqdn = proxyFqdnIn; - } - public String getProxyFqdn() { return proxyFqdn; } - public Map getRegistryUrls() { - return registryUrls; + public void setProxyFqdn(String proxyFqdnIn) { + this.proxyFqdn = proxyFqdnIn; } - public void setProxyMinion(MinionServer minionServerIn) { - this.proxyMinion = minionServerIn; + public Map getRegistryUrls() { + return registryUrls; } public MinionServer getProxyMinion() { return proxyMinion; } - public void setParentServer(Server server) { - this.parentServer = server; - } - - public void setProxyConfig(ProxyConfig proxyConfigIn) { - this.proxyConfig = proxyConfigIn; + public void setProxyMinion(MinionServer minionServerIn) { + this.proxyMinion = minionServerIn; } public Server getParentServer() { return parentServer; } + public void setParentServer(Server server) { + this.parentServer = server; + } + public ProxyConfig getProxyConfig() { return proxyConfig; } + public void setProxyConfig(ProxyConfig proxyConfigIn) { + this.proxyConfig = proxyConfigIn; + } + public SystemManager getSystemManager() { return systemManager; } @@ -133,14 +155,14 @@ public User getUser() { return user; } - public void setProxyConfigFiles(Map proxyConfigFilesIn) { - this.proxyConfigFiles = proxyConfigFilesIn; - } - public Map getProxyConfigFiles() { return proxyConfigFiles; } + public void setProxyConfigFiles(Map proxyConfigFilesIn) { + this.proxyConfigFiles = proxyConfigFilesIn; + } + public String getRootCA() { return rootCA; } @@ -184,5 +206,9 @@ public void setPillar(Pillar pillarIn) { public SaltApi getSaltApi() { return saltApi; } + + public ProxyConfigGetFacade getProxyConfigGetFacade() { + return proxyConfigGetFacade; + } } diff --git a/java/code/src/com/suse/proxy/update/ProxyConfigUpdateFacade.java b/java/code/src/com/suse/proxy/update/ProxyConfigUpdateFacade.java new file mode 100644 index 000000000000..a1aa832b74b1 --- /dev/null +++ b/java/code/src/com/suse/proxy/update/ProxyConfigUpdateFacade.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2025 SUSE LLC + * + * This software is licensed to you under the GNU General Public License, + * version 2 (GPLv2). There is NO WARRANTY for this software, express or + * implied, including the implied warranties of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 + * along with this software; if not, see + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * Red Hat trademarks are not licensed under GPLv2. No permission is + * granted to use or replicate Red Hat trademarks that are incorporated + * in this software or its documentation. + */ + +package com.suse.proxy.update; + +import com.redhat.rhn.domain.user.User; +import com.redhat.rhn.manager.system.SystemManager; + +import com.suse.manager.webui.services.iface.SaltApi; +import com.suse.manager.webui.utils.gson.ProxyConfigUpdateJson; + +public interface ProxyConfigUpdateFacade { + /** + * Update a proxy configuration to a proxy minion. + * @param request the proxy configuration update JSON with the new values + * @param systemManager the system manager + * @param saltApi the salt API + * @param user the user + */ + void update(ProxyConfigUpdateJson request, SystemManager systemManager, SaltApi saltApi, User user); +} diff --git a/java/code/src/com/suse/proxy/update/ProxyConfigUpdate.java b/java/code/src/com/suse/proxy/update/ProxyConfigUpdateFacadeImpl.java similarity index 95% rename from java/code/src/com/suse/proxy/update/ProxyConfigUpdate.java rename to java/code/src/com/suse/proxy/update/ProxyConfigUpdateFacadeImpl.java index 4482afdf3f1f..70ec6eba2217 100644 --- a/java/code/src/com/suse/proxy/update/ProxyConfigUpdate.java +++ b/java/code/src/com/suse/proxy/update/ProxyConfigUpdateFacadeImpl.java @@ -33,13 +33,13 @@ * These steps have a specific order and are executed in sequence. * If an error occurs in any of these steps, the process halts and the errors are be reported. */ -public class ProxyConfigUpdate { +public class ProxyConfigUpdateFacadeImpl implements ProxyConfigUpdateFacade { private final List contextHandlerChain = new ArrayList<>(); /** * Constructor */ - public ProxyConfigUpdate() { + public ProxyConfigUpdateFacadeImpl() { this.contextHandlerChain.addAll(asList( new ProxyConfigUpdateAcquisitor(), new ProxyConfigUpdateValidation(), @@ -58,6 +58,7 @@ public ProxyConfigUpdate() { * @param saltApi the salt API * @param user the user */ + @Override public void update(ProxyConfigUpdateJson request, SystemManager systemManager, SaltApi saltApi, User user) { ProxyConfigUpdateContext context = new ProxyConfigUpdateContext(request, systemManager, saltApi, user); diff --git a/java/code/src/com/suse/proxy/update/ProxyConfigUpdateFileAcquisitor.java b/java/code/src/com/suse/proxy/update/ProxyConfigUpdateFileAcquisitor.java index 091e82a08bfe..6483a4ae48ee 100644 --- a/java/code/src/com/suse/proxy/update/ProxyConfigUpdateFileAcquisitor.java +++ b/java/code/src/com/suse/proxy/update/ProxyConfigUpdateFileAcquisitor.java @@ -105,7 +105,5 @@ null, null, null, new SSLCertManager()) LOG.error("Failed to create proxy container configuration", e); context.getErrorReport().register("Failed to create proxy container configuration"); } - } - } diff --git a/java/code/src/com/suse/proxy/update/ProxyConfigUpdateRegistryPreConditions.java b/java/code/src/com/suse/proxy/update/ProxyConfigUpdateRegistryPreConditions.java index e9e9338aea6c..1697ee108420 100644 --- a/java/code/src/com/suse/proxy/update/ProxyConfigUpdateRegistryPreConditions.java +++ b/java/code/src/com/suse/proxy/update/ProxyConfigUpdateRegistryPreConditions.java @@ -70,7 +70,8 @@ public void handle(ProxyConfigUpdateContext context) { registryUtils.getTags(context.getRegistryUrls().get(proxyImage)); } catch (ParseException parseException) { - LOG.error("Failed to get tags for: {} {}", proxyImage.getImageName(), context.getRegistryUrls().get(proxyImage)); + LOG.error("Failed to get tags for: {} {}", + proxyImage.getImageName(), context.getRegistryUrls().get(proxyImage)); context.getErrorReport().register( "Failed to get tags for: " + proxyImage.getImageName() ); diff --git a/java/code/src/com/suse/rest/RestRequest.java b/java/code/src/com/suse/rest/RestRequest.java index 5dac55cf3a51..09a657ead539 100644 --- a/java/code/src/com/suse/rest/RestRequest.java +++ b/java/code/src/com/suse/rest/RestRequest.java @@ -17,6 +17,9 @@ import java.util.Map; +/** + * Class to represent a generic REST request. + */ public class RestRequest { private final RestRequestMethodEnum method; diff --git a/java/code/src/com/suse/rest/RestRequestAuthEnum.java b/java/code/src/com/suse/rest/RestRequestAuthEnum.java index 61828df8e02e..ca16f0e79375 100644 --- a/java/code/src/com/suse/rest/RestRequestAuthEnum.java +++ b/java/code/src/com/suse/rest/RestRequestAuthEnum.java @@ -16,7 +16,7 @@ package com.suse.rest; /** - * Enum to represent the type of authentication required for a request. + * Enum to represent the types of authentication required for a request. */ public enum RestRequestAuthEnum { NONE, diff --git a/java/code/src/com/suse/rest/RestRequestBuilder.java b/java/code/src/com/suse/rest/RestRequestBuilder.java index 74f519be426a..85337431d889 100644 --- a/java/code/src/com/suse/rest/RestRequestBuilder.java +++ b/java/code/src/com/suse/rest/RestRequestBuilder.java @@ -21,7 +21,7 @@ import java.util.Map; /** - * Class to build and execute a request. + * Builder for Rest request. */ @SuppressWarnings("checkstyle:VisibilityModifier") public class RestRequestBuilder { diff --git a/java/code/src/com/suse/rest/RestResponse.java b/java/code/src/com/suse/rest/RestResponse.java index 2b9f1cd030de..6277b9b6a18f 100644 --- a/java/code/src/com/suse/rest/RestResponse.java +++ b/java/code/src/com/suse/rest/RestResponse.java @@ -24,7 +24,7 @@ import java.util.Map; /** - * Class to represent a response from a request. + * Class to represent a response from a Rest request. */ public class RestResponse { private final int statusCode; diff --git a/java/code/webapp/WEB-INF/nav/system_detail.xml b/java/code/webapp/WEB-INF/nav/system_detail.xml index bbd09d80ef2a..49351e618866 100644 --- a/java/code/webapp/WEB-INF/nav/system_detail.xml +++ b/java/code/webapp/WEB-INF/nav/system_detail.xml @@ -10,8 +10,11 @@ /rhn/systems/details/SystemRemoteCommand.do - - + + /rhn/manager/systems/details/proxy-config + + + @@ -213,11 +216,6 @@ /rhn/manager/systems/details/formulas - - /rhn/manager/systems/details/proxy-config - - - /rhn/manager/systems/details/ansible/control-node diff --git a/schema/spacewalk/common/data/rhnServerServerGroupArchCompat.sql b/schema/spacewalk/common/data/rhnServerServerGroupArchCompat.sql index 8ad69c29cdb3..d57d124aaf96 100644 --- a/schema/spacewalk/common/data/rhnServerServerGroupArchCompat.sql +++ b/schema/spacewalk/common/data/rhnServerServerGroupArchCompat.sql @@ -939,26 +939,168 @@ insert into rhnServerServerGroupArchCompat ( server_arch_id, server_group_type ) lookup_sg_type('peripheral_server')); -- proxy_entitled compatibilities -DO $$ -DECLARE - loop_server_arch_id INT; - proxy_sg_type_id INT; -BEGIN - proxy_sg_type_id := lookup_sg_type('proxy_entitled'); - - FOR loop_server_arch_id IN - SELECT id FROM rhnserverarch - LOOP - INSERT INTO rhnServerServerGroupArchCompat (server_arch_id, server_group_type) - SELECT - loop_server_arch_id, - proxy_sg_type_id - WHERE NOT EXISTS ( - SELECT 1 - FROM rhnServerServerGroupArchCompat AS rs - WHERE rs.server_arch_id = loop_server_arch_id AND rs.server_group_type = proxy_sg_type_id - ); - END LOOP; -END $$; - +insert into rhnServerServerGroupArchCompat ( server_arch_id, server_group_type ) + values (lookup_server_arch('i386-redhat-linux'), + lookup_sg_type('proxy_entitled')); + +insert into rhnServerServerGroupArchCompat ( server_arch_id, server_group_type ) + values (lookup_server_arch('i386-debian-linux'), + lookup_sg_type('proxy_entitled')); + +insert into rhnServerServerGroupArchCompat ( server_arch_id, server_group_type ) + values (lookup_server_arch('i486-redhat-linux'), + lookup_sg_type('proxy_entitled')); + +insert into rhnServerServerGroupArchCompat ( server_arch_id, server_group_type ) + values (lookup_server_arch('i586-redhat-linux'), + lookup_sg_type('proxy_entitled')); + +insert into rhnServerServerGroupArchCompat ( server_arch_id, server_group_type ) + values (lookup_server_arch('i686-redhat-linux'), + lookup_sg_type('proxy_entitled')); + +insert into rhnServerServerGroupArchCompat ( server_arch_id, server_group_type ) + values (lookup_server_arch('athlon-redhat-linux'), + lookup_sg_type('proxy_entitled')); + +insert into rhnServerServerGroupArchCompat ( server_arch_id, server_group_type ) + values (lookup_server_arch('alpha-redhat-linux'), + lookup_sg_type('proxy_entitled')); + +insert into rhnServerServerGroupArchCompat ( server_arch_id, server_group_type ) + values (lookup_server_arch('alpha-debian-linux'), + lookup_sg_type('proxy_entitled')); + +insert into rhnServerServerGroupArchCompat ( server_arch_id, server_group_type ) + values (lookup_server_arch('alphaev6-redhat-linux'), + lookup_sg_type('proxy_entitled')); + +insert into rhnServerServerGroupArchCompat ( server_arch_id, server_group_type ) + values (lookup_server_arch('ia64-redhat-linux'), + lookup_sg_type('proxy_entitled')); + +insert into rhnServerServerGroupArchCompat ( server_arch_id, server_group_type ) + values (lookup_server_arch('ia64-debian-linux'), + lookup_sg_type('proxy_entitled')); + +insert into rhnServerServerGroupArchCompat ( server_arch_id, server_group_type ) + values (lookup_server_arch('sparc-redhat-linux'), + lookup_sg_type('proxy_entitled')); + +insert into rhnServerServerGroupArchCompat ( server_arch_id, server_group_type ) + values (lookup_server_arch('sparc-debian-linux'), + lookup_sg_type('proxy_entitled')); + +insert into rhnServerServerGroupArchCompat ( server_arch_id, server_group_type ) + values (lookup_server_arch('sparcv9-redhat-linux'), + lookup_sg_type('proxy_entitled')); + +insert into rhnServerServerGroupArchCompat ( server_arch_id, server_group_type ) + values (lookup_server_arch('sparc64-redhat-linux'), + lookup_sg_type('proxy_entitled')); + +insert into rhnServerServerGroupArchCompat ( server_arch_id, server_group_type ) + values (lookup_server_arch('s390-redhat-linux'), + lookup_sg_type('proxy_entitled')); + +insert into rhnServerServerGroupArchCompat ( server_arch_id, server_group_type ) + values (lookup_server_arch('s390-debian-linux'), + lookup_sg_type('proxy_entitled')); + +insert into rhnServerServerGroupArchCompat ( server_arch_id, server_group_type ) + values (lookup_server_arch('s390x-redhat-linux'), + lookup_sg_type('proxy_entitled')); + +insert into rhnServerServerGroupArchCompat ( server_arch_id, server_group_type ) + values (lookup_server_arch('ppc-redhat-linux'), + lookup_sg_type('proxy_entitled')) + ; +insert into rhnServerServerGroupArchCompat ( server_arch_id, server_group_type ) + values (lookup_server_arch('aarch64-redhat-linux'), + lookup_sg_type('proxy_entitled')); + +insert into rhnServerServerGroupArchCompat ( server_arch_id, server_group_type ) + values (lookup_server_arch('armv7l-redhat-linux'), + lookup_sg_type('proxy_entitled')); + +insert into rhnServerServerGroupArchCompat ( server_arch_id, server_group_type ) + values (lookup_server_arch('armv5tejl-redhat-linux'), + lookup_sg_type('proxy_entitled')); + +insert into rhnServerServerGroupArchCompat ( server_arch_id, server_group_type ) + values (lookup_server_arch('armv6l-redhat-linux'), + lookup_sg_type('proxy_entitled')); + +insert into rhnServerServerGroupArchCompat ( server_arch_id, server_group_type ) + values (lookup_server_arch('armv6hl-redhat-linux'), + lookup_sg_type('proxy_entitled')); + +insert into rhnServerServerGroupArchCompat ( server_arch_id, server_group_type ) + values (lookup_server_arch('powerpc-debian-linux'), + lookup_sg_type('proxy_entitled')); + +insert into rhnServerServerGroupArchCompat ( server_arch_id, server_group_type ) + values (lookup_server_arch('ppc64-redhat-linux'), + lookup_sg_type('proxy_entitled')); + +insert into rhnServerServerGroupArchCompat ( server_arch_id, server_group_type ) + values (lookup_server_arch('ppc64le-redhat-linux'), + lookup_sg_type('proxy_entitled')); + +insert into rhnServerServerGroupArchCompat ( server_arch_id, server_group_type ) + values (lookup_server_arch('pSeries-redhat-linux'), + lookup_sg_type('proxy_entitled')); + +insert into rhnServerServerGroupArchCompat ( server_arch_id, server_group_type ) + values (lookup_server_arch('iSeries-redhat-linux'), + lookup_sg_type('proxy_entitled')); + +insert into rhnServerServerGroupArchCompat ( server_arch_id, server_group_type ) + values (lookup_server_arch('x86_64-redhat-linux'), + lookup_sg_type('proxy_entitled')); + +insert into rhnServerServerGroupArchCompat ( server_arch_id, server_group_type ) + values (lookup_server_arch('ppc64iseries-redhat-linux'), + lookup_sg_type('proxy_entitled')); + +insert into rhnServerServerGroupArchCompat ( server_arch_id, server_group_type ) + values (lookup_server_arch('ppc64pseries-redhat-linux'), + lookup_sg_type('proxy_entitled')); + +insert into rhnServerServerGroupArchCompat ( server_arch_id, server_group_type ) + values (lookup_server_arch('ia32e-redhat-linux'), + lookup_sg_type('proxy_entitled')); + +insert into rhnServerServerGroupArchCompat ( server_arch_id, server_group_type ) + values (lookup_server_arch('amd64-redhat-linux'), + lookup_sg_type('proxy_entitled')); + +insert into rhnServerServerGroupArchCompat ( server_arch_id, server_group_type ) + values (lookup_server_arch('amd64-debian-linux'), + lookup_sg_type('proxy_entitled')); + +insert into rhnServerServerGroupArchCompat ( server_arch_id, server_group_type ) + values (lookup_server_arch('arm-debian-linux'), + lookup_sg_type('proxy_entitled')) + ; +insert into rhnServerServerGroupArchCompat ( server_arch_id, server_group_type ) + values (lookup_server_arch('armv6l-debian-linux'), + lookup_sg_type('proxy_entitled')); + +insert into rhnServerServerGroupArchCompat ( server_arch_id, server_group_type ) + values (lookup_server_arch('mips-debian-linux'), + lookup_sg_type('proxy_entitled')); + +insert into rhnServerServerGroupArchCompat ( server_arch_id, server_group_type ) + values (lookup_server_arch('armv7l-debian-linux'), + lookup_sg_type('proxy_entitled')); + +insert into rhnServerServerGroupArchCompat ( server_arch_id, server_group_type ) + values (lookup_server_arch('cloud'), + lookup_sg_type('proxy_entitled + l_server')); +insert into rhnServerServerGroupArchCompat ( server_arch_id, server_group_type ) + values (lookup_server_arch('arm64-debian-linux'), + lookup_sg_type('proxy_entitled')); + commit; diff --git a/schema/spacewalk/postgres/packages/rhn_entitlements.pkb b/schema/spacewalk/postgres/packages/rhn_entitlements.pkb index 5fb7741c6fa0..6418d4791413 100644 --- a/schema/spacewalk/postgres/packages/rhn_entitlements.pkb +++ b/schema/spacewalk/postgres/packages/rhn_entitlements.pkb @@ -1,5 +1,6 @@ -- oracle equivalent source sha1 0690aebc316b2ea8195ae4804ec450d5d301057c -- +-- Copyright (c) 2016--2025 SUSE LLC -- Copyright (c) 2008--2015 Red Hat, Inc. -- -- This software is licensed to you under the GNU General Public License, @@ -238,6 +239,7 @@ as $$ when 'monitoring_entitled' then 'Monitoring' when 'ansible_control_node' then 'Ansible' when 'peripheral_server' then 'Peripheral' + when 'proxy_entitled' then 'Proxy' end ); perform rhn_server.insert_into_servergroup (server_id_in, sgid); diff --git a/schema/spacewalk/upgrade/susemanager-schema-5.1.2-to-susemanager-schema-5.1.3/012-create_new_org.sql b/schema/spacewalk/upgrade/susemanager-schema-5.1.2-to-susemanager-schema-5.1.3/012-create_new_org.sql new file mode 100644 index 000000000000..7c0f1c97e457 --- /dev/null +++ b/schema/spacewalk/upgrade/susemanager-schema-5.1.2-to-susemanager-schema-5.1.3/012-create_new_org.sql @@ -0,0 +1,261 @@ +-- +-- Copyright (c) 2013--2025 SUSE LLC +-- Copyright (c) 2008--2012 Red Hat, Inc. +-- +-- This software is licensed to you under the GNU General Public License, +-- version 2 (GPLv2). There is NO WARRANTY for this software, express or +-- implied, including the implied warranties of MERCHANTABILITY or FITNESS +-- FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 +-- along with this software; if not, see +-- http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. +-- +-- Red Hat trademarks are not licensed under GPLv2. No permission is +-- granted to use or replicate Red Hat trademarks that are incorporated +-- in this software or its documentation. +-- + +create or replace function create_new_org +( + name_in in varchar, + password_in in varchar + --org_id_out out number +) returns numeric +as +$$ +declare + ug_type numeric; + group_val numeric; + new_org_id numeric; + org_id_out numeric; +begin + + select nextval('web_customer_id_seq') into new_org_id from dual; + + insert into web_customer ( + id, name + ) values ( + new_org_id, name_in + ); + + select nextval('rhn_user_group_id_seq') into group_val from dual; + + select id + into ug_type + from rhnUserGroupType + where label = 'org_admin'; + + insert into rhnUserGroup ( + id, name, + description, + max_members, group_type, org_id + ) values ( + group_val, 'Organization Administrators', + 'Organization Administrators for Org ' || name_in, + NULL, ug_type, new_org_id + ); + + select nextval('rhn_user_group_id_seq') into group_val from dual; + + select id + into ug_type + from rhnUserGroupType + where label = 'system_group_admin'; + + insert into rhnUserGroup ( + id, name, + description, + max_members, group_type, org_id + ) values ( + group_val, 'System Group Administrators', + 'System Group Administrators for Org ' || name_in, + NULL, ug_type, new_org_id + ); + + + select nextval('rhn_user_group_id_seq') into group_val from dual; + + select id + into ug_type + from rhnUserGroupType + where label = 'activation_key_admin'; + + insert into rhnUserGroup ( + id, name, + description, + max_members, group_type, org_id + ) values ( + group_val, 'Activation Key Administrators', + 'Activation Key Administrators for Org ' || name_in, + NULL, ug_type, new_org_id + ); + + select nextval('rhn_user_group_id_seq') into group_val from dual; + + select id + into ug_type + from rhnUserGroupType + where label = 'channel_admin'; + + insert into rhnUserGroup ( + id, name, + description, + max_members, group_type, org_id + ) values ( + group_val, 'Channel Administrators', + 'Channel Administrators for Org ' || name_in, + NULL, ug_type, new_org_id + ); + + if new_org_id = 1 then + select nextval('rhn_user_group_id_seq') into group_val from dual; + + select id + into ug_type + from rhnUserGroupType + where label = 'satellite_admin'; + + insert into rhnUserGroup ( + id, name, + description, + max_members, group_type, org_id + ) values ( + group_val, 'SUSE Manager Administrators', + 'SUSE Manager Administrators for Org ' || name_in, + NULL, ug_type, new_org_id + ); + end if; + + select nextval('rhn_user_group_id_seq') into group_val from dual; + + select id + into ug_type + from rhnUserGroupType + where label = 'config_admin'; + + insert into rhnUserGroup ( + id, name, + description, + max_members, group_type, org_id + ) values ( + group_val, 'Configuration Administrators', + 'Configuration Administrators for Org ' || name_in, + NULL, ug_type, new_org_id + ); + + select nextval('rhn_user_group_id_seq') into group_val from dual; + + select id + into ug_type + from rhnUserGroupType + where label = 'image_admin'; + + insert into rhnUserGroup ( + id, name, + description, + max_members, group_type, org_id + ) values ( + group_val, 'Image Administrators', + 'Image Administrators for Org ' || name_in, + NULL, ug_type, new_org_id + ); + + select nextval('rhn_user_group_id_seq') into group_val from dual; + + -- there aren't any users yet, so we don't need to update + -- rhnUserServerPerms + + insert into rhnServerGroup + ( id, name, description, group_type, org_id ) + select nextval('rhn_server_group_id_seq'), sgt.name, sgt.name, + sgt.id, new_org_id + from rhnServerGroupType sgt + where sgt.label = 'bootstrap_entitled'; + + insert into rhnServerGroup + ( id, name, description, group_type, org_id ) + select nextval('rhn_server_group_id_seq'), sgt.name, sgt.name, + sgt.id, new_org_id + from rhnServerGroupType sgt + where sgt.label = 'enterprise_entitled'; + + insert into rhnServerGroup + ( id, name, description, group_type, org_id ) + select nextval('rhn_server_group_id_seq'), sgt.name, sgt.name, + sgt.id, new_org_id + from rhnServerGroupType sgt + where sgt.label = 'salt_entitled'; + + insert into rhnServerGroup + ( id, name, description, group_type, org_id ) + select nextval('rhn_server_group_id_seq'), sgt.name, sgt.name, + sgt.id, new_org_id + from rhnServerGroupType sgt + where sgt.label = 'foreign_entitled'; + + insert into rhnServerGroup + ( id, name, description, group_type, org_id ) + select nextval('rhn_server_group_id_seq'), sgt.name, sgt.name, + sgt.id, new_org_id + from rhnServerGroupType sgt + where sgt.label = 'virtualization_host'; + + insert into rhnServerGroup + ( id, name, description, group_type, org_id ) + select nextval('rhn_server_group_id_seq'), sgt.name, sgt.name, + sgt.id, new_org_id + from rhnServerGroupType sgt + where sgt.label = 'container_build_host'; + + insert into rhnServerGroup + ( id, name, description, group_type, org_id ) + select nextval('rhn_server_group_id_seq'), sgt.name, sgt.name, + sgt.id, new_org_id + from rhnServerGroupType sgt + where sgt.label = 'osimage_build_host'; + + insert into rhnServerGroup + ( id, name, description, group_type, org_id ) + select nextval('rhn_server_group_id_seq'), sgt.name, sgt.name, + sgt.id, new_org_id + from rhnServerGroupType sgt + where sgt.label = 'monitoring_entitled'; + + insert into rhnServerGroup + ( id, name, description, group_type, org_id ) + select nextval('rhn_server_group_id_seq'), sgt.name, sgt.name, + sgt.id, new_org_id + from rhnServerGroupType sgt + where sgt.label = 'ansible_control_node'; + + insert into rhnServerGroup + ( id, name, description, group_type, org_id ) + select nextval('rhn_server_group_id_seq'), sgt.name, sgt.name, + sgt.id, new_org_id + from rhnServerGroupType sgt + where sgt.label = 'peripheral_server'; + + + insert into rhnServerGroup + ( id, name, description, group_type, org_id ) + select nextval('rhn_server_group_id_seq'), sgt.name, sgt.name, + sgt.id, new_org_id + from rhnServerGroupType sgt + where sgt.label = 'proxy_entitled'; + + insert into suseImageStore (id, label, uri, store_type_id, org_id) + values ( + nextval('suse_imgstore_id_seq'), + 'SUSE Manager OS Image Store', + new_org_id || '/', + (SELECT id FROM suseImageStoreType WHERE label = 'os_image'), + new_org_id + ); + + org_id_out := new_org_id; + + -- Returning the value of OUT parameter + return org_id_out; + +end; +$$ +language plpgsql; diff --git a/susemanager-utils/susemanager-sls/salt/apply_proxy_config.sls b/susemanager-utils/susemanager-sls/salt/proxy/apply_proxy_config.sls similarity index 59% rename from susemanager-utils/susemanager-sls/salt/apply_proxy_config.sls rename to susemanager-utils/susemanager-sls/salt/proxy/apply_proxy_config.sls index 44395a037bbc..710ccd7358de 100644 --- a/susemanager-utils/susemanager-sls/salt/apply_proxy_config.sls +++ b/susemanager-utils/susemanager-sls/salt/proxy/apply_proxy_config.sls @@ -3,12 +3,9 @@ {%- set mgrpxy_operation = 'install' if not mgrpxy_installed or 'Error: no installed proxy detected' in mgrpxy_status_output else 'upgrade' %} {%- set transactional = grains['transactional'] %} -podman_installed_running: +podman_installed: pkg.installed: - name: podman - service.running: - - name: podman - - enable: True mgrpxy_installed: pkg.installed: @@ -66,13 +63,30 @@ mgrpxy_installed: {{ pillar['ssh']['server_ssh_push_pub'] | replace('\\n', '\n') | indent(12) }} +{% set args = [] %} +{% if pillar['httpd_image'] is defined and pillar['httpd_tag'] is defined %} + {% do args.append("--httpd-image " ~ pillar['httpd_image'] ~ " --httpd-tag " ~ pillar['httpd_tag']) %} +{% endif %} +{% if pillar['saltbroker_image'] is defined and pillar['saltbroker_tag'] is defined %} + {% do args.append("--saltbroker-image " ~ pillar['saltbroker_image'] ~ " --saltbroker-tag " ~ pillar['saltbroker_tag']) %} +{% endif %} +{% if pillar['squid_image'] is defined and pillar['squid_tag'] is defined %} + {% do args.append("--squid-image " ~ pillar['squid_image'] ~ " --squid-tag " ~ pillar['squid_tag']) %} +{% endif %} +{% if pillar['ssh_image'] is defined and pillar['ssh_tag'] is defined %} + {% do args.append("--ssh-image " ~ pillar['ssh_image'] ~ " --ssh-tag " ~ pillar['ssh_tag']) %} +{% endif %} +{% if pillar['tftpd_image'] is defined and pillar['tftpd_tag'] is defined %} + {% do args.append("--tftpd-image " ~ pillar['tftpd_image'] ~ " --tftpd-tag " ~ pillar['tftpd_tag']) %} +{% endif %} + {% if transactional %} # If we're on a transactional system, we'll install mgrpxy apply as a service that # executes the mgrpxy install/update command after next reboot -/etc/systemd/system/apply_mgrpxy.service: +/etc/systemd/system/apply_proxy_config.service: file.managed: - - name: /etc/systemd/system/apply_mgrpxy.service + - name: /etc/systemd/system/apply_proxy_config.service - user: root - group: root - mode: 664 @@ -86,19 +100,13 @@ mgrpxy_installed: [Service] Type=oneshot - ExecStart=/bin/bash -c 'mgrpxy {{ mgrpxy_operation }} podman --logLevel debug \ - {% if pillar['httpd_image'] is defined and pillar['httpd_tag'] is defined %}--httpd-image {{ pillar['httpd_image'] }} --httpd-tag {{ pillar['httpd_tag'] }} {% endif %} \ - {% if pillar['saltbroker_image'] is defined and pillar['saltbroker_tag'] is defined %}--saltbroker-image {{ pillar['saltbroker_image'] }} --saltbroker-tag {{ pillar['saltbroker_tag'] }} {% endif %} \ - {% if pillar['squid_image'] is defined and pillar['squid_tag'] is defined %}--squid-image {{ pillar['squid_image'] }} --squid-tag {{ pillar['squid_tag'] }} {% endif %} \ - {% if pillar['ssh_image'] is defined and pillar['ssh_tag'] is defined %}--ssh-image {{ pillar['ssh_image'] }} --ssh-tag {{ pillar['ssh_tag'] }} {% endif %} \ - {% if pillar['tftpd_image'] is defined and pillar['tftpd_tag'] is defined %}--tftpd-image {{ pillar['tftpd_image'] }} --tftpd-tag {{ pillar['tftpd_tag'] }} {% endif %} \ - 2>&1 | tee -a /var/log/mgrpxy_install.log' - + ExecStart=/bin/bash -c 'mgrpxy {{ mgrpxy_operation }} podman --logLevel debug {{ args | join(" ") }} 2>&1 | tee -a /var/log/mgrpxy_install.log' + ExecStartPost=/bin/bash -c 'STATUS_OUTPUT=$(mgrpxy status 2>&1); \ echo "$STATUS_OUTPUT" | tee -a /var/log/mgrpxy_install.log; \ if ! echo "$STATUS_OUTPUT" | grep -q "Error: no installed proxy detected"; then \ echo "mgrpxy was successfully {{ mgrpxy_operation }}ed. Removing apply mgrpxy service and configuration file." | tee -a /var/log/mgrpxy_install.log; \ - rm -f /etc/systemd/system/apply_mgrpxy.service; \ + rm -f /etc/systemd/system/apply_proxy_config.service; \ else \ echo "mgrpxy status check failed. Service file will remain for troubleshooting." | tee -a /var/log/mgrpxy_install.log; \ fi' @@ -106,13 +114,13 @@ mgrpxy_installed: [Install] WantedBy=multi-user.target -# The system will run this service to enable apply_mgrpxy.service after reboot -enable_apply_mgrpxy_service: +# The system will run this service to enable apply_proxy_config.service after reboot +enable_apply_proxy_config_service: service.running: - - name: apply_mgrpxy.service + - name: apply_proxy_config.service - enable: True - require: - - file: /etc/systemd/system/apply_mgrpxy.service + - file: /etc/systemd/system/apply_proxy_config.service - file: /etc/uyuni/proxy/config.yaml - file: /etc/uyuni/proxy/httpd.yaml - file: /etc/uyuni/proxy/ssh.yaml @@ -123,19 +131,14 @@ enable_apply_mgrpxy_service: apply_proxy_configuration: cmd.run: - name: > - mgrpxy {{ mgrpxy_operation }} podman --logLevel debug \ - {% if pillar['httpd_image'] is defined and pillar['httpd_tag'] is defined %} --httpd-image {{ pillar['httpd_image'] }} --httpd-tag {{ pillar['httpd_tag'] }} {% endif %} \ - {% if pillar['saltbroker_image'] is defined and pillar['saltbroker_tag'] is defined %} --saltbroker-image {{ pillar['saltbroker_image'] }} --saltbroker-tag {{ pillar['saltbroker_tag'] }} {% endif %} \ - {% if pillar['squid_image'] is defined and pillar['squid_tag'] is defined %} --squid-image {{ pillar['squid_image'] }} --squid-tag {{ pillar['squid_tag'] }} {% endif %} \ - {% if pillar['ssh_image'] is defined and pillar['ssh_tag'] is defined %} --ssh-image {{ pillar['ssh_image'] }} --ssh-tag {{ pillar['ssh_tag'] }} {% endif %} \ - {% if pillar['tftpd_image'] is defined and pillar['tftpd_tag'] is defined %} --tftpd-image {{ pillar['tftpd_image'] }} --tftpd-tag {{ pillar['tftpd_tag'] }} {% endif %} \ - > 2>&1 | tee -a /var/log/mgrpxy_install.log + mgrpxy {{ mgrpxy_operation }} podman --logLevel debug {{ args | join(" ") }} + 2>&1 | tee -a /var/log/mgrpxy_install.log - shell: /bin/bash - require: - file: /etc/uyuni/proxy/config.yaml - file: /etc/uyuni/proxy/httpd.yaml - file: /etc/uyuni/proxy/ssh.yaml - - service: podman_installed_running + - pkg: podman_installed - pkg: mgrpxy_installed {%- endif %} diff --git a/web/html/src/manager/minion/proxy/proxy-config.tsx b/web/html/src/manager/minion/proxy/proxy-config.tsx index 328c4ed84f6f..6372a8f4157e 100644 --- a/web/html/src/manager/minion/proxy/proxy-config.tsx +++ b/web/html/src/manager/minion/proxy/proxy-config.tsx @@ -10,7 +10,7 @@ import { FormMultiInput } from "components/input/form-multi-input/FormMultiInput import { unflattenModel } from "components/input/form-utils"; import { Radio } from "components/input/radio/Radio"; import { Text } from "components/input/text/Text"; -import { Panel } from "components/panels/Panel"; +import { Messages } from "components/messages/messages"; import { TopPanel } from "components/panels/TopPanel"; import Validation from "components/validation"; @@ -36,13 +36,9 @@ enum RegistryMode { type ProxyConfigModel = { rootCA: string; - rootCA_safe?: string; proxyCertificate: string; - proxyCertificate_safe?: string; proxyKey: string; - proxyKey_safe?: string; intermediateCAs?: string[]; - intermediateCAs_safe?: string[]; proxyAdminEmail: string; maxSquidCacheSize: string; parentFQDN: string; @@ -130,7 +126,13 @@ const tagMapping = { registryTftpdURL: "registryTftpdTag", }; -export function ProxyConfig({ serverId, isUyuni, parents, currentConfig, initFailMessage }: ProxyConfigProps) { +export function ProxyConfig({ + serverId, + isUyuni, + parents, + currentConfig, + initFailMessage, +}: Readonly) { const [messages, setMessages] = useState([]); const [loading, setLoading] = useState(false); const [success, setSuccess] = useState(); @@ -138,8 +140,7 @@ export function ProxyConfig({ serverId, isUyuni, parents, currentConfig, initFai const [errors, setErrors] = useState({}); const [tagOptions, setTagOptions] = useState({}); - const showUseCertsMode = - currentConfig.rootCA_safe || currentConfig.proxyKey_safe || currentConfig.proxyCertificate_safe; + const hasExistingConfig = currentConfig !== undefined && Object.keys(currentConfig).length > 0; const originalConfig = { ...currentConfig }; const [model, setModel] = useState(() => { @@ -148,13 +149,6 @@ export function ProxyConfig({ serverId, isUyuni, parents, currentConfig, initFai ...currentConfig, }; - if (showUseCertsMode) { - return { - ...initialModel, - useCertsMode: UseCertsMode.Keep, - }; - } - return initialModel; }); @@ -162,6 +156,8 @@ export function ProxyConfig({ serverId, isUyuni, parents, currentConfig, initFai if (currentConfig.sourceMode === SourceMode.RPM) { //work-around to trigger validation for filled forms using RPM retrieveRegistryTags(currentConfig, null); + } else if (currentConfig.registryBaseURL) { + retrieveRegistryTags(currentConfig, "registryBaseURL"); } else { imageNames.forEach((url) => { if (currentConfig[url]) { @@ -302,7 +298,9 @@ export function ProxyConfig({ serverId, isUyuni, parents, currentConfig, initFai const restoreRegistryInputs = () => { setModel({ ...model, - registryMode: RegistryMode.Advanced, + registryMode: originalConfig.registryMode, + registryBaseURL: originalConfig.registryBaseURL, + registryBaseTag: originalConfig.registryBaseTag, registryHttpdURL: originalConfig.registryHttpdURL, registryHttpdTag: originalConfig.registryHttpdTag, registrySaltbrokerURL: originalConfig.registrySaltbrokerURL, @@ -322,16 +320,12 @@ export function ProxyConfig({ serverId, isUyuni, parents, currentConfig, initFai } }; - const onChangeRegistryeMode = (e, v) => { - if (RegistryMode.Advanced === v && Object.keys(originalConfig).length > 0) { + const onChangeRegistryMode = (e, v) => { + if (originalConfig.registryMode === v && Object.keys(originalConfig).length > 0) { restoreRegistryInputs(); } }; - const getMinionNames = (data: any[] = []) => { - return Array.from(new Set(data.map((item) => item.name))).sort(); - }; - const useDebounce = (callback: (...args: any) => any, timeoutMs: number) => useCallback(debounce(callback, timeoutMs), []); @@ -413,7 +407,7 @@ export function ProxyConfig({ serverId, isUyuni, parents, currentConfig, initFai placeholder={t("e.g., server.domain.com")} labelClass="col-md-3" divClass="col-md-6" - options={getMinionNames(parents)} + options={parents} isClearable={true} />


- {showUseCertsMode && ( + {hasExistingConfig && ( 0 && model.useCertsMode === UseCertsMode.Keep && ( <> - - - {(currentConfig.intermediateCAs_safe || []).map((ca, index) => ( - - ))} - - - +
+ +
)} {(currentConfig === undefined || model.useCertsMode === UseCertsMode.Replace) && ( @@ -602,7 +560,7 @@ export function ProxyConfig({ serverId, isUyuni, parents, currentConfig, initFai { label: t("Simple"), value: RegistryMode.Simple }, { label: t("Advanced"), value: RegistryMode.Advanced }, ]} - onChange={onChangeRegistryeMode} + onChange={onChangeRegistryMode} /> {model.registryMode === RegistryMode.Simple && ( <>