Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ISSv3 - UI skeleton and Hub details page #9830

Merged
merged 9 commits into from
Feb 24, 2025
24 changes: 24 additions & 0 deletions java/code/src/com/redhat/rhn/common/security/acl/Access.java
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/*
* Copyright (c) 2025 SUSE LLC
* Copyright (c) 2009--2015 Red Hat, Inc.
*
* This software is licensed to you under the GNU General Public License,
Expand Down Expand Up @@ -43,6 +44,7 @@
import com.redhat.rhn.manager.system.SystemManager;
import com.redhat.rhn.manager.user.UserManager;

import com.suse.manager.model.hub.HubFactory;
import com.suse.manager.webui.controllers.utils.ContactMethodUtil;
import com.suse.manager.webui.utils.ViewHelper;

Expand Down Expand Up @@ -676,4 +678,26 @@ public boolean aclSystemHasModularChannels(Map<String, Object> ctx, String[] par

return server.getChannels().stream().anyMatch(Channel::isModular);
}

/**
* Checks if this server is a hub
* @param ctx the acl context
* @param params the parameters for the acl
* @return true if this server has peripheral registered
*/
public boolean aclIsHub(Map<String, Object> ctx, String[] params) {
HubFactory factory = new HubFactory();
return factory.isISSHub();
}

/**
* Checks if this server is a peripheral
* @param ctx the acl context
* @param params the parameters for the acl
* @return true if this server is registered as a peripheral on a hub
*/
public boolean aclIsPeripheral(Map<String, Object> ctx, String[] params) {
HubFactory factory = new HubFactory();
return factory.isISSPeripheral();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7784,6 +7784,9 @@ Follow this url to see the full list of inactive systems:
<trans-unit id="api.iss.duplicateslave" xml:space="preserve">
<source>A record for Slave @@PRODUCT_NAME@@ {0} already exists</source>
</trans-unit>
<trans-unit id="api.iss.serverinvocationexception" xml:space="preserve">
<source>Unable to invoke the remote server {0}</source>
</trans-unit>
<trans-unit id="securityErrata" xml:space="preserve">
<source>Security Patches</source>
</trans-unit>
Expand Down Expand Up @@ -9160,6 +9163,12 @@ Alternatively, you will want to download &lt;strong&gt;Incremental Channel Conte
<trans-unit id="hub.unable_to_store_token" xml:space="preserve">
<source>Unable to store the token. Please check the server logs.</source>
</trans-unit>
<trans-unit id="hub.cannot_find_server" xml:space="preserve">
<source>Cannot find a remote server with the specified id.</source>
</trans-unit>
<trans-unit id="hub.unable_to_deregister" xml:space="preserve">
<source>Unable to deregister: an unexpected error is occurred while contacting the remote server. Please check the server logs.</source>
</trans-unit>
<trans-unit id="cveaudit.nav.title" xml:space="preserve">
<source>CVE Audit</source>
</trans-unit>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,30 @@
<context context-type="sourcefile">Navigation Menu</context>
</context-group>
</trans-unit>
<trans-unit id="Hub Configuration" xml:space="preserve">
<source>Hub Configuration</source>
<context-group name="ctx">
<context context-type="sourcefile">Navigation Menu</context>
</context-group>
</trans-unit>
<trans-unit id="Hub Details" xml:space="preserve">
<source>Hub Details</source>
<context-group name="ctx">
<context context-type="sourcefile">Navigation Menu</context>
</context-group>
</trans-unit>
<trans-unit id="Peripherals Configuration" xml:space="preserve">
<source>Peripherals Configuration</source>
<context-group name="ctx">
<context context-type="sourcefile">Navigation Menu</context>
</context-group>
</trans-unit>
<trans-unit id="Access Tokens" xml:space="preserve">
<source>Access Tokens</source>
<context-group name="ctx">
<context context-type="sourcefile">Navigation Menu</context>
</context-group>
</trans-unit>
<trans-unit id="Remote Command" xml:space="preserve">
<source>Remote Command</source>
<context-group name="ctx">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright (c) 2025 SUSE LLC
* Copyright (c) 2013 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.
*/
package com.redhat.rhn.frontend.xmlrpc;

import com.redhat.rhn.FaultException;
import com.redhat.rhn.common.localization.LocalizationService;

/**
* ISS Slave we're trying to create already exists
*
*/
public class ServerInvocationException extends FaultException {

private static final long serialVersionUID = -736057155929214695L;

/**
* Tried to create a slave when one already exists w/a given name
* @param fqdn the fqdn of the problematic server
*/
public ServerInvocationException(String fqdn) {
super(3002, "serverInvocationException", LocalizationService.getInstance().
getMessage("api.iss.serverinvocationexception", fqdn));
}

/**
* Tried to create a slave when one already exists w/a given name
* @param fqdn the fqdn of the problematic server
* @param cause what caused this exception
*/
public ServerInvocationException(String fqdn, Throwable cause) {
super(3002, "serverInvocationException", LocalizationService.getInstance().
getMessage("api.iss.serverinvocationexception", fqdn), cause);


}
}
80 changes: 71 additions & 9 deletions java/code/src/com/suse/manager/hub/HubManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,19 @@ public IssServer findServer(User user, String serverFqdn, IssRole role) {
return lookupServerByFqdnAndRole(serverFqdn, role);
}

/**
* Returns the ISS of the specified role, if present
* @param user the user performing the operation
* @param id the id of the server
* @param role the role of the server
* @return an {@link IssHub} or {@link IssPeripheral} depending on the specified role, null if the FQDN is unknown
*/
public IssServer findServer(User user, long id, IssRole role) {
ensureSatAdmin(user);

return lookupServerByIdAndRole(id, role);
}

/**
* Save the given remote server as hub or peripheral depending on the specified role
* @param accessToken the access token granting access and identifying the caller
Expand All @@ -222,17 +235,30 @@ public IssServer saveNewServer(IssAccessToken accessToken, IssRole role, String
}

/**
* Delete locally all ISS artifacts for the hub or peripheral server identified by the FQDN
* Deregister the server with the given FQDN. The de-registration can be optionally performed also on the
* remote server.
* @param user the user
* @param fqdn the FQDN
* @param onlyLocal specify if the de-registration has to be performed also on the remote server
* @throws CertificateException when it's not possible to use remote server certificate
* @throws IOException when the connection with the remote server fails
*/
public void deleteIssServerLocal(User user, String fqdn) {
public void deregister(User user, String fqdn, boolean onlyLocal) throws CertificateException, IOException {
ensureSatAdmin(user);
if (hubFactory.isISSPeripheral()) {
deleteHub(fqdn);

IssRole remoteRole = hubFactory.isISSPeripheral() ? IssRole.HUB : IssRole.PERIPHERAL;
IssServer server = findServer(user, fqdn, remoteRole);

if (!onlyLocal) {
IssAccessToken accessToken = hubFactory.lookupAccessTokenFor(server.getFqdn());
var internalClient = clientFactory.newInternalClient(fqdn, accessToken.getToken(), server.getRootCa());
internalClient.deregister();
}
else {
deletePeripheral(fqdn);

switch (remoteRole) {
case HUB -> deleteHub(fqdn);
case PERIPHERAL -> deletePeripheral(fqdn);
default -> throw new IllegalStateException("Role should either be HUB or PERIPHERAL");
}
}

Expand All @@ -257,10 +283,15 @@ private void deletePeripheral(String peripheralFqdn) {
LOG.info("Peripheral Server with name {} not found", peripheralFqdn);
return; // no error as the state is already as wanted.
}

IssPeripheral peripheral = issPeripheral.get();
deletePeripheral(peripheral);
}

private void deletePeripheral(IssPeripheral peripheral) {
CredentialsFactory.removeCredentials(peripheral.getMirrorCredentials());
hubFactory.remove(peripheral);
hubFactory.removeAccessTokensFor(peripheralFqdn);
hubFactory.removeAccessTokensFor(peripheral.getFqdn());
}

private void deleteHub(String hubFqdn) {
Expand All @@ -270,9 +301,13 @@ private void deleteHub(String hubFqdn) {
return; // no error as the state is already as wanted.
}
IssHub hub = issHub.get();
deleteHub(hub);
}

private void deleteHub(IssHub hub) {
CredentialsFactory.removeCredentials(hub.getMirrorCredentials());
hubFactory.remove(hub);
hubFactory.removeAccessTokensFor(hubFqdn);
hubFactory.removeAccessTokensFor(hub.getFqdn());
}

/**
Expand Down Expand Up @@ -737,6 +772,13 @@ private IssServer lookupServerByFqdnAndRole(String serverFqdn, IssRole role) {
};
}

private IssServer lookupServerByIdAndRole(long id, IssRole role) {
return switch (role) {
case HUB -> hubFactory.findHubById(id);
case PERIPHERAL -> hubFactory.findPeripheralById(id);
};
}

private IssServer createServer(IssRole role, String serverFqdn, String rootCA, String gpgKey, User user)
throws TaskomaticApiException {
taskomaticApi.scheduleSingleRootCaCertUpdate(computeRootCaFileName(role, serverFqdn), rootCA);
Expand Down Expand Up @@ -872,6 +914,27 @@ public List<Channel> collectAllChannels(IssAccessToken accessToken) {
return ChannelFactory.listAllChannels();
}

/**
* Count the registered peripherals on "this" hub
* @param user the SatAdmin
* @return the count of registered peripherals entities
*/
public Long countRegisteredPeripherals(User user) {
ensureSatAdmin(user);
return hubFactory.countPeripherals();
}

/**
* List the peripherals with pagination //TODO: and search
* @param user the SatAdmin
* @param pc the PageControl
* @return a List of Peripherals entities
*/
public List<IssPeripheral> listRegisteredPeripherals(User user, PageControl pc) {
ensureSatAdmin(user);
return hubFactory.listPaginatedPeripherals(pc.getStart() - 1, pc.getPageSize());
}

/**
* add vendor channel to peripheral
*
Expand Down Expand Up @@ -933,7 +996,6 @@ public List<Channel> addVendorChannels(IssAccessToken accessToken, List<String>
.toList();
}


/**
* add custom channels to peripheral
*
Expand Down
53 changes: 47 additions & 6 deletions java/code/src/com/suse/manager/hub/test/HubManagerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -589,10 +589,30 @@ public void canStoreSCCCredentials() throws TaskomaticApiException {
}

@Test
public void canDeregisterHub() throws TokenBuildingException, TaskomaticApiException, TokenParsingException {
public void canDeregisterHub() throws Exception {
String fqdn = LOCAL_SERVER_FQDN;
createHubRegistration(fqdn, null, null);
hubManager.deleteIssServerLocal(satAdmin, fqdn);
IssAccessToken token = createHubRegistration(fqdn, null, null);
HubInternalClient internalClient = mock(HubInternalClient.class);

context().checking(new Expectations() {{
allowing(clientFactoryMock).newInternalClient(fqdn, token.getToken(), null);
will(returnValue(internalClient));

allowing(internalClient).deregister();
}});

hubManager.deregister(satAdmin, fqdn, false);

assertNull(hubFactory.lookupAccessTokenFor(fqdn));
assertNull(hubFactory.lookupIssuedToken(fqdn));
assertTrue(hubFactory.lookupIssHub().isEmpty(), "Failed to remove Hub");
assertEquals(0, CredentialsFactory.listSCCCredentials().size());
}

@Test
public void canDeregisterHubLocalOnly() throws Exception {
String fqdn = LOCAL_SERVER_FQDN;
hubManager.deregister(satAdmin, fqdn, true);

assertNull(hubFactory.lookupAccessTokenFor(fqdn));
assertNull(hubFactory.lookupIssuedToken(fqdn));
Expand All @@ -601,10 +621,31 @@ public void canDeregisterHub() throws TokenBuildingException, TaskomaticApiExcep
}

@Test
public void canDeregisterPeripheral() throws TokenBuildingException, TaskomaticApiException, TokenParsingException {
public void canDeregisterPeripheral() throws Exception {
String fqdn = LOCAL_SERVER_FQDN;
createPeripheralRegistration(fqdn, null);
hubManager.deleteIssServerLocal(satAdmin, fqdn);
IssAccessToken token = createPeripheralRegistration(fqdn, null);
HubInternalClient internalClient = mock(HubInternalClient.class);

context().checking(new Expectations() {{
allowing(clientFactoryMock).newInternalClient(fqdn, token.getToken(), null);
will(returnValue(internalClient));

allowing(internalClient).deregister();
}});

hubManager.deregister(satAdmin, fqdn, false);

assertNull(hubFactory.lookupAccessTokenFor(fqdn));
assertNull(hubFactory.lookupIssuedToken(fqdn));
assertTrue(hubFactory.lookupIssPeripheralByFqdn(fqdn).isEmpty(), "Failed to remove Peripheral");
assertEquals(0, CredentialsFactory.listCredentialsByType(HubSCCCredentials.class).size());
}

@Test
public void canDeregisterPeripheralLocalOnly() throws Exception {
String fqdn = LOCAL_SERVER_FQDN;

hubManager.deregister(satAdmin, fqdn, true);

assertNull(hubFactory.lookupAccessTokenFor(fqdn));
assertNull(hubFactory.lookupIssuedToken(fqdn));
Expand Down
Loading
Loading