diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index ddbb9383b..16cd14340 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -82,6 +82,7 @@ jobs: disk_request: 1G gpu_request: 0 lfs_auto_fetch: false + ssh_request: false serverOptions: cpu_request: order: 1 diff --git a/helm-chart/renku-notebooks/templates/statefulset.yaml b/helm-chart/renku-notebooks/templates/statefulset.yaml index f1cbc0d4f..83657df66 100644 --- a/helm-chart/renku-notebooks/templates/statefulset.yaml +++ b/helm-chart/renku-notebooks/templates/statefulset.yaml @@ -166,6 +166,8 @@ spec: value: {{ .Values.sessionAutosave.terminationGracePeriodSeconds | quote }} - name: NB_SESSIONS__AUTOSAVE_MINIMUM_LFS_FILE_SIZE_BYTES value: {{ .Values.sessionAutosave.minimumLFSFileSizeBytes | quote }} + - name: NB_SESSION_SSH__ENABLED + value: {{ .Values.session_ssh.enabled | quote }} - name: NB_VERSION value: {{ .Values.image.tag | quote }} {{ if .Values.sessionsNamespace }} diff --git a/helm-chart/renku-notebooks/values.schema.json b/helm-chart/renku-notebooks/values.schema.json index d11575d02..44a37e121 100644 --- a/helm-chart/renku-notebooks/values.schema.json +++ b/helm-chart/renku-notebooks/values.schema.json @@ -233,7 +233,8 @@ "mem_request": { "$ref": "#/definitions/informationAmount" }, "lfs_auto_fetch": { "type": "boolean" }, "gpu_request": { "$ref": "#/definitions/gpuRequest" }, - "disk_request": { "$ref": "#/definitions/informationAmountOrNull" } + "disk_request": { "$ref": "#/definitions/informationAmountOrNull" }, + "ssh_request": { "type": "boolean" } }, "required": [ "defaultUrl", @@ -241,7 +242,8 @@ "mem_request", "lfs_auto_fetch", "gpu_request", - "disk_request" + "disk_request", + "ssh_request" ], "type": "object", "additionalProperties": false @@ -254,7 +256,8 @@ "mem_request": { "$ref": "#/definitions/serverOptionMemory" }, "lfs_auto_fetch": { "$ref": "#/definitions/serverOptionBool" }, "gpu_request": { "$ref": "#/definitions/serverOptionGpu" }, - "disk_request": { "$ref": "#/definitions/serverOptionDisk" } + "disk_request": { "$ref": "#/definitions/serverOptionDisk" }, + "ssh_request": { "$ref": "#/definitions/serverOptionBool" } }, "required": [ "lfs_auto_fetch" diff --git a/helm-chart/renku-notebooks/values.yaml b/helm-chart/renku-notebooks/values.yaml index 877b87305..8ef7c13ef 100644 --- a/helm-chart/renku-notebooks/values.yaml +++ b/helm-chart/renku-notebooks/values.yaml @@ -26,7 +26,7 @@ global: clientSecret: keycloak: ## The name of the realm in Keycloak used by Renku - realm: + realm: amalthea: scope: @@ -65,6 +65,9 @@ cloudstorage: enabled: false readOnly: true +session_ssh: + enabled: false + # configuration for user session persistent volumes userSessionPersistentVolumes: enabled: true @@ -215,6 +218,11 @@ serverOptions: displayName: Automatically fetch LFS data type: boolean default: false + ssh_request: + order: 6 + displayName: Enable SSH connections + type: boolean + default: false ## Default server option values used to launch a session when ## such values are not provided explicitly in the post request. @@ -229,6 +237,7 @@ serverDefaults: disk_request: 1G gpu_request: 0 lfs_auto_fetch: false + ssh_request: false ## How to enforce CPU limits for sessions, options are "lax", "off" or "strict" ## - "strict" = CPU limit equals cpu request diff --git a/renku_notebooks/api/amalthea_patches/jupyter_server.py b/renku_notebooks/api/amalthea_patches/jupyter_server.py index 853b30a41..856f66997 100644 --- a/renku_notebooks/api/amalthea_patches/jupyter_server.py +++ b/renku_notebooks/api/amalthea_patches/jupyter_server.py @@ -64,6 +64,14 @@ def env(server: "UserServer"): "path": "/statefulset/spec/template/spec/containers/0/env/-", "value": {"name": "GIT_CLONE_REPO", "value": "true"}, }, + { + "op": "add", + "path": "/statefulset/spec/template/spec/containers/0/env/-", + "value": { + "name": "RENKU_ENABLE_SSH", + "value": "1" if server.server_options.get("ssh_request") else "0", + }, + }, ] if server.environment_variables: diff --git a/renku_notebooks/api/classes/server_manifest.py b/renku_notebooks/api/classes/server_manifest.py index d876a20e8..d174699b5 100644 --- a/renku_notebooks/api/classes/server_manifest.py +++ b/renku_notebooks/api/classes/server_manifest.py @@ -64,6 +64,17 @@ def server_options(self) -> Dict[str, Any]: for env in patch.get("value", {}).get("env", []): if env.get("name") == "GIT_CLONE_LFS_AUTO_FETCH": server_options["lfs_auto_fetch"] = env.get("value") == "1" + # ssh request + if config.sessions.session_ssh_enabled: + for patches in js["spec"]["patches"]: + for patch in patches.get("patch", []): + if ( + patch.get("path") + == "/statefulset/spec/template/spec/containers/0/env/-" + ): + for env in patch.get("value", {}).get("env", []): + if env.get("name") == "RENKU_ENABLE_SSH": + server_options["ssh_request"] = env.get("value") == "1" return { **config.server_options.defaults, **server_options, diff --git a/renku_notebooks/api/schemas/config_server_options.py b/renku_notebooks/api/schemas/config_server_options.py index 04b5b6127..fb3c09378 100644 --- a/renku_notebooks/api/schemas/config_server_options.py +++ b/renku_notebooks/api/schemas/config_server_options.py @@ -84,6 +84,7 @@ class ServerOptionsChoices(Schema): disk_request = fields.Nested(MemoryServerOptionsChoice, required=False) lfs_auto_fetch = fields.Nested(BoolServerOptionsChoice, required=False) gpu_request = fields.Nested(GpuServerOptionsChoice, required=False) + ssh_request = fields.Nested(BoolServerOptionsChoice, required=False) class ServerOptionsDefaults(Schema): @@ -95,6 +96,7 @@ class ServerOptionsDefaults(Schema): disk_request = ByteSizeField(required=True) lfs_auto_fetch = fields.Bool(required=True) gpu_request = GpuField(required=True) + ssh_request = fields.Bool(required=True) class CloudStorageServerOption(Schema): diff --git a/renku_notebooks/api/schemas/server_options.py b/renku_notebooks/api/schemas/server_options.py index 534c5cc14..e9acbeeb1 100644 --- a/renku_notebooks/api/schemas/server_options.py +++ b/renku_notebooks/api/schemas/server_options.py @@ -80,3 +80,6 @@ class LaunchNotebookRequestServerOptions(Schema): config.server_options.defaults, ), ) + ssh_request = fields.Bool( + required=False, missing=config.server_options.defaults["ssh_request"] + ) diff --git a/renku_notebooks/config/__init__.py b/renku_notebooks/config/__init__.py index b250596b7..94b658658 100644 --- a/renku_notebooks/config/__init__.py +++ b/renku_notebooks/config/__init__.py @@ -160,6 +160,7 @@ def get_config(default_config: str) -> _NotebooksConfig: } enforce_cpu_limits: false autosave_minimum_lfs_file_size_bytes: 1000000 + session_ssh_enabled: false termination_grace_period_seconds: 600 image_default_workdir: /home/jovyan node_selector: "{}" diff --git a/renku_notebooks/config/dynamic.py b/renku_notebooks/config/dynamic.py index 01f15694c..6707bb5c0 100644 --- a/renku_notebooks/config/dynamic.py +++ b/renku_notebooks/config/dynamic.py @@ -187,6 +187,7 @@ class _SessionConfig: default_image: Text = "renku/singleuser:latest" enforce_cpu_limits: Union[Text, bool] = False autosave_minimum_lfs_file_size_bytes: Union[int, Text] = 1000000 + session_ssh_enabled: Union[Text, bool] = False termination_grace_period_seconds: Union[int, Text] = 600 image_default_workdir: Text = "/home/jovyan" node_selector: Text = "{}" diff --git a/tests/unit/dummy_server_options.json b/tests/unit/dummy_server_options.json index 9124d5daa..c41bba2fb 100644 --- a/tests/unit/dummy_server_options.json +++ b/tests/unit/dummy_server_options.json @@ -38,5 +38,11 @@ "min": "1G", "max": "100G" } + }, + "ssh_request": { + "default": false, + "displayName": "Enable SSH connections", + "order": 6, + "type": "boolean" } } diff --git a/tests/unit/test_server_class/test_manifest.py b/tests/unit/test_server_class/test_manifest.py index f5ea2673e..6a55d3ac7 100644 --- a/tests/unit/test_server_class/test_manifest.py +++ b/tests/unit/test_server_class/test_manifest.py @@ -38,6 +38,7 @@ def test_session_manifest( "cpu_request": "100", "mem_request": "100", "disk_request": "100", + "ssh_request": 0, }, "branch": "master", "commit_sha": "abcdefg123456789",