This is an automated email from the ASF dual-hosted git repository. yasith pushed a commit to branch feat/airavata-service-layer in repository https://gitbox.apache.org/repos/asf/airavata.git
commit e355a731c004f727ee5b3b0b49a45319e8b0bc45 Author: yasithdev <[email protected]> AuthorDate: Thu Mar 26 12:51:36 2026 -0500 feat: add SSHAccountService for SSH account management Extracted doesUserHaveSSHAccount, isSSHSetupCompleteForUserComputeResourcePreference, and setupUserComputeResourcePreferencesForSSH from AiravataServerHandler into a dedicated SSHAccountService. Handler methods are now ThriftAdapter one-liners. Includes 6 unit tests covering all methods and error paths. --- .../airavata/service/ssh/SSHAccountService.java | 81 ++++++++++++++ .../service/ssh/SSHAccountServiceTest.java | 121 +++++++++++++++++++++ 2 files changed, 202 insertions(+) diff --git a/airavata-api/src/main/java/org/apache/airavata/service/ssh/SSHAccountService.java b/airavata-api/src/main/java/org/apache/airavata/service/ssh/SSHAccountService.java new file mode 100644 index 0000000000..8deafaa5b0 --- /dev/null +++ b/airavata-api/src/main/java/org/apache/airavata/service/ssh/SSHAccountService.java @@ -0,0 +1,81 @@ +package org.apache.airavata.service.ssh; + +import org.apache.airavata.accountprovisioning.SSHAccountManager; +import org.apache.airavata.credential.store.server.CredentialStoreServerHandler; +import org.apache.airavata.model.appcatalog.userresourceprofile.UserComputeResourcePreference; +import org.apache.airavata.model.credential.store.SSHCredential; +import org.apache.airavata.service.context.RequestContext; +import org.apache.airavata.service.exception.ServiceException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class SSHAccountService { + + private static final Logger logger = LoggerFactory.getLogger(SSHAccountService.class); + + private final CredentialStoreServerHandler credentialHandler; + + public SSHAccountService(CredentialStoreServerHandler credentialHandler) { + this.credentialHandler = credentialHandler; + } + + public boolean doesUserHaveSSHAccount(RequestContext ctx, String computeResourceId, String userId) + throws ServiceException { + String gatewayId = ctx.getGatewayId(); + try { + return SSHAccountManager.doesUserHaveSSHAccount(gatewayId, computeResourceId, userId); + } catch (Exception e) { + String msg = "Error occurred while checking if [" + userId + "] has an SSH Account on [" + + computeResourceId + "]."; + logger.error(msg, e); + throw new ServiceException(msg + " More info: " + e.getMessage(), e); + } + } + + public boolean isSSHSetupCompleteForUserComputeResourcePreference( + RequestContext ctx, String computeResourceId, String airavataCredStoreToken) + throws ServiceException { + String gatewayId = ctx.getGatewayId(); + String userId = ctx.getUserId(); + + SSHCredential sshCredential; + try { + sshCredential = credentialHandler.getSSHCredential(airavataCredStoreToken, gatewayId); + } catch (Exception e) { + String msg = "Error occurred while retrieving SSH Credential."; + logger.error(msg, e); + throw new ServiceException(msg + " More info: " + e.getMessage(), e); + } + + try { + return SSHAccountManager.isSSHAccountSetupComplete(gatewayId, computeResourceId, userId, sshCredential); + } catch (Exception e) { + String msg = "Error occurred while checking if setup of SSH account is complete for user [" + userId + "]."; + logger.error(msg, e); + throw new ServiceException(msg + " More info: " + e.getMessage(), e); + } + } + + public UserComputeResourcePreference setupUserComputeResourcePreferencesForSSH( + RequestContext ctx, String computeResourceId, String userId, String airavataCredStoreToken) + throws ServiceException { + String gatewayId = ctx.getGatewayId(); + + SSHCredential sshCredential; + try { + sshCredential = credentialHandler.getSSHCredential(airavataCredStoreToken, gatewayId); + } catch (Exception e) { + String msg = "Error occurred while retrieving SSH Credential."; + logger.error(msg, e); + throw new ServiceException(msg + " More info: " + e.getMessage(), e); + } + + try { + return SSHAccountManager.setupSSHAccount(gatewayId, computeResourceId, userId, sshCredential); + } catch (Exception e) { + String msg = "Error occurred while automatically setting up SSH account for user [" + userId + "]."; + logger.error(msg, e); + throw new ServiceException(msg + " More info: " + e.getMessage(), e); + } + } +} diff --git a/airavata-api/src/test/java/org/apache/airavata/service/ssh/SSHAccountServiceTest.java b/airavata-api/src/test/java/org/apache/airavata/service/ssh/SSHAccountServiceTest.java new file mode 100644 index 0000000000..bdeab25a00 --- /dev/null +++ b/airavata-api/src/test/java/org/apache/airavata/service/ssh/SSHAccountServiceTest.java @@ -0,0 +1,121 @@ +package org.apache.airavata.service.ssh; + +import org.apache.airavata.credential.store.server.CredentialStoreServerHandler; +import org.apache.airavata.model.credential.store.SSHCredential; +import org.apache.airavata.service.context.RequestContext; +import org.apache.airavata.service.exception.ServiceException; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.junit.jupiter.MockitoExtension; + +import org.apache.airavata.accountprovisioning.SSHAccountManager; +import org.apache.airavata.model.appcatalog.userresourceprofile.UserComputeResourcePreference; + +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class SSHAccountServiceTest { + + @Mock CredentialStoreServerHandler credentialHandler; + + SSHAccountService sshAccountService; + RequestContext ctx; + + @BeforeEach + void setUp() { + sshAccountService = new SSHAccountService(credentialHandler); + ctx = new RequestContext("testUser", "testGateway", "token123", + Map.of("userName", "testUser", "gatewayId", "testGateway")); + } + + @Test + void doesUserHaveSSHAccount_delegatesToSSHAccountManager() throws Exception { + try (MockedStatic<SSHAccountManager> mock = mockStatic(SSHAccountManager.class)) { + mock.when(() -> SSHAccountManager.doesUserHaveSSHAccount("testGateway", "cr-001", "testUser")) + .thenReturn(true); + + boolean result = sshAccountService.doesUserHaveSSHAccount(ctx, "cr-001", "testUser"); + + assertTrue(result); + mock.verify(() -> SSHAccountManager.doesUserHaveSSHAccount("testGateway", "cr-001", "testUser")); + } + } + + @Test + void doesUserHaveSSHAccount_wrapsException() { + try (MockedStatic<SSHAccountManager> mock = mockStatic(SSHAccountManager.class)) { + mock.when(() -> SSHAccountManager.doesUserHaveSSHAccount(any(), any(), any())) + .thenThrow(new RuntimeException("connection failed")); + + assertThrows(ServiceException.class, + () -> sshAccountService.doesUserHaveSSHAccount(ctx, "cr-001", "testUser")); + } + } + + @Test + void isSSHSetupComplete_fetchesCredentialAndDelegates() throws Exception { + SSHCredential cred = new SSHCredential(); + when(credentialHandler.getSSHCredential("tok-123", "testGateway")).thenReturn(cred); + + try (MockedStatic<SSHAccountManager> mock = mockStatic(SSHAccountManager.class)) { + mock.when(() -> SSHAccountManager.isSSHAccountSetupComplete("testGateway", "cr-001", "testUser", cred)) + .thenReturn(false); + + boolean result = sshAccountService.isSSHSetupCompleteForUserComputeResourcePreference( + ctx, "cr-001", "tok-123"); + + assertFalse(result); + verify(credentialHandler).getSSHCredential("tok-123", "testGateway"); + } + } + + @Test + void isSSHSetupComplete_wrapsCredentialException() throws Exception { + when(credentialHandler.getSSHCredential(any(), any())).thenThrow(new RuntimeException("store error")); + + assertThrows(ServiceException.class, + () -> sshAccountService.isSSHSetupCompleteForUserComputeResourcePreference(ctx, "cr-001", "tok-bad")); + } + + @Test + void setupSSHAccount_fetchesCredentialAndDelegates() throws Exception { + SSHCredential cred = new SSHCredential(); + when(credentialHandler.getSSHCredential("tok-123", "testGateway")).thenReturn(cred); + + UserComputeResourcePreference pref = new UserComputeResourcePreference(); + pref.setComputeResourceId("cr-001"); + + try (MockedStatic<SSHAccountManager> mock = mockStatic(SSHAccountManager.class)) { + mock.when(() -> SSHAccountManager.setupSSHAccount("testGateway", "cr-001", "testUser", cred)) + .thenReturn(pref); + + UserComputeResourcePreference result = sshAccountService.setupUserComputeResourcePreferencesForSSH( + ctx, "cr-001", "testUser", "tok-123"); + + assertNotNull(result); + assertEquals("cr-001", result.getComputeResourceId()); + verify(credentialHandler).getSSHCredential("tok-123", "testGateway"); + } + } + + @Test + void setupSSHAccount_wrapsSSHAccountManagerException() throws Exception { + SSHCredential cred = new SSHCredential(); + when(credentialHandler.getSSHCredential("tok-123", "testGateway")).thenReturn(cred); + + try (MockedStatic<SSHAccountManager> mock = mockStatic(SSHAccountManager.class)) { + mock.when(() -> SSHAccountManager.setupSSHAccount(any(), any(), any(), any())) + .thenThrow(new RuntimeException("setup failed")); + + assertThrows(ServiceException.class, + () -> sshAccountService.setupUserComputeResourcePreferencesForSSH( + ctx, "cr-001", "testUser", "tok-123")); + } + } +}
