diff --git a/CHANGELOG.MD b/CHANGELOG.MD index bde79e9..06dda63 100644 --- a/CHANGELOG.MD +++ b/CHANGELOG.MD @@ -11,6 +11,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [JHP-103]: Check for xdat_user table before creating JupyterHub user account. +### Changed: + +- [JHP-112]: The path translation settings have always been applied to both Docker Swarm and Kubernetes deployments. + Updated the plugin settings labels and descriptions to reflect this. + ## [1.2.0] - 2024-06-27 ### Added @@ -85,4 +90,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [JHP-89]: https://radiologics.atlassian.net/jira/software/c/projects/JHP/issues/JHP-89 [JHP-91]: https://radiologics.atlassian.net/jira/software/c/projects/JHP/issues/JHP-91 [JHP-92]: https://radiologics.atlassian.net/jira/software/c/projects/JHP/issues/JHP-92 -[JHP-103]: https://radiologics.atlassian.net/jira/software/c/projects/JHP/issues/JHP-103 \ No newline at end of file +[JHP-103]: https://radiologics.atlassian.net/jira/software/c/projects/JHP/issues/JHP-103 +[JHP-112]: https://radiologics.atlassian.net/jira/software/c/projects/JHP/issues/JHP-112 \ No newline at end of file diff --git a/src/main/java/org/nrg/xnatx/plugins/jupyterhub/initialize/JupyterHubPreferenceInitializer.java b/src/main/java/org/nrg/xnatx/plugins/jupyterhub/initialize/JupyterHubPreferenceInitializer.java index b69b4f5..c9a3b53 100644 --- a/src/main/java/org/nrg/xnatx/plugins/jupyterhub/initialize/JupyterHubPreferenceInitializer.java +++ b/src/main/java/org/nrg/xnatx/plugins/jupyterhub/initialize/JupyterHubPreferenceInitializer.java @@ -65,8 +65,10 @@ protected void callImpl() throws InitializingTaskException { initializeStopTimeoutFromEnv(); initializePathTranslationArchivePrefixFromEnv(); initializePathTranslationArchiveDockerPrefixFromEnv(); + initializePathTranslationArchiveServerPrefixFromEnv(); // Overwrites DOCKER env var if set initializePathTranslationWorkspacePrefixFromEnv(); initializePathTranslationWorkspaceDockerPrefixFromEnv(); + initializePathTranslationWorkspaceServerPrefixFromEnv(); // Overwrites DOCKER env var if set initializeWorkspacePathFromEnv(); initializeInactivityTimeoutFromEnv(); initializeMaxServerLifetimeFromEnv(); @@ -196,6 +198,20 @@ protected void initializePathTranslationArchiveDockerPrefixFromEnv() { } } + /** + * Initialize the JupyterHub path translation archive docker prefix preference from the JH_XNAT_PT_ARCHIVE_SERVER_PREFIX environment variable. + */ + protected void initializePathTranslationArchiveServerPrefixFromEnv() { + String jupyterHubPathTranslationArchiveServerPrefixEnv = systemHelper.getEnv("JH_XNAT_PT_ARCHIVE_SERVER_PREFIX"); + + if (StringUtils.isNotBlank(jupyterHubPathTranslationArchiveServerPrefixEnv)) { + jupyterHubPreferences.setPathTranslationArchiveDockerPrefix(jupyterHubPathTranslationArchiveServerPrefixEnv); + log.info("JupyterHub Path Translation Archive Server Prefix preference initialized from environment variable to: " + jupyterHubPathTranslationArchiveServerPrefixEnv); + } else { + log.debug("JupyterHub Path Translation Archive Server Prefix environment variable not set. Skipping initialization."); + } + } + /** * Initialize the JupyterHub path translation workspace prefix preference from the JH_XNAT_PT_WORKSPACE_PREFIX environment variable. */ @@ -224,6 +240,20 @@ protected void initializePathTranslationWorkspaceDockerPrefixFromEnv() { } } + /** + * Initialize the JupyterHub path translation workspace server prefix preference from the JH_XNAT_PT_WORKSPACE_SERVER_PREFIX environment variable. + */ + protected void initializePathTranslationWorkspaceServerPrefixFromEnv() { + String jupyterHubPathTranslationWorkspaceServerPrefixEnv = systemHelper.getEnv("JH_XNAT_PT_WORKSPACE_SERVER_PREFIX"); + + if (StringUtils.isNotBlank(jupyterHubPathTranslationWorkspaceServerPrefixEnv)) { + jupyterHubPreferences.setPathTranslationWorkspaceDockerPrefix(jupyterHubPathTranslationWorkspaceServerPrefixEnv); + log.info("JupyterHub Path Translation Workspace Server Prefix preference initialized from environment variable to: " + jupyterHubPathTranslationWorkspaceServerPrefixEnv); + } else { + log.debug("JupyterHub Path Translation Workspace Server Prefix environment variable not set. Skipping initialization."); + } + } + /** * Initialize the JupyterHub workspace path preference from the JH_XNAT_WORKSPACE_PATH environment variable. */ diff --git a/src/main/resources/META-INF/resources/scripts/xnat/plugin/jupyterhub/jupyterhub-hub.js b/src/main/resources/META-INF/resources/scripts/xnat/plugin/jupyterhub/jupyterhub-hub.js index e7c351c..e7ae7d7 100644 --- a/src/main/resources/META-INF/resources/scripts/xnat/plugin/jupyterhub/jupyterhub-hub.js +++ b/src/main/resources/META-INF/resources/scripts/xnat/plugin/jupyterhub/jupyterhub-hub.js @@ -100,7 +100,7 @@ XNAT.plugin.jupyterhub.hub = getObject(XNAT.plugin.jupyterhub.hub || {}); content: spawn('div#jupyterhub-setup-form'), maxBtn: true, footer: false, - width: 800, + width: 900, beforeShow: function(obj) { console.log(obj) let serverFormContainerEl = document.getElementById(`jupyterhub-setup-form`); @@ -124,6 +124,10 @@ XNAT.plugin.jupyterhub.hub = getObject(XNAT.plugin.jupyterhub.hub || {}); revertButton.addEventListener("click", () => { XNAT.ui.dialog.closeAll(); }); + + // Hide panel header + const panelHeader = formContainerEl.querySelector('.panel-heading'); + panelHeader.style.display = 'none'; }) }, buttons: [] diff --git a/src/main/resources/META-INF/xnat/spawner/jupyterhub/site-settings.yaml b/src/main/resources/META-INF/xnat/spawner/jupyterhub/site-settings.yaml index 3d2b177..780cdbc 100644 --- a/src/main/resources/META-INF/xnat/spawner/jupyterhub/site-settings.yaml +++ b/src/main/resources/META-INF/xnat/spawner/jupyterhub/site-settings.yaml @@ -101,37 +101,45 @@ stopPollingInterval: description: > The rate (in seconds) at which to poll JupyterHub to check if the single-user server has stopped. +userLimitsAndTimeoutsSubhead: + kind: panel.subhead + text: User Limits and Timeouts + +pathTranslationSubhead: + kind: panel.subhead + text: Path Translation (Optional) + pathTranslationArchivePrefix: kind: panel.input.text id: pathTranslationArchivePrefix name: pathTranslationArchivePrefix - label: Path Translation XNAT Archive Prefix + label: XNAT Archive Path Prefix description: > - (Optional) Enter the XNAT archive path as seen by XNAT, i.e. "/data/xnat/archive" + Enter the XNAT archive path as seen by XNAT, i.e. "/data/xnat/archive" pathTranslationArchiveDockerPrefix: kind: panel.input.text id: pathTranslationArchiveDockerPrefix name: pathTranslationArchiveDockerPrefix - label: Path Translation Docker Archive Prefix + label: Server Archive Path Prefix description: > - (Optional) Enter the Docker Server path to the XNAT archive mount, i.e. "/docker/my-data/XNAT/archive" + Enter the server path to the XNAT archive mount, i.e. "/docker/my-data/XNAT/archive" pathTranslationWorkspacePrefix: kind: panel.input.text id: pathTranslationWorkspacePrefix name: pathTranslationWorkspacePrefix - label: Path Translation User Workspace Prefix + label: XNAT User Workspaces Path Prefix description: > - (Optional) Enter the user workspace path as seen by XNAT, i.e. "/data/xnat/workspaces" + Enter the user workspaces path as seen by XNAT, i.e. "/data/xnat/workspaces" pathTranslationWorkspaceDockerPrefix: kind: panel.input.text id: pathTranslationWorkspaceDockerPrefix name: pathTranslationWorkspaceDockerPrefix - label: Path Translation Docker User Workspace Prefix + label: Server User Workspaces Path Prefix description: > - (Optional) Enter the Docker Server path to the user workspace mount, i.e. "/docker/my-data/XNAT/workspaces" + Enter the server path to the user workspaces mount, i.e. "/docker/my-data/XNAT/workspaces" inactivityTimeout: kind: panel.input.number @@ -292,12 +300,14 @@ jupyterhubPreferences: ${jupyterHubHostUrl} ${jupyterhubApiUrl} ${jupyterHubToken} - ${startTimeout} - ${stopTimeout} - ${inactivityTimeout} + ${workspacePath} + ${userLimitsAndTimeoutsSubhead} ${maxServerLifetime} ${maxNamedServers} - ${workspacePath} + ${inactivityTimeout} + ${startTimeout} + ${stopTimeout} + ${pathTranslationSubhead} ${pathTranslationArchivePrefix} ${pathTranslationArchiveDockerPrefix} ${pathTranslationWorkspacePrefix} diff --git a/src/test/java/org/nrg/xnatx/plugins/jupyterhub/initialize/JupyterHubPreferenceInitializerTest.java b/src/test/java/org/nrg/xnatx/plugins/jupyterhub/initialize/JupyterHubPreferenceInitializerTest.java index 028bbb0..391970e 100644 --- a/src/test/java/org/nrg/xnatx/plugins/jupyterhub/initialize/JupyterHubPreferenceInitializerTest.java +++ b/src/test/java/org/nrg/xnatx/plugins/jupyterhub/initialize/JupyterHubPreferenceInitializerTest.java @@ -131,8 +131,10 @@ public void callImpl_initialized_envSet() throws Exception { when(mockSystemHelper.getEnv("JH_XNAT_STOP_TIMEOUT")).thenReturn("60"); when(mockSystemHelper.getEnv("JH_XNAT_PT_ARCHIVE_PREFIX")).thenReturn("/data/xnat/archive"); when(mockSystemHelper.getEnv("JH_XNAT_PT_ARCHIVE_DOCKER_PREFIX")).thenReturn("/home/andy/xnat-docker-compose/xnat-data/archive"); + when(mockSystemHelper.getEnv("JH_XNAT_PT_ARCHIVE_SERVER_PREFIX")).thenReturn("/home/andy/xnat-docker-compose/xnat-data/archive"); when(mockSystemHelper.getEnv("JH_XNAT_PT_WORKSPACE_PREFIX")).thenReturn("/data/xnat/workspaces"); when(mockSystemHelper.getEnv("JH_XNAT_PT_WORKSPACE_DOCKER_PREFIX")).thenReturn("/home/andy/xnat-docker-compose/xnat-data/workspaces"); + when(mockSystemHelper.getEnv("JH_XNAT_PT_WORKSPACE_SERVER_PREFIX")).thenReturn("/home/andy/xnat-docker-compose/xnat-data/workspaces"); when(mockSystemHelper.getEnv("JH_XNAT_WORKSPACE_PATH")).thenReturn("/data/xnat/workspaces"); when(mockSystemHelper.getEnv("JH_XNAT_INACTIVITY_TIMEOUT")).thenReturn("24"); when(mockSystemHelper.getEnv("JH_XNAT_MAX_SERVER_LIFETIME")).thenReturn("48"); @@ -148,9 +150,9 @@ public void callImpl_initialized_envSet() throws Exception { verify(mockJupyterHubPreferences).setStartTimeout(60); verify(mockJupyterHubPreferences).setStopTimeout(60); verify(mockJupyterHubPreferences).setPathTranslationArchivePrefix("/data/xnat/archive"); - verify(mockJupyterHubPreferences).setPathTranslationArchiveDockerPrefix("/home/andy/xnat-docker-compose/xnat-data/archive"); + verify(mockJupyterHubPreferences, times(2)).setPathTranslationArchiveDockerPrefix("/home/andy/xnat-docker-compose/xnat-data/archive"); verify(mockJupyterHubPreferences).setPathTranslationWorkspacePrefix("/data/xnat/workspaces"); - verify(mockJupyterHubPreferences).setPathTranslationWorkspaceDockerPrefix("/home/andy/xnat-docker-compose/xnat-data/workspaces"); + verify(mockJupyterHubPreferences, times(2)).setPathTranslationWorkspaceDockerPrefix("/home/andy/xnat-docker-compose/xnat-data/workspaces"); verify(mockJupyterHubPreferences).setWorkspacePath("/data/xnat/workspaces"); verify(mockJupyterHubPreferences).setInactivityTimeout(24L); verify(mockJupyterHubPreferences).setMaxServerLifetime(48L); @@ -169,8 +171,10 @@ public void callImpl_initialized_envNotSet() throws Exception { when(mockSystemHelper.getEnv("JH_XNAT_STOP_TIMEOUT")).thenReturn(""); when(mockSystemHelper.getEnv("JH_XNAT_PT_ARCHIVE_PREFIX")).thenReturn(""); when(mockSystemHelper.getEnv("JH_XNAT_PT_ARCHIVE_DOCKER_PREFIX")).thenReturn(""); + when(mockSystemHelper.getEnv("JH_XNAT_PT_ARCHIVE_SERVER_PREFIX")).thenReturn(""); when(mockSystemHelper.getEnv("JH_XNAT_PT_WORKSPACE_PREFIX")).thenReturn(""); when(mockSystemHelper.getEnv("JH_XNAT_PT_WORKSPACE_DOCKER_PREFIX")).thenReturn(""); + when(mockSystemHelper.getEnv("JH_XNAT_PT_WORKSPACE_SERVER_PREFIX")).thenReturn(""); when(mockSystemHelper.getEnv("JH_XNAT_WORKSPACE_PATH")).thenReturn(""); when(mockSystemHelper.getEnv("JH_XNAT_INACTIVITY_TIMEOUT")).thenReturn(""); when(mockSystemHelper.getEnv("JH_XNAT_MAX_SERVER_LIFETIME")).thenReturn(""); @@ -207,8 +211,10 @@ public void callImpl_initialized_envNotSet2() throws Exception { when(mockSystemHelper.getEnv("JH_XNAT_STOP_TIMEOUT")).thenReturn(null); when(mockSystemHelper.getEnv("JH_XNAT_PT_ARCHIVE_PREFIX")).thenReturn(null); when(mockSystemHelper.getEnv("JH_XNAT_PT_ARCHIVE_DOCKER_PREFIX")).thenReturn(null); + when(mockSystemHelper.getEnv("JH_XNAT_PT_ARCHIVE_SERVER_PREFIX")).thenReturn(null); when(mockSystemHelper.getEnv("JH_XNAT_PT_WORKSPACE_PREFIX")).thenReturn(null); when(mockSystemHelper.getEnv("JH_XNAT_PT_WORKSPACE_DOCKER_PREFIX")).thenReturn(null); + when(mockSystemHelper.getEnv("JH_XNAT_PT_WORKSPACE_SERVER_PREFIX")).thenReturn(null); when(mockSystemHelper.getEnv("JH_XNAT_WORKSPACE_PATH")).thenReturn(null); when(mockSystemHelper.getEnv("JH_XNAT_INACTIVITY_TIMEOUT")).thenReturn(null); when(mockSystemHelper.getEnv("JH_XNAT_MAX_SERVER_LIFETIME")).thenReturn(null);