From 5eedf854a01b44ac2f9af4416d97e68e73300f0d Mon Sep 17 00:00:00 2001 From: ArmanShah Date: Wed, 1 Jun 2022 09:56:43 -0500 Subject: [PATCH 1/9] Added new WebhookKernelSessionManager --- .../services/sessions/kernelsessionmanager.py | 139 ++++++++++++++++++ 1 file changed, 139 insertions(+) diff --git a/enterprise_gateway/services/sessions/kernelsessionmanager.py b/enterprise_gateway/services/sessions/kernelsessionmanager.py index 31ebd5823..ad0bc714d 100644 --- a/enterprise_gateway/services/sessions/kernelsessionmanager.py +++ b/enterprise_gateway/services/sessions/kernelsessionmanager.py @@ -6,6 +6,9 @@ import json import os import threading +import requests +from requests.auth import HTTPBasicAuth, HTTPDigestAuth +import urllib.parse from jupyter_core.paths import jupyter_data_dir from traitlets import Bool, Unicode, default @@ -385,3 +388,139 @@ def _get_sessions_loc(self): if not os.path.exists(path): os.makedirs(path, 0o755) return path + +class WebhookKernelSessionManager(KernelSessionManager): + """ + Performs kernel session persistence operations against URL provided (EG_WEBHOOK_URL). The URL must have 4 endpoints + associated with it. 1 delete endpoint that takes a list of kernel ids in the body, 1 post endpoint that takes kernels id as a + url param and the kernel session as the body, 1 get endpoint that returns all kernel sessions, and 1 get endpoint that returns + a specific kernel session based on kernel id as url param. + """ + + # Webhook URL + webhook_url_env = "EG_WEBHOOK_URL" + webhook_url = Unicode( + config=True, + help="""URL endpoint for webhook kernel session manager""", + ) + + @default("webhook_url") + def webhook_url_default(self): + return os.getenv(self.webhook_url_env, "") + + # Webhook Username + webhook_username_env = "EG_WEBHOOK_USERNAME" + webhook_username = Unicode( + config=True, + help="""Username for webhook kernel session manager API auth""", + ) + + @default("webhook_username") + def webhook_username_default(self): + return os.getenv(self.webhook_username_env, "") + + # Webhook Password + webhook_password_env = "EG_WEBHOOK_PASSWORD" + webhook_password = Unicode( + config=True, + help="""Password for webhook kernel session manager API auth""", + ) + + @default("webhook_password") + def webhook_password_default(self): + return os.getenv(self.webhook_password_env, "") + + # Auth Type + auth_type_env = "EG_AUTH_TYPE" + auth_type = Unicode( + config=True, + help="""ROPC for webhook kernel session manager API auth Basic, Digest or None""", + ) + + @default("auth_type") + def auth_type_default(self): + return os.getenv(self.auth_type_env, "") + + def __init__(self, kernel_manager, **kwargs): + super().__init__(kernel_manager, **kwargs) + if self.enable_persistence: + self.log.info("Webhook kernel session persistence activated") + self.auth = "" + if (self.auth_type): + if (self.webhook_username and self.webhook_password): + if (self.auth_type.lower() == "basic"): + self.auth = HTTPBasicAuth(self.webhook_username, self.webhook_password) + elif (self.auth_type.lower() == "digest"): + self.auth = HTTPDigestAuth(self.webhook_username, self.webhook_password) + elif (self.auth_type.lower() == "none"): + self.auth = "" + else: + self.log.error("No such option for auth_type/EG_AUTH_TYPE") + else: + self.log.error("Username and/or password aren't set") + + + def delete_sessions(self, kernel_ids): + """ + Deletes kernel sessions from database + + :param list of strings kernel_ids: A list of kernel ids + """ + if self.enable_persistence: + response = requests.delete(self.webhook_url, auth=self.auth, json=kernel_ids) + self.log.debug(f"Webhook kernel session deleting: {kernel_ids}") + if (response.status_code != 204): + self.log.error(response.raise_for_status()) + + def save_session(self, kernel_id): + """ + Saves kernel session to database + + :param string kernel_id: A kernel id + """ + if self.enable_persistence: + if kernel_id is not None: + temp_session = dict() + temp_session[kernel_id] = self._sessions[kernel_id] + body = KernelSessionManager.pre_save_transformation(temp_session) + response = requests.post(f'{self.webhook_url}/{kernel_id}', auth=self.auth, json=body) + self.log.debug(f"Webhook kernel session saving: {kernel_id}") + if (response.status_code != 204): + self.log.error(response.raise_for_status()) + + def load_sessions(self): + """ + Loads kernel sessions from database + """ + if self.enable_persistence: + response = requests.get(self.webhook_url, auth=self.auth) + if (response.status_code == 200): + kernel_sessions = response.content + for kernel_session in kernel_sessions: + self._load_session_from_file(kernel_session) + else: + self.log.error(response.raise_for_status()) + + def load_session(self, kernel_id): + """ + Loads a kernel session from database + + :param string kernel_id: A kernel id + """ + if self.enable_persistence: + if kernel_id is not None: + response = requests.get(f'{self.webhook_url}/{kernel_id}', auth=self.auth) + if (response.status_code == 200): + kernel_session = response.content + self._load_session_from_file(kernel_session) + else: + self.log.error(response.raise_for_status()) + + def _load_session_from_file(self, kernel): + """ + Loads kernel session to current session + + :param dictionary kernel: Kernel session information + """ + self.log.debug(f"Loading saved session(s)") + self._sessions.update(KernelSessionManager.post_load_transformation(json.loads(kernel)["kernel"])) From 1851878ae9c9b6266bf51421824470a67aa747a2 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 1 Jun 2022 15:37:20 +0000 Subject: [PATCH 2/9] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .../services/sessions/kernelsessionmanager.py | 34 +++++++++++-------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/enterprise_gateway/services/sessions/kernelsessionmanager.py b/enterprise_gateway/services/sessions/kernelsessionmanager.py index ad0bc714d..0de24199e 100644 --- a/enterprise_gateway/services/sessions/kernelsessionmanager.py +++ b/enterprise_gateway/services/sessions/kernelsessionmanager.py @@ -6,11 +6,11 @@ import json import os import threading -import requests -from requests.auth import HTTPBasicAuth, HTTPDigestAuth import urllib.parse +import requests from jupyter_core.paths import jupyter_data_dir +from requests.auth import HTTPBasicAuth, HTTPDigestAuth from traitlets import Bool, Unicode, default from traitlets.config.configurable import LoggingConfigurable @@ -389,6 +389,7 @@ def _get_sessions_loc(self): os.makedirs(path, 0o755) return path + class WebhookKernelSessionManager(KernelSessionManager): """ Performs kernel session persistence operations against URL provided (EG_WEBHOOK_URL). The URL must have 4 endpoints @@ -446,19 +447,18 @@ def __init__(self, kernel_manager, **kwargs): if self.enable_persistence: self.log.info("Webhook kernel session persistence activated") self.auth = "" - if (self.auth_type): - if (self.webhook_username and self.webhook_password): - if (self.auth_type.lower() == "basic"): + if self.auth_type: + if self.webhook_username and self.webhook_password: + if self.auth_type.lower() == "basic": self.auth = HTTPBasicAuth(self.webhook_username, self.webhook_password) - elif (self.auth_type.lower() == "digest"): + elif self.auth_type.lower() == "digest": self.auth = HTTPDigestAuth(self.webhook_username, self.webhook_password) - elif (self.auth_type.lower() == "none"): + elif self.auth_type.lower() == "none": self.auth = "" else: self.log.error("No such option for auth_type/EG_AUTH_TYPE") else: self.log.error("Username and/or password aren't set") - def delete_sessions(self, kernel_ids): """ @@ -469,7 +469,7 @@ def delete_sessions(self, kernel_ids): if self.enable_persistence: response = requests.delete(self.webhook_url, auth=self.auth, json=kernel_ids) self.log.debug(f"Webhook kernel session deleting: {kernel_ids}") - if (response.status_code != 204): + if response.status_code != 204: self.log.error(response.raise_for_status()) def save_session(self, kernel_id): @@ -483,9 +483,11 @@ def save_session(self, kernel_id): temp_session = dict() temp_session[kernel_id] = self._sessions[kernel_id] body = KernelSessionManager.pre_save_transformation(temp_session) - response = requests.post(f'{self.webhook_url}/{kernel_id}', auth=self.auth, json=body) + response = requests.post( + f"{self.webhook_url}/{kernel_id}", auth=self.auth, json=body + ) self.log.debug(f"Webhook kernel session saving: {kernel_id}") - if (response.status_code != 204): + if response.status_code != 204: self.log.error(response.raise_for_status()) def load_sessions(self): @@ -494,7 +496,7 @@ def load_sessions(self): """ if self.enable_persistence: response = requests.get(self.webhook_url, auth=self.auth) - if (response.status_code == 200): + if response.status_code == 200: kernel_sessions = response.content for kernel_session in kernel_sessions: self._load_session_from_file(kernel_session) @@ -509,8 +511,8 @@ def load_session(self, kernel_id): """ if self.enable_persistence: if kernel_id is not None: - response = requests.get(f'{self.webhook_url}/{kernel_id}', auth=self.auth) - if (response.status_code == 200): + response = requests.get(f"{self.webhook_url}/{kernel_id}", auth=self.auth) + if response.status_code == 200: kernel_session = response.content self._load_session_from_file(kernel_session) else: @@ -523,4 +525,6 @@ def _load_session_from_file(self, kernel): :param dictionary kernel: Kernel session information """ self.log.debug(f"Loading saved session(s)") - self._sessions.update(KernelSessionManager.post_load_transformation(json.loads(kernel)["kernel"])) + self._sessions.update( + KernelSessionManager.post_load_transformation(json.loads(kernel)["kernel"]) + ) From 08d7ef260234cf03d149047992c04438a7edd457 Mon Sep 17 00:00:00 2001 From: amazingarman Date: Wed, 1 Jun 2022 10:40:02 -0500 Subject: [PATCH 3/9] Removed unused imports --- enterprise_gateway/services/sessions/kernelsessionmanager.py | 1 - 1 file changed, 1 deletion(-) diff --git a/enterprise_gateway/services/sessions/kernelsessionmanager.py b/enterprise_gateway/services/sessions/kernelsessionmanager.py index 0de24199e..c6dea3aad 100644 --- a/enterprise_gateway/services/sessions/kernelsessionmanager.py +++ b/enterprise_gateway/services/sessions/kernelsessionmanager.py @@ -6,7 +6,6 @@ import json import os import threading -import urllib.parse import requests from jupyter_core.paths import jupyter_data_dir From 81c87b3f8b57a8103a17349940eeb19ebb832f88 Mon Sep 17 00:00:00 2001 From: amazingarman Date: Wed, 1 Jun 2022 10:46:47 -0500 Subject: [PATCH 4/9] Clean up --- enterprise_gateway/services/sessions/kernelsessionmanager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/enterprise_gateway/services/sessions/kernelsessionmanager.py b/enterprise_gateway/services/sessions/kernelsessionmanager.py index c6dea3aad..db2cad235 100644 --- a/enterprise_gateway/services/sessions/kernelsessionmanager.py +++ b/enterprise_gateway/services/sessions/kernelsessionmanager.py @@ -523,7 +523,7 @@ def _load_session_from_file(self, kernel): :param dictionary kernel: Kernel session information """ - self.log.debug(f"Loading saved session(s)") + self.log.debug("Loading saved session(s)") self._sessions.update( KernelSessionManager.post_load_transformation(json.loads(kernel)["kernel"]) ) From 87e2402a132e336e0231080c5a7c51ea50064ef6 Mon Sep 17 00:00:00 2001 From: ArmanShah Date: Tue, 7 Jun 2022 12:38:17 -0500 Subject: [PATCH 5/9] Updated based off of PR comments --- docs/source/operators/config-cli.md | 23 +++++++++++++ .../operators/config-kernel-persistence.md | 33 +++++++++++++++++++ docs/source/operators/index.rst | 1 + enterprise_gateway/enterprisegatewayapp.py | 4 +-- .../services/sessions/kernelsessionmanager.py | 4 +-- 5 files changed, 61 insertions(+), 4 deletions(-) create mode 100644 docs/source/operators/config-kernel-persistence.md diff --git a/docs/source/operators/config-cli.md b/docs/source/operators/config-cli.md index baf40d175..63d6cdac4 100644 --- a/docs/source/operators/config-cli.md +++ b/docs/source/operators/config-cli.md @@ -283,6 +283,29 @@ FileKernelSessionManager(KernelSessionManager) options reside. This directory should exist. (EG_PERSISTENCE_ROOT env var) Default: '' +WebhookKernelSessionManager(KernelSessionManager) options +--------------------------------------------------------- +--WebhookKernelSessionManager.enable_persistence= + Enable kernel session persistence (True or False). Default = False + (EG_KERNEL_SESSION_PERSISTENCE env var) + Default: False +--WebhookKernelSessionManager.persistence_root= + Identifies the root 'directory' under which the 'kernel_sessions' node will + reside. This directory should exist. (EG_PERSISTENCE_ROOT env var) + Default: '' +--WebhookKernelSessionManager.webhook_url= + URL endpoint for webhook kernel session manager + Default: '' +--WebhookKernelSessionManager.auth_type= + Authentication type for webhook kernel session manager API. Either Basic, Digest or None + Default: '' +--WebhookKernelSessionManager.webhook_username= + Username for webhook kernel session manager API auth + Default: '' +--WebhookKernelSessionManager.webhook_password= + Password for webhook kernel session manager API auth + Default: '' + RemoteMappingKernelManager(AsyncMappingKernelManager) options ------------------------------------------------------------- --RemoteMappingKernelManager.allowed_message_types=... diff --git a/docs/source/operators/config-kernel-persistence.md b/docs/source/operators/config-kernel-persistence.md new file mode 100644 index 000000000..2da8e8723 --- /dev/null +++ b/docs/source/operators/config-kernel-persistence.md @@ -0,0 +1,33 @@ +# Kernel Session Persistence +Enabling kernel session persistence allows Jupyter Notebooks to reconnect to kernels when Enterprise Gateway is restarted. There are two ways of persisting kernel sessions: _File Kernel Session Persistence_ and _Webhook Kernel Session Persistence_. + +NOTE: Kernel Session Persistence should be considered experimental! + +## File Kernel Session Persistence +File Kernel Session Persistence stores all kernel sessions as a file in a specified directory. To enable this, set the environment variable `EG_KERNEL_SESSION_PERSISTENCE=True` or configure `FileKernelSessionManager.enable_persistence=True`. To change the directory in which the kernel session file is being saved, either set the environment variable `EG_PERSISTENCE_ROOT` or configure `FileKernelSessionManager.persistence_root` to the directory. + +## Webhook Kernel Session Persistence +Webhook Kernel Session Persistence stores all kernel sessions to any database. In order for this to work, an API must be created. The API must include four endpoints: + +- A GET that will retrieve a list of all kernel sessions from a database +- A GET that will take the kernel id as a path variable and retrieve that information from a database +- A DELETE that will delete all kernel sessions, where the body of the request is a list of kernel ids +- A POST that will take kernel id as a path variable and kernel session in the body of the request and save it to a database where the object being saved is: +``` + { + kernel_id: KERNEL ID, + kernel: KERNEL SESSION OBJECT + } +``` + +To enable the webhook kernel session persistence, set the environment variable `EG_KERNEL_SESSION_PERSISTENCE=True` or configure `WebhookKernelSessionManager.enable_persistence=True`. To connect the API, set the environment varible `EG_WEBHOOK_URL` or configure `WebhookKernelSessionManager.webhook_url` to the API endpoint. + +### Enabling Authentication +Enabling authentication is an option if the API requries it for requests. Set the environment variable `EG_AUTH_TYPE` or configure `WebhookKernelSessionManager.auth_type` to be either `Basic` or `Digest`. If it is set to an empty string authentication won't be enabled. + +Then set the environment variables `EG_WEBHOOK_USERNAME` and `EG_WEBHOOK_PASSWORD` or configure `WebhookKernelSessionManager.webhook_username` and `WebhookKernelSessionManager.webhook_password` to provide the username and password for authentication. + +## Testing Kernel Session Persistence +Once kernel session persistence has been enabled and configured, create a kernel by opening up a Jupyter Notebook. Save some variable in that notebook and shutdown Enterprise Gateway using `kill -9 PID`, wher `PID` is the PID of gateway. Restart Enterprise Gateway and refresh you notebook tab. If all worked correctly, the variable should be loaded without the need to rerun the cell. + +If you are using docker, ensure the container isn't tied to the PID of Enterprise Gateway. The container should still run after killing that PID. \ No newline at end of file diff --git a/docs/source/operators/index.rst b/docs/source/operators/index.rst index e4dbe61f2..6b0f8ef9e 100644 --- a/docs/source/operators/index.rst +++ b/docs/source/operators/index.rst @@ -65,4 +65,5 @@ Jupyter Enterprise Gateway adheres to config-kernel-override config-dynamic config-culling + config-kernel-persistence config-security diff --git a/enterprise_gateway/enterprisegatewayapp.py b/enterprise_gateway/enterprisegatewayapp.py index ced8214af..37274ebb1 100644 --- a/enterprise_gateway/enterprisegatewayapp.py +++ b/enterprise_gateway/enterprisegatewayapp.py @@ -34,7 +34,7 @@ default_handlers as default_kernelspec_handlers, ) from .services.sessions.handlers import default_handlers as default_session_handlers -from .services.sessions.kernelsessionmanager import FileKernelSessionManager +from .services.sessions.kernelsessionmanager import FileKernelSessionManager, WebhookKernelSessionManager from .services.sessions.sessionmanager import SessionManager try: @@ -77,7 +77,7 @@ class EnterpriseGatewayApp(EnterpriseGatewayConfigMixin, JupyterApp): """ # Also include when generating help options - classes = [KernelSpecCache, FileKernelSessionManager, RemoteMappingKernelManager] + classes = [KernelSpecCache, FileKernelSessionManager, WebhookKernelSessionManager, RemoteMappingKernelManager] # Enable some command line shortcuts aliases = aliases diff --git a/enterprise_gateway/services/sessions/kernelsessionmanager.py b/enterprise_gateway/services/sessions/kernelsessionmanager.py index db2cad235..ba871f15f 100644 --- a/enterprise_gateway/services/sessions/kernelsessionmanager.py +++ b/enterprise_gateway/services/sessions/kernelsessionmanager.py @@ -434,7 +434,7 @@ def webhook_password_default(self): auth_type_env = "EG_AUTH_TYPE" auth_type = Unicode( config=True, - help="""ROPC for webhook kernel session manager API auth Basic, Digest or None""", + help="""Authentication type for webhook kernel session manager API. Either Basic, Digest or None""", ) @default("auth_type") @@ -517,7 +517,7 @@ def load_session(self, kernel_id): else: self.log.error(response.raise_for_status()) - def _load_session_from_file(self, kernel): + def _load_session_from_response(self, kernel): """ Loads kernel session to current session From 245dc9e704212afe28cf140c2a768adde4e312fa Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 7 Jun 2022 17:43:45 +0000 Subject: [PATCH 6/9] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- docs/source/operators/config-kernel-persistence.md | 10 ++++++++-- enterprise_gateway/enterprisegatewayapp.py | 12 ++++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/docs/source/operators/config-kernel-persistence.md b/docs/source/operators/config-kernel-persistence.md index 2da8e8723..1086981d4 100644 --- a/docs/source/operators/config-kernel-persistence.md +++ b/docs/source/operators/config-kernel-persistence.md @@ -1,18 +1,22 @@ # Kernel Session Persistence + Enabling kernel session persistence allows Jupyter Notebooks to reconnect to kernels when Enterprise Gateway is restarted. There are two ways of persisting kernel sessions: _File Kernel Session Persistence_ and _Webhook Kernel Session Persistence_. NOTE: Kernel Session Persistence should be considered experimental! ## File Kernel Session Persistence + File Kernel Session Persistence stores all kernel sessions as a file in a specified directory. To enable this, set the environment variable `EG_KERNEL_SESSION_PERSISTENCE=True` or configure `FileKernelSessionManager.enable_persistence=True`. To change the directory in which the kernel session file is being saved, either set the environment variable `EG_PERSISTENCE_ROOT` or configure `FileKernelSessionManager.persistence_root` to the directory. ## Webhook Kernel Session Persistence + Webhook Kernel Session Persistence stores all kernel sessions to any database. In order for this to work, an API must be created. The API must include four endpoints: - A GET that will retrieve a list of all kernel sessions from a database - A GET that will take the kernel id as a path variable and retrieve that information from a database - A DELETE that will delete all kernel sessions, where the body of the request is a list of kernel ids - A POST that will take kernel id as a path variable and kernel session in the body of the request and save it to a database where the object being saved is: + ``` { kernel_id: KERNEL ID, @@ -23,11 +27,13 @@ Webhook Kernel Session Persistence stores all kernel sessions to any database. I To enable the webhook kernel session persistence, set the environment variable `EG_KERNEL_SESSION_PERSISTENCE=True` or configure `WebhookKernelSessionManager.enable_persistence=True`. To connect the API, set the environment varible `EG_WEBHOOK_URL` or configure `WebhookKernelSessionManager.webhook_url` to the API endpoint. ### Enabling Authentication + Enabling authentication is an option if the API requries it for requests. Set the environment variable `EG_AUTH_TYPE` or configure `WebhookKernelSessionManager.auth_type` to be either `Basic` or `Digest`. If it is set to an empty string authentication won't be enabled. -Then set the environment variables `EG_WEBHOOK_USERNAME` and `EG_WEBHOOK_PASSWORD` or configure `WebhookKernelSessionManager.webhook_username` and `WebhookKernelSessionManager.webhook_password` to provide the username and password for authentication. +Then set the environment variables `EG_WEBHOOK_USERNAME` and `EG_WEBHOOK_PASSWORD` or configure `WebhookKernelSessionManager.webhook_username` and `WebhookKernelSessionManager.webhook_password` to provide the username and password for authentication. ## Testing Kernel Session Persistence + Once kernel session persistence has been enabled and configured, create a kernel by opening up a Jupyter Notebook. Save some variable in that notebook and shutdown Enterprise Gateway using `kill -9 PID`, wher `PID` is the PID of gateway. Restart Enterprise Gateway and refresh you notebook tab. If all worked correctly, the variable should be loaded without the need to rerun the cell. -If you are using docker, ensure the container isn't tied to the PID of Enterprise Gateway. The container should still run after killing that PID. \ No newline at end of file +If you are using docker, ensure the container isn't tied to the PID of Enterprise Gateway. The container should still run after killing that PID. diff --git a/enterprise_gateway/enterprisegatewayapp.py b/enterprise_gateway/enterprisegatewayapp.py index 37274ebb1..0bb698b63 100644 --- a/enterprise_gateway/enterprisegatewayapp.py +++ b/enterprise_gateway/enterprisegatewayapp.py @@ -34,7 +34,10 @@ default_handlers as default_kernelspec_handlers, ) from .services.sessions.handlers import default_handlers as default_session_handlers -from .services.sessions.kernelsessionmanager import FileKernelSessionManager, WebhookKernelSessionManager +from .services.sessions.kernelsessionmanager import ( + FileKernelSessionManager, + WebhookKernelSessionManager, +) from .services.sessions.sessionmanager import SessionManager try: @@ -77,7 +80,12 @@ class EnterpriseGatewayApp(EnterpriseGatewayConfigMixin, JupyterApp): """ # Also include when generating help options - classes = [KernelSpecCache, FileKernelSessionManager, WebhookKernelSessionManager, RemoteMappingKernelManager] + classes = [ + KernelSpecCache, + FileKernelSessionManager, + WebhookKernelSessionManager, + RemoteMappingKernelManager, + ] # Enable some command line shortcuts aliases = aliases From 7d96d599d358a18ff9448dff9664577686a788fb Mon Sep 17 00:00:00 2001 From: ArmanShah Date: Wed, 8 Jun 2022 10:31:34 -0500 Subject: [PATCH 7/9] Updated based off of PR comments --- docs/source/operators/config-cli.md | 12 +++---- .../operators/config-kernel-persistence.md | 4 +-- .../services/sessions/kernelsessionmanager.py | 35 +++++++++++-------- 3 files changed, 28 insertions(+), 23 deletions(-) diff --git a/docs/source/operators/config-cli.md b/docs/source/operators/config-cli.md index 63d6cdac4..585def30c 100644 --- a/docs/source/operators/config-cli.md +++ b/docs/source/operators/config-cli.md @@ -292,19 +292,19 @@ WebhookKernelSessionManager(KernelSessionManager) options --WebhookKernelSessionManager.persistence_root= Identifies the root 'directory' under which the 'kernel_sessions' node will reside. This directory should exist. (EG_PERSISTENCE_ROOT env var) - Default: '' + Default: None --WebhookKernelSessionManager.webhook_url= URL endpoint for webhook kernel session manager - Default: '' + Default: None --WebhookKernelSessionManager.auth_type= - Authentication type for webhook kernel session manager API. Either Basic, Digest or None - Default: '' + Authentication type for webhook kernel session manager API. Either basic, digest or None + Default: None --WebhookKernelSessionManager.webhook_username= Username for webhook kernel session manager API auth - Default: '' + Default: None --WebhookKernelSessionManager.webhook_password= Password for webhook kernel session manager API auth - Default: '' + Default: None RemoteMappingKernelManager(AsyncMappingKernelManager) options ------------------------------------------------------------- diff --git a/docs/source/operators/config-kernel-persistence.md b/docs/source/operators/config-kernel-persistence.md index 1086981d4..46289972e 100644 --- a/docs/source/operators/config-kernel-persistence.md +++ b/docs/source/operators/config-kernel-persistence.md @@ -19,8 +19,8 @@ Webhook Kernel Session Persistence stores all kernel sessions to any database. I ``` { - kernel_id: KERNEL ID, - kernel: KERNEL SESSION OBJECT + kernel_id: UUID string, + kernel_session: JSON } ``` diff --git a/enterprise_gateway/services/sessions/kernelsessionmanager.py b/enterprise_gateway/services/sessions/kernelsessionmanager.py index ba871f15f..e962b0a5f 100644 --- a/enterprise_gateway/services/sessions/kernelsessionmanager.py +++ b/enterprise_gateway/services/sessions/kernelsessionmanager.py @@ -10,7 +10,7 @@ import requests from jupyter_core.paths import jupyter_data_dir from requests.auth import HTTPBasicAuth, HTTPDigestAuth -from traitlets import Bool, Unicode, default +from traitlets import Bool, Unicode, CaselessStrEnum, default from traitlets.config.configurable import LoggingConfigurable kernels_lock = threading.Lock() @@ -401,45 +401,50 @@ class WebhookKernelSessionManager(KernelSessionManager): webhook_url_env = "EG_WEBHOOK_URL" webhook_url = Unicode( config=True, + allow_none=True, help="""URL endpoint for webhook kernel session manager""", ) @default("webhook_url") def webhook_url_default(self): - return os.getenv(self.webhook_url_env, "") + return os.getenv(self.webhook_url_env, None) # Webhook Username webhook_username_env = "EG_WEBHOOK_USERNAME" webhook_username = Unicode( config=True, + allow_none=True, help="""Username for webhook kernel session manager API auth""", ) @default("webhook_username") def webhook_username_default(self): - return os.getenv(self.webhook_username_env, "") + return os.getenv(self.webhook_username_env, None) # Webhook Password webhook_password_env = "EG_WEBHOOK_PASSWORD" webhook_password = Unicode( config=True, + allow_none=True, help="""Password for webhook kernel session manager API auth""", ) @default("webhook_password") def webhook_password_default(self): - return os.getenv(self.webhook_password_env, "") + return os.getenv(self.webhook_password_env, None) # Auth Type auth_type_env = "EG_AUTH_TYPE" - auth_type = Unicode( + auth_type = CaselessStrEnum( config=True, - help="""Authentication type for webhook kernel session manager API. Either Basic, Digest or None""", + allow_none=True, + values=["basic", "digest"], + help="""Authentication type for webhook kernel session manager API. Either basic, digest or None""", ) @default("auth_type") def auth_type_default(self): - return os.getenv(self.auth_type_env, "") + return os.getenv(self.auth_type_env, None) def __init__(self, kernel_manager, **kwargs): super().__init__(kernel_manager, **kwargs) @@ -448,11 +453,11 @@ def __init__(self, kernel_manager, **kwargs): self.auth = "" if self.auth_type: if self.webhook_username and self.webhook_password: - if self.auth_type.lower() == "basic": + if self.auth_type == "basic": self.auth = HTTPBasicAuth(self.webhook_username, self.webhook_password) - elif self.auth_type.lower() == "digest": + elif self.auth_type == "digest": self.auth = HTTPDigestAuth(self.webhook_username, self.webhook_password) - elif self.auth_type.lower() == "none": + elif self.auth_type == None: self.auth = "" else: self.log.error("No such option for auth_type/EG_AUTH_TYPE") @@ -498,7 +503,7 @@ def load_sessions(self): if response.status_code == 200: kernel_sessions = response.content for kernel_session in kernel_sessions: - self._load_session_from_file(kernel_session) + self._load_session_from_response(kernel_session) else: self.log.error(response.raise_for_status()) @@ -513,17 +518,17 @@ def load_session(self, kernel_id): response = requests.get(f"{self.webhook_url}/{kernel_id}", auth=self.auth) if response.status_code == 200: kernel_session = response.content - self._load_session_from_file(kernel_session) + self._load_session_from_response(kernel_session) else: self.log.error(response.raise_for_status()) - def _load_session_from_response(self, kernel): + def _load_session_from_response(self, kernel_session: dict): """ Loads kernel session to current session - :param dictionary kernel: Kernel session information + :param dictionary kernel_session: Kernel session information """ self.log.debug("Loading saved session(s)") self._sessions.update( - KernelSessionManager.post_load_transformation(json.loads(kernel)["kernel"]) + KernelSessionManager.post_load_transformation(json.loads(kernel_session)["kernel_session"]) ) From f410b01f05e4ace31aa966e40467dd36d6e6351f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 8 Jun 2022 15:32:27 +0000 Subject: [PATCH 8/9] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .../services/sessions/kernelsessionmanager.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/enterprise_gateway/services/sessions/kernelsessionmanager.py b/enterprise_gateway/services/sessions/kernelsessionmanager.py index e962b0a5f..db4d6d72e 100644 --- a/enterprise_gateway/services/sessions/kernelsessionmanager.py +++ b/enterprise_gateway/services/sessions/kernelsessionmanager.py @@ -10,7 +10,7 @@ import requests from jupyter_core.paths import jupyter_data_dir from requests.auth import HTTPBasicAuth, HTTPDigestAuth -from traitlets import Bool, Unicode, CaselessStrEnum, default +from traitlets import Bool, CaselessStrEnum, Unicode, default from traitlets.config.configurable import LoggingConfigurable kernels_lock = threading.Lock() @@ -530,5 +530,7 @@ def _load_session_from_response(self, kernel_session: dict): """ self.log.debug("Loading saved session(s)") self._sessions.update( - KernelSessionManager.post_load_transformation(json.loads(kernel_session)["kernel_session"]) + KernelSessionManager.post_load_transformation( + json.loads(kernel_session)["kernel_session"] + ) ) From baa80ca4a0d682e78061759f3a82796a9b9ac44f Mon Sep 17 00:00:00 2001 From: ArmanShah Date: Wed, 8 Jun 2022 10:34:04 -0500 Subject: [PATCH 9/9] Reformatted --- enterprise_gateway/services/sessions/kernelsessionmanager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/enterprise_gateway/services/sessions/kernelsessionmanager.py b/enterprise_gateway/services/sessions/kernelsessionmanager.py index db4d6d72e..bbf0bbaff 100644 --- a/enterprise_gateway/services/sessions/kernelsessionmanager.py +++ b/enterprise_gateway/services/sessions/kernelsessionmanager.py @@ -457,7 +457,7 @@ def __init__(self, kernel_manager, **kwargs): self.auth = HTTPBasicAuth(self.webhook_username, self.webhook_password) elif self.auth_type == "digest": self.auth = HTTPDigestAuth(self.webhook_username, self.webhook_password) - elif self.auth_type == None: + elif self.auth_type is None: self.auth = "" else: self.log.error("No such option for auth_type/EG_AUTH_TYPE")