Skip to content

Commit 63e2840

Browse files
ZsailerGitHub Enterprise
authored andcommitted
Add Kernel restart, and move apple cert into Jupyter runtime dir (jupyter-server#57)
* enable kernel restart * add some comments, cleanup, etc * remove old env vars
1 parent bbfbc6e commit 63e2840

File tree

6 files changed

+53
-13
lines changed

6 files changed

+53
-13
lines changed

data_studio_jupyter_extensions/app.py

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import os
22
import pathlib
33

4+
from jupyter_core.paths import jupyter_runtime_dir
45
from jupyter_server.config_manager import recursive_update
56
from jupyter_server.extension.application import ExtensionApp
67
from jupyter_server.extension.application import ExtensionAppJinjaMixin
@@ -18,12 +19,23 @@
1819
from .telemetry.utils import DEFAULT_TEMPLATE_FILES_PATH
1920
from .telemetry.utils import get_schema_files
2021
from .traits import UnicodeFromEnv
22+
from .utils import get_ssl_cert
2123

2224

2325
MODE_CONFIG_PATH = pathlib.Path(__file__).parent.joinpath("config")
2426

2527

2628
class DataStudioJupyterExtensions(ExtensionAppJinjaMixin, ExtensionApp):
29+
"""JupyterLab with Data Studio extensions.
30+
31+
This extension bundles multiple Jupyter server and client extensions to
32+
ship a JupyterLab experience that serves Apple Data Scientists.
33+
34+
The application can be launched by calling:
35+
```
36+
DataStudioJupyterExtensions.launch_instance()
37+
```
38+
"""
2739

2840
name = "data_studio_jupyter_extensions"
2941
default_url = "/lab"
@@ -32,18 +44,36 @@ class DataStudioJupyterExtensions(ExtensionAppJinjaMixin, ExtensionApp):
3244
template_paths = [str(DEFAULT_TEMPLATE_FILES_PATH)]
3345
static_paths = [str(DEFAULT_STATIC_FILES_PATH)]
3446

47+
# Add configurables to the list of classes displayed
48+
# in the --help.
49+
classes = [NotebookServiceClient, TelemetryBus]
50+
3551
handlers = handlers
3652

3753
aliases = {"mode": "DataStudioJupyterExtensions.mode"}
3854

3955
mode = UnicodeFromEnv(
4056
default_value="local-local",
41-
help="The type",
57+
help="The mode describing how/where the application is being launched."
58+
"There are three option, 'local-local', 'local-cluster', or "
59+
"'cluster-cluster'. ",
4260
name=constants.NOTEBOOK_SERVICE_MODE,
4361
).tag(config=True)
4462

4563
mode_config_path = str(MODE_CONFIG_PATH)
4664

65+
ssl_cert_file = UnicodeFromEnv(
66+
name="DS_SSL_CERT_FILE",
67+
help="The Apple corporate SSL cert file necessary for accessing "
68+
"the Data Platform UI. If not given, this application will try to "
69+
"automatically download a new SSL cert to the Runtime directory.",
70+
allow_none=True,
71+
).tag(config=True)
72+
73+
@default("ssl_cert_file")
74+
def _default_ssl_cert_file(self): # pragma: no cover
75+
return get_ssl_cert(jupyter_runtime_dir())
76+
4777
# List configurables here.
4878
nbservice_client_class = Type(
4979
default_value=NotebookServiceClient,
@@ -96,8 +126,7 @@ def initialize_settings(self):
96126

97127
def initialize_configurables(self):
98128
self.nbservice_client = self.nbservice_client_class.instance(
99-
parent=self,
100-
log=self.log,
129+
parent=self, log=self.log, ssl_cert_file=self.ssl_cert_file
101130
)
102131
self.telemetry_bus = TelemetryBus.instance(
103132
allowed_schemas=["event.datastudio.jupyter.com/kernel-message"]

data_studio_jupyter_extensions/notebook_service.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import ssl
44
import urllib
55

6+
from jupyter_core.paths import jupyter_runtime_dir
67
from jupyter_server.utils import url_path_join as ujoin
78
from tornado.escape import json_decode
89
from tornado.httpclient import AsyncHTTPClient
@@ -44,7 +45,7 @@ class NotebookServiceClient(SingletonConfigurable):
4445

4546
@default("ssl_cert_file")
4647
def _default_ssl_cert_file(self): # pragma: no cover
47-
return get_ssl_cert()
48+
return get_ssl_cert(jupyter_runtime_dir())
4849

4950
http_client = Instance(AsyncHTTPClient).tag(config=True)
5051

data_studio_jupyter_extensions/provisioner.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,8 @@ async def terminate(self, restart: bool = False) -> None:
337337

338338
async def shutdown_requested(self, restart: bool = False) -> None:
339339
await self.nbservice_client.stop_kernel(self.process_id)
340+
if restart:
341+
self.process_id = None
340342

341343
async def pre_launch(self, **kwargs: Any) -> Dict[str, Any]:
342344
return await super().pre_launch(cmd=[], **kwargs)

data_studio_jupyter_extensions/traits.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,21 @@ class FromEnvMixin:
1717
# and prevents the dynamic default from working.
1818
default_value = Undefined
1919

20-
def __init__(self, name, *args, **kwargs):
20+
def __init__(self, name, help=None, *args, **kwargs):
2121
self.envvar_name = name
22+
# Prefix the "help" string in these type of traits
23+
# with some documentation that mentions the
24+
# environment variable.
25+
help_prefix = (
26+
f"(This trait is also configurable from the environment variable, {name}.) "
27+
)
28+
if not help:
29+
help = help_prefix
30+
else:
31+
help = help_prefix + help
2232
# The actual traittype is second in the MRO.
2333
traittype = self.__class__.mro()[2]
24-
traittype.__init__(self, *args, **kwargs)
34+
traittype.__init__(self, help=help, *args, **kwargs)
2535

2636
def make_dynamic_default(self):
2737
# Make sure to dynamically load the default when the

data_studio_jupyter_extensions/utils.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,13 @@
1313
from tenacity import stop_after_delay
1414
from tenacity import wait_exponential
1515

16+
1617
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
1718

1819

19-
def get_ssl_cert():
20-
"""Get Apple corproate SSL certificate, write
21-
to a temporary file and return that file name.
20+
def get_ssl_cert(path): # pragma: no cover
21+
"""Get Apple corporate SSL certificate, write
22+
to `path`.
2223
"""
2324
urls = [
2425
"https://certificatemanager.apple.com/certs/apple_corporate_root_ca.pem",
@@ -29,7 +30,7 @@ def get_ssl_cert():
2930
r = requests.get(url, verify=False)
3031
certs += r.text
3132

32-
fpath = pathlib.Path("apple_root_ca.pem")
33+
fpath = pathlib.Path(path).joinpath("apple_root_ca.pem")
3334
fpath.write_text(certs)
3435
return str(fpath.absolute())
3536

env.sh

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,3 @@ export ISSUER=https://iam.corp.apple.com
66
export KEY_URL=https://iam.corp.apple.com/oauth2/v3/certs
77
export AUDIENCE=notebook-server-int
88
export CLIENT_ID=d314ef93-a7b3-4451-b68d-51bd395ba7f2
9-
# export DS_PROCESS_ID=4p27l98hlgm9
10-
export DS_SPEC_ID=bkvgsydsi1rd
11-
export KG_LIST_KERNELS=True

0 commit comments

Comments
 (0)