Skip to content

Commit 6309798

Browse files
ZsailerGitHub Enterprise
authored and
GitHub Enterprise
committed
remove unused code for testing locally (jupyter-server#405)
1 parent 2a5f6db commit 6309798

File tree

10 files changed

+56
-257
lines changed

10 files changed

+56
-257
lines changed

Makefile

-4
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,6 @@ test: test-python
3131
check-manifest -v
3232
pre-commit run --all-files
3333

34-
run-remote:
35-
test -f myenv.sh && source myenv.sh && jupyter datastudio --mode local-cluster
36-
test -f myenv.sh || echo "no myenv.sh found" && jupyter datastudio --mode local-cluster
37-
3834
run-local:
3935
export DATASTUDIO_NOTEBOOK_ID="local-notebook"; jupyter datastudio --mode local-local --ServerApp.open_browser=False
4036

conftest.py

+35
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
import pytest
44
from jupyter_server.serverapp import ServerApp
5+
from jwcrypto.jwk import JWK
6+
from jwcrypto.jwt import JWT
57

68
from data_studio_jupyter_extensions import constants
79
from data_studio_jupyter_extensions.app import DS_JUPYTER_SERVER_CONFIG_OVERRIDES
@@ -133,3 +135,36 @@ def mock_kernelspec():
133135
resource_dir="Unicode()",
134136
metadata={},
135137
)
138+
139+
140+
@pytest.fixture
141+
def json_web_key():
142+
return {
143+
"d": "AjY--3WmGQNg5B7qouRlFmezMT5yrSyg8P3nbB29tb9xlnuKlvRpXbw0Ty2O3WTwjKMyjDADSRoJq9mqhHwB7TVFGfOdThWad8rroIKy66zAFcV0KTB5D24WQWO-gkn5o90m6qTAj3-xsalaedyXLdoBHz3RXnxm_wY0Yk7NmtXIu0H28DgGD8xJQ5HxGN3-7foRarB2O0XjV2nvH_a3YY9bSvT57hKeywqbOT22sLy5jg2xF8-VlksYn7IVOHlc13WImuV2FH8Lk2dMmyXwXEkIngZ-KmR3rqGO7aXLXPmTqADgI2TlLQZwpT2YJggMLq8XHpKz2TQ60Ac8wkhHZy_nlNogC_oaeUQw5dJzabF5MHoikDgdTNmz7wHoDOo8y4okR7rkFwoxte7NdvQOk1abQwJOMMXn5IQrnkYdGJ5hJlXSYPB6fyPxZItLj9GnukNvtFoOyudjtlPi8wRRQqQnMVgfYInl9KBMJsTNi86uUv39mE6yXftCIiqMLJI_zqOprOvDrkE2MGm_D_N5axTIVxNL044SvjLDuJ5aixCJkGpnOlAufmAEWCriKfGmCNsB44n75EwOy0Vkpp2Vimac51IcL1ldGV_8CuF5jDwdV4vzbg4Zy7bphwvXm6av5GBJ0XhFZSFCgDh9v9RvtW1AJ48na-3jL7BI0SA4oJE",
144+
"dp": "GnBb1FW583tVk74jQ-yYnzvMwY_LMP7Sl0UealGFthWBQkhH9blw8FDGHM-WDlpP9RUByzdrVjeQyy6GZ7ir1Ckb5MgwRfZw0reqeC_TJCUJZPcpFUwIavTuLxqlX4Kis5DpYGu6oZ73V3OoKs4HajbtRaXRJ8gPldHJ-PW7APsOIjmPh450j1EgtXOwns1IaexY3DTg2CxbwA2_E5O7XrugL6IYNRdrQ3u_foH6XulidfT77JwSt63UoawXZYsUJpyr_axPm9fSCwSd5A9hwYlaQTsngOO7Sg1umTqJgZ5gXdZs8pDiRAT7gIG7hOfWT5on3W3PiPvoxLI3Xck50Q",
145+
"dq": "MP69nX6s8stmGqi10ATwTx36Xrqvnad9vLTqEDorKSZD8AKaRqFcRVdzRPFaG3h0B-G1Bmlye_-x_Rja2irUttWZOZlV647tIPziPWyydi__YRScli_OnN75W9jK6pQ5HO6pQPun5lf0_kpYDGOC2hHFaTip84BzJl1JozxSAHYMUR6sm8uWhRNcmHN9Ln37vgSx3LiCu0rZwdFXsIgHw61TWPEo27ECZI6QziFq9OjnVgPH7VjuMEcNcT6fw5M3aHZMiBTbbpy2m1d3HckbkImOn64VMAr_sfItP5-KrB8uoGU1A4gSVAKwF3Yp9bBPApfwFI3GCCVF8xyDktl49w",
146+
"e": "AQAB",
147+
"kid": "5RoiFp22GMfkoZmLENDLdjN5eAaYgJKzlPY867ffcgA",
148+
"kty": "RSA",
149+
"n": "3KQeRymFIOqILq7bsCJIAd2Nz4sS8hdskH_3b4DoCD4VyqsVn8HH8pWklMtp91n8t9DsquKSKdGLD7erHW2m2quRCT2qKOCnUGtRNxFQBhsuklQjUa8M0hQjpNJfFmYPhfVk1vUrWVQ9UElOywiWk7-yjjLkdAbP2YC-WU2BnMpy9oesr7eiah7OdV1i5Yo_HNVKt94R0hFiTzTQCIKqxjrHn3i_VlO486_V27z0GLWw0I8PAKdQnCBPBI-_iP6QfZ0NziaQ7ud66iGDfIK7HovYqxlm0qhbmyyjV_Ps0Tf3Q53dCV1ZMuT8XmODKoxbdo9Qhr_fO6WbkiNgDm6JvDuXc5za0SlQbFD6P9iXTLwamV-p8itka9mP_1qAL6CedOzDGcdorDaGdUpEVXKWhLilazB5X_qVbHRJX8Rl7dqKk4iUNq54HxRbkN0XKTARMeyJV17sh0V3Ao2qNoqf6NhCOVTAzX__qu2-hHEsZWHxnc2bo6ya9EFRPgpGrwbMQ4hQMN5eNfENyL8C-EonJU9xti9UwqHmj5nTYvo_vsoA9FFJSMAQFYAqztdYUOAHqhqZAr-UxpcWRg8oE0SUEk5TBZppOKEfq3Zn6Y9-kF7i4MxT19TxJ8Al8ErV-ilnMKVSnWtxBp5F6uLI2yPuTWZx0xNcq9VKPhwWHqKxlJs",
150+
"p": "_KhcwBOlQwP_EdUcEs74dAiCs38rZ8YzJMuULH5SQffDXswyZNb2lYclUCu095PVRf1rcLQE_Qwh2QDhZlIbNNFXWFKcQ3E1uMuPaUcflDOSLdw9rxz01p2Rzpuai-h9p-PQkVMO6D5zEAORv5P6oj4-u83JHKOgD5R8VRkofaaHBzr4WhxfxuAfTZV3eFgQ_gM9UHiJQmpPJvPMYvN-MDDvUuFPVJKj6BKgTIEKaRu_xSY4WeMoOyYpV3NirvCb8pemzB_aFG9PUUB2lMPRvyoGN-VzDHBwzJaIkqtds2Wux-MjDSImQh5LAvUs97Bi00w0ixMS1-NloZhgwYiuyQ",
151+
"q": "349UipnuqoGqKaZ_mBoZfRvZXwAqo9qhhVBqdnWpC2EIeJqbViul7qKGt7Npue19gHMoDTvHRof1P6m7paD6_FDrisQ6nq44SQqOPNSrOqFCjfuApZ-o9jUeTACenl1s-eHqyJpL7azAiN-Mn4x9XRFnhOlnHMGuvS_teQoFZYqy-DFwEK-13aJQPQeIZ0phx7iPnKh1aw8LQjLS9SP0lnNNF3uROUzpBIbFP4JmGWn3LQZBSkAe9pfsU_xhyJ8umljQlAgebuafhZ_nSH4Sh7qLXeOtDSOpCa0I4_Ej8bPxPAtupOMtQWmtg-GVKbGyF2bD0YyVwJJDDyP2XSomQw",
152+
"qi": "ywRu8HqEgqhmbM4EDbspHWFbN4CKJcYQWyi6Mf4Ws6YVSYd-RLbOVw5j6BHVOtZD7Hx6Bzcke6uiY46BYJmyOXb40qNyg8NwqN1TOiQHWBBwqUHLFC58Hg6jT2eeM964b5jv8IEiuAgH3PG8t79SrVJEEazjyzweiqtF79Rj7KZjxASKvyayF_oAOETNbnhcqJkfu0ZRdVrp71vJkFO3Sje8TrsLM3QKFzZyo-R8gGQGSm29aHQqSUH43sUohLLibaWttp2yDbofcPvw6bigweMgdDhbh8qu4WV25Ng8gK__ThTC26I9xwMlriiJhWR3HWfvaH5WZjMPU-A0PMhI4A",
153+
}
154+
155+
156+
@pytest.fixture
157+
def json_web_token(json_web_key):
158+
"""JSON web token, generated using"""
159+
key = JWK(**json_web_key)
160+
jwt = JWT(
161+
header={"alg": "RS256"},
162+
default_claims={"exp": None},
163+
claims={
164+
"client_id": "client_id",
165+
"aud": "notebook-server",
166+
"iss": "iam.corp.apple.com",
167+
},
168+
)
169+
jwt.make_signed_token(key)
170+
return jwt.serialize()

data_studio_jupyter_extensions/configurables/notebook_service.py

+3-54
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import base64
21
import json
32
import secrets
43
import ssl
@@ -49,7 +48,7 @@ class NotebookServiceClient(RefreshTokenConfigurable):
4948
client_secret = UnicodeFromEnv(name="IAS_CLIENT_SECRET", allow_none=True).tag(
5049
config=True
5150
)
52-
request_token = Unicode(allow_none=True)
51+
request_token = Unicode(allow_none=True).tag(config=True)
5352

5453
request_timeout = IntFromEnv(
5554
name=constants.DS_API_REQUEST_TIMEOUT, default_value=120, allow_none=True
@@ -61,43 +60,6 @@ class NotebookServiceClient(RefreshTokenConfigurable):
6160
def _default_http_client(self): # pragma: no cover
6261
return AsyncHTTPClient()
6362

64-
async def fetch_token(self): # pragma: no cover
65-
# From DS-INT UI
66-
# These were all in data-platform-ui/config/dsp-ui-dev.json
67-
scope = "openid offline corpds:ds:dsid corpds:ds:firstName corpds:ds:lastName corpds:ds:email"
68-
audience = "notebook-service-int datastudio-int"
69-
mayActSub = "2320309053"
70-
url = "https://iam.corp.apple.com/oauth2/token"
71-
data = dict(
72-
scope=scope,
73-
audience=audience,
74-
subject_token=self.api_token,
75-
grant_type="urn:ietf:params:oauth:grant-type:token-exchange",
76-
subject_token_type="urn:ietf:params:oauth:token-type:id_token",
77-
requested_token_type="urn:ietf:params:oauth:token-type:id_token",
78-
may_act_sub=mayActSub,
79-
)
80-
81-
encoded = base64.b64encode(
82-
f"{self.client_id}:{self.client_secret}".encode("utf-8")
83-
).decode("utf-8")
84-
headers = {
85-
"Content-Type": "application/x-www-form-urlencoded",
86-
"Authorization": "Basic " + encoded,
87-
}
88-
request = HTTPRequest(
89-
url=url,
90-
method="POST",
91-
headers=headers,
92-
body=urllib.parse.urlencode(data),
93-
allow_nonstandard_methods=True,
94-
ca_certs=self.ssl_cert_file,
95-
)
96-
response = await self.http_client.fetch(request)
97-
resp_body = json.loads(response.body)
98-
token = resp_body["access_token"]
99-
return token
100-
10163
def get_headers(self, trace_id=None):
10264
"""Get the headers needed for a request"""
10365
headers = {
@@ -138,7 +100,7 @@ async def fetch(self, *parts, method="GET", data=None):
138100
if self.local_mode:
139101
self.request_token = ""
140102
elif not self.request_token:
141-
self.request_token = await self.fetch_token()
103+
raise Exception("No request token has been set. Try logging in again.")
142104
elif not self.is_token_valid(self.request_token):
143105
self.request_token = await self.fetch_id_token_from_refresh_token()
144106

@@ -153,12 +115,7 @@ async def fetch(self, *parts, method="GET", data=None):
153115
request = self._get_request(url, method=method, data=data)
154116
response = await self.http_client.fetch(request)
155117
except HTTPClientError as err:
156-
# Fresh token
157-
if err.code == 401 and not self.local_mode:
158-
self.request_token = await self.fetch_token()
159-
request = self._get_request(url, method=method, data=data)
160-
response = await self.http_client.fetch(request)
161-
elif err.code >= 500:
118+
if err.code >= 500:
162119
# Get response from notebook service
163120
response = err.response
164121
code = err.code
@@ -249,11 +206,3 @@ async def initialize_namespace_for_spark_kernels(
249206
async def get_profile_properties(self, kerneltype_id): # pragma: no cover
250207
"""Get profile properties by kernel type Id."""
251208
raise NotImplementedError
252-
253-
254-
if __name__ == "__main__": # pragma: no cover
255-
import asyncio
256-
257-
nbservice = NotebookServiceClient()
258-
r = asyncio.run(nbservice.get_list_of_kernelspecs_for_notebook())
259-
print(r)

data_studio_jupyter_extensions/configurables/provisioner.py

+1-133
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
captured by the client and rendered in the notebook status bar.
55
"""
66
import asyncio
7-
import os
8-
import socket
97
import time
108
from typing import Any
119
from typing import Dict
@@ -15,9 +13,6 @@
1513

1614
from jupyter_client import provisioning
1715
from jupyter_client.connect import KernelConnectionInfo
18-
from kubernetes_asyncio import client as kclient
19-
from kubernetes_asyncio import config as kconfig
20-
from kubernetes_asyncio.client.api_client import ApiClient
2116
from tornado.escape import json_decode
2217
from tornado.httpclient import HTTPClientError
2318
from tornado.web import HTTPError
@@ -39,7 +34,6 @@
3934
from data_studio_jupyter_extensions.traits import IntFromEnv
4035
from data_studio_jupyter_extensions.traits import UnicodeFromEnv
4136
from data_studio_jupyter_extensions.utils import get_available_mode_names
42-
from data_studio_jupyter_extensions.utils import run_async
4337

4438

4539
class KernelFailedError(Exception):
@@ -127,118 +121,6 @@ def connection_info(self) -> KernelConnectionInfo:
127121
)
128122
return info
129123

130-
async def _run_kube_method(
131-
self, method_type, name, quiet=False
132-
): # pragma: no cover
133-
if not quiet:
134-
self.log.debug(f"{method_type}ing service {name}")
135-
await kconfig.load_kube_config()
136-
137-
# use the context manager to close http sessions automatically
138-
async with ApiClient() as api:
139-
140-
v1 = kclient.CoreV1Api(api)
141-
method = getattr(v1, f"{method_type}_namespaced_service")
142-
return await method(namespace=self.namespace, name=name)
143-
144-
async def open_route(self, process_id): # pragma: no cover
145-
"""Connect to a remote kernel given by a process id
146-
Returns a map of port by port name
147-
148-
Prerequisites:
149-
kcli init
150-
151-
Representative url:
152-
https://ds-int.apple.com/projects/2j1cd6f8ekj1/notebooks/servers/p4xpnb1208u4/kernels/launch?notebookName=Untitled.ipynb&kernelspecId=bkvgsydsi1rd&kernelspecDisplayName=Python+3&kernelspecLang=python&kernelId=vhz7kghpaujd
153-
154-
The process id is the kernelId in the above url
155-
156-
Used them when launching the kernel instead of using the env variables
157-
only if LOCAL_MODE is set
158-
"""
159-
logger = self.log
160-
here = os.path.abspath(os.path.dirname(__file__))
161-
162-
# First check if the kernel is already set up and accessible
163-
try:
164-
name = f"ipython-{process_id}-kernel-service-iopub"
165-
ret = await self._run_kube_method("read", name)
166-
ip = ret.spec.external_i_ps[0]
167-
168-
message = f"Connecting to running kernel for {process_id}"
169-
self._emit_kernel_message(message)
170-
connected = True
171-
except Exception as e:
172-
logger.error(str(e))
173-
connected = False
174-
175-
# Create the connection if needed
176-
if not connected:
177-
message = f"Creating a connection to kernel: {process_id}"
178-
self._emit_kernel_message(message)
179-
180-
# Remove the root service and network policy created by notebook-service
181-
name = f"ipython-{process_id}-kernel-service"
182-
try:
183-
await self._run_kube_method("delete", name)
184-
except Exception as e:
185-
logger.error(e)
186-
187-
cmd = f"kubectl delete AppleNetworkPolicy ipython-{process_id}"
188-
await run_async(cmd, logger)
189-
190-
# Install the helm chart
191-
cmd = "helm uninstall remote-kernel"
192-
await run_async(cmd, logger)
193-
194-
helm_file = os.path.abspath(os.path.join(here, "..", "helm"))
195-
cmd = f"helm install --set process={process_id} remote-kernel {helm_file}"
196-
ret = await run_async(cmd, logger)
197-
assert ret == 0, "Could not run helm install"
198-
199-
# Get the port map
200-
ports = {}
201-
annotation = "pie.traffic.plb/tcp_service_port"
202-
203-
for name in ["hb", "control", "iopub", "shell", "stdin"]:
204-
service = f"ipython-{process_id}-kernel-service-{name}"
205-
self._emit_kernel_message(f"> {cmd}")
206-
attempts = 0
207-
while attempts < 100:
208-
ret = await self._run_kube_method("read", service, quiet=True)
209-
port = ret.metadata.annotations.get(annotation, "")
210-
if port:
211-
ports[name] = int(port)
212-
break
213-
await asyncio.sleep(0.1)
214-
if attempts == 10:
215-
raise ValueError(f"Could not find port for {name}")
216-
217-
# Establish a connection to the shell and iopub ports
218-
name = f"ipython-{process_id}-kernel-service-iopub"
219-
ret = await self._run_kube_method("read", name)
220-
ip = ret.spec.external_i_ps[0]
221-
222-
for name in ["shell", "iopub"]:
223-
port = ports[name]
224-
location = (ip, port)
225-
attempts = 0
226-
message = f"Connecting to {name} on {ip}:{port}"
227-
self._emit_kernel_message(message)
228-
allowed_attempts = 6000
229-
while attempts < allowed_attempts:
230-
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
231-
sock.settimeout(0.1)
232-
result = sock.connect_ex(location)
233-
if result == 0:
234-
break
235-
attempts += 1
236-
await asyncio.sleep(0.1)
237-
if attempts == allowed_attempts:
238-
raise ValueError(f"Could not connect to port for {name}")
239-
240-
return ip, ports
241-
242124
@property
243125
def has_process(self) -> bool:
244126
"""
@@ -403,22 +285,8 @@ async def pre_launch(self, **kwargs: Any) -> Dict[str, Any]:
403285

404286
async def _fetch_connection_info(self) -> None:
405287
"""
406-
Fetch connection info from notebook-service (or the control
407-
plane in local-cluster mode).
288+
Fetch connection info from notebook-service
408289
"""
409-
if self.mode == "local-cluster":
410-
# Ports and host will depend on the ingress routes
411-
# set by the kubernetes cluster.
412-
host, port_map = await self.open_route(self.process_id)
413-
# set up the connection info
414-
self.iopub_port = port_map["iopub"]
415-
self.hb_port = port_map["hb"]
416-
self.control_port = port_map["control"]
417-
self.shell_port = port_map["shell"]
418-
self.stdin_port = port_map["stdin"]
419-
self.ip = self.ip or host
420-
return
421-
422290
r = await self.nbservice_client.get_kernel_details(self.process_id)
423291
kernel_info = json_decode(r.body)
424292
self.ip = self.ip or kernel_info["host"]

data_studio_jupyter_extensions/modes/local_cluster.py

-4
This file was deleted.

data_studio_jupyter_extensions/tests/auth/conftest.py

-36
This file was deleted.

0 commit comments

Comments
 (0)