Skip to content

Commit 43032d6

Browse files
committed
Deprecate env-whitelist traits, send client-envs in kernelspec
1 parent f127e41 commit 43032d6

File tree

3 files changed

+76
-25
lines changed

3 files changed

+76
-25
lines changed

enterprise_gateway/mixins.py

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -372,30 +372,53 @@ def list_kernels_default(self) -> bool:
372372
== "true"
373373
)
374374

375-
env_whitelist_env = "EG_ENV_WHITELIST"
376375
env_whitelist = ListTrait(
377376
config=True,
378-
help="""Environment variables allowed to be set when a client requests a
379-
new kernel. Use '*' to allow all environment variables sent in the request.
380-
(EG_ENV_WHITELIST env var)""",
377+
help="""DEPRECATED, use allowed_envs.""",
381378
)
382379

383380
@default("env_whitelist")
384381
def env_whitelist_default(self) -> List[str]:
385382
return os.getenv(self.env_whitelist_env, os.getenv("KG_ENV_WHITELIST", "")).split(",")
386383

387-
env_process_whitelist_env = "EG_ENV_PROCESS_WHITELIST"
384+
@observe("env_whitelist")
385+
def _update_env_whitelist(self, change):
386+
self.log.warning("env_whitelist is deprecated, use client_envs")
387+
self.client_envs = change["new"]
388+
389+
client_envs_env = "EG_CLIENT_ENVS"
390+
client_envs = ListTrait(
391+
config=True,
392+
help="""Environment variables allowed to be set when a client requests a
393+
new kernel. (EG_CLIENT_ENVS env var)""",
394+
)
395+
396+
@default("client_envs")
397+
def client_envs_default(self):
398+
return os.getenv(self.client_envs_env, os.getenv("EG_ENV_WHITELIST", "")).split(",")
399+
388400
env_process_whitelist = ListTrait(
401+
config=True,
402+
help="""DEPRECATED, use inherited_envs""",
403+
)
404+
405+
@observe("env_process_whitelist")
406+
def _update_env_process_whitelist(self, change):
407+
self.log.warning("env_process_whitelist is deprecated, use inherited_envs")
408+
self.inherited_envs = change["new"]
409+
410+
inherited_envs_env = "EG_INHERITED_ENVS"
411+
inherited_envs = ListTrait(
389412
config=True,
390413
help="""Environment variables allowed to be inherited
391-
from the spawning process by the kernel. (EG_ENV_PROCESS_WHITELIST env var)""",
414+
from the spawning process by the kernel. (EG_INHERITED_ENVS env var)""",
392415
)
393416

394-
@default("env_process_whitelist")
395-
def env_process_whitelist_default(self) -> List[str]:
396-
return os.getenv(
397-
self.env_process_whitelist_env, os.getenv("KG_ENV_PROCESS_WHITELIST", "")
398-
).split(",")
417+
@default("inherited_envs")
418+
def inherited_envs_default(self) -> List[str]:
419+
return os.getenv(self.inherited_envs_env, os.getenv("EG_ENV_PROCESS_WHITELIST", "")).split(
420+
","
421+
)
399422

400423
kernel_headers_env = "EG_KERNEL_HEADERS"
401424
kernel_headers = ListTrait(

enterprise_gateway/services/kernelspecs/handlers.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ def kernel_spec_cache(self) -> KernelSpecCache:
6969

7070
@web.authenticated
7171
async def get(self) -> None:
72-
ksm = self.kernel_spec_cache
72+
ksc = self.kernel_spec_cache
7373
km = self.kernel_manager
7474
model = {}
7575
model["default"] = km.default_kernel_name
@@ -82,7 +82,7 @@ async def get(self) -> None:
8282
if kernel_user:
8383
self.log.debug("Searching kernels for user '%s' " % kernel_user)
8484

85-
kspecs = await ensure_async(ksm.get_all_specs())
85+
kspecs = await ensure_async(ksc.get_all_specs())
8686

8787
list_kernels_found = []
8888
for kernel_name, kernel_info in kspecs.items():
@@ -122,14 +122,14 @@ def kernel_spec_cache(self) -> KernelSpecCache:
122122

123123
@web.authenticated
124124
async def get(self, kernel_name: str) -> None:
125-
ksm = self.kernel_spec_cache
125+
ksc = self.kernel_spec_cache
126126
kernel_name = url_unescape(kernel_name)
127127
kernel_user_filter = self.request.query_arguments.get("user")
128128
kernel_user = None
129129
if kernel_user_filter:
130130
kernel_user = kernel_user_filter[0].decode("utf-8")
131131
try:
132-
spec = await ensure_async(ksm.get_kernel_spec(kernel_name))
132+
spec = await ensure_async(ksc.get_kernel_spec(kernel_name))
133133
except KeyError:
134134
raise web.HTTPError(404, "Kernel spec %s not found" % kernel_name)
135135
if is_kernelspec_model(spec):
@@ -166,9 +166,9 @@ def initialize(self) -> None:
166166

167167
@web.authenticated
168168
async def get(self, kernel_name: str, path: str, include_body: bool = True) -> None:
169-
ksm = self.kernel_spec_cache
169+
ksc = self.kernel_spec_cache
170170
try:
171-
kernelspec = await ensure_async(ksm.get_kernel_spec(kernel_name))
171+
kernelspec = await ensure_async(ksc.get_kernel_spec(kernel_name))
172172
self.root = kernelspec.resource_dir
173173
except KeyError as e:
174174
raise web.HTTPError(404, "Kernel spec %s not found" % kernel_name) from e

enterprise_gateway/services/kernelspecs/kernelspec_cache.py

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"""Cache handling for kernel specs."""
44

55
import os
6-
from typing import Dict, Optional, Union
6+
from typing import Dict, Optional, Set, Union
77

88
from jupyter_client.kernelspec import KernelSpec
99
from jupyter_server.utils import ensure_async
@@ -33,7 +33,7 @@ class KernelSpecCache(SingletonConfigurable):
3333

3434
cache_enabled_env = "EG_KERNELSPEC_CACHE_ENABLED"
3535
cache_enabled = CBool(
36-
False,
36+
True,
3737
config=True,
3838
help="""Enable Kernel Specification caching. (EG_KERNELSPEC_CACHE_ENABLED env var)""",
3939
)
@@ -110,7 +110,7 @@ def get_item(self, kernel_name: str) -> Optional[KernelSpec]:
110110
)
111111
return kernelspec
112112

113-
def get_all_items(self) -> Optional[Dict[str, CacheItemType]]:
113+
def get_all_items(self) -> Dict[str, CacheItemType]:
114114
"""Retrieves all kernel specification from the cache.
115115
116116
If cache is disabled or no items are in the cache, an empty dictionary is returned;
@@ -140,6 +140,34 @@ def put_item(self, kernel_name: str, cache_item: Union[KernelSpec, CacheItemType
140140
kernel_name=kernel_name
141141
)
142142
)
143+
# Irrespective of cache enablement, add/update the 'metadata.client_envs' entry
144+
# with the set of configured values. If the stanza already exists in the kernelspec
145+
# update with the union of it and those values configured via `EnterpriseGatewayApp'.
146+
# We apply this logic here so that its only performed once for cached values or on
147+
# every retrieval when caching is not enabled.
148+
# Note: We only need to do this if we have a KernelSpec instance, since CacheItemType
149+
# instances will have already been modified.
150+
151+
# Create a set from the configured value, update it with the (potential) value
152+
# in the kernelspec, and apply the changes back to the kernelspec.
153+
154+
client_envs: Set[str] = set(self.parent.client_envs)
155+
kspec_client_envs: Set[str]
156+
if type(cache_item) is KernelSpec:
157+
kspec: KernelSpec = cache_item
158+
kspec_client_envs = set(kspec.metadata.get("client_envs", []))
159+
else:
160+
kspec_client_envs = set(cache_item["spec"].get("metadata", {}).get("client_envs", []))
161+
162+
client_envs.update(kspec_client_envs)
163+
if type(cache_item) is KernelSpec:
164+
kspec: KernelSpec = cache_item
165+
kspec.metadata["client_envs"] = list(client_envs)
166+
else:
167+
if "metadata" not in cache_item["spec"]:
168+
cache_item["spec"]["metadata"] = {}
169+
cache_item["spec"]["metadata"]["client_envs"] = list(client_envs)
170+
143171
if self.cache_enabled:
144172
if type(cache_item) is KernelSpec:
145173
cache_item = KernelSpecCache.kernel_spec_to_cache_item(cache_item)
@@ -159,9 +187,8 @@ def put_item(self, kernel_name: str, cache_item: Union[KernelSpec, CacheItemType
159187

160188
def put_all_items(self, kernelspecs: Dict[str, CacheItemType]) -> None:
161189
"""Adds or updates a dictionary of kernel specification in the cache."""
162-
if self.cache_enabled and kernelspecs:
163-
for kernel_name, cache_item in kernelspecs.items():
164-
self.put_item(kernel_name, cache_item)
190+
for kernel_name, cache_item in kernelspecs.items():
191+
self.put_item(kernel_name, cache_item)
165192

166193
def remove_item(self, kernel_name: str) -> Optional[CacheItemType]:
167194
"""Removes the cache item corresponding to kernel_name from the cache."""
@@ -212,7 +239,7 @@ def _initialize(self):
212239

213240
@staticmethod
214241
def kernel_spec_to_cache_item(kernelspec: KernelSpec) -> CacheItemType:
215-
"""Convets a KernelSpec instance to a CacheItemType for storage into the cache."""
242+
"""Converts a KernelSpec instance to a CacheItemType for storage into the cache."""
216243
cache_item = dict()
217244
cache_item["spec"] = kernelspec.to_dict()
218245
cache_item["resource_dir"] = kernelspec.resource_dir
@@ -221,7 +248,8 @@ def kernel_spec_to_cache_item(kernelspec: KernelSpec) -> CacheItemType:
221248
@staticmethod
222249
def cache_item_to_kernel_spec(cache_item: CacheItemType) -> KernelSpec:
223250
"""Converts a CacheItemType to a KernelSpec instance for user consumption."""
224-
return KernelSpec.from_resource_dir(cache_item["resource_dir"])
251+
kernel_spec = KernelSpec(resource_dir=cache_item["resource_dir"], **cache_item["spec"])
252+
return kernel_spec
225253

226254

227255
class KernelSpecChangeHandler(FileSystemEventHandler):

0 commit comments

Comments
 (0)