Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for named server #68

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,17 @@ With a JupyterHub [SSH](https://www.ssh.com/ssh) server deployed, you can start
[SFTP](https://www.ssh.com/ssh/sftp) server deployed alongside the JupyterHub's user storage, you can use SFTP to work against your JupyterHub user's home directory.
These services are authenticated using an access token acquired from your JupyterHub's user interface under `/hub/token`.

## What does this fork have?
This project a forked project from yuvipanda/jupyterhub_ssh and I was able to directly contribute to create a fork to support one small feature.

Current jupyterhub-ssh by yuvipanda only supports ssh connection to unnamed server. I added few lines to support named server as well.

The way it'd work is if you have a named server, you'd simply do `ssh user-namedserver@hub_url`

It does create the named server automactically if it doesn't exist, which you'll be able to view in the JupyterHub UI as well.

All the other features remain the same and you can still connect to unnamed server by just `user@hub_url`

## Development Status

This project is under active develpoment :tada:, so expect a few changes along the way.
Expand Down Expand Up @@ -204,3 +215,8 @@ proxy:
4. Enter the token received from JupyterHub as a password.

5. TADA :tada: Now you can transfer files to and from your home directory on the hubs.


# Disclaimer
I do not own this project. Please look at official project at https://github.com/yuvipanda/jupyterhub-ssh
I just added a few lines of code to support named servers.
35 changes: 31 additions & 4 deletions jupyterhub_ssh/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,23 +40,43 @@ async def get_user_server_url(self, session, username):

Else return None
"""
# Checking if username has any dash char "-" which would be then have the name of the named server the user wants to connect to
# For example username would look like admin-mytestserver. Any characters can be used here but chose - just for the sake of it
# If the server name itself has "-" then we would need to split only once. Splitting with split(char, #Occurrence)
dash_char = "-"
server_name = ""
if dash_char in username:
username_with_server = username.split(dash_char, 1)
username = username_with_server[0]
server_name = username_with_server[1]
async with session.get(self.app.hub_url / "hub/api/users" / username) as resp:
if resp.status != 200:
return None
user = await resp.json()
print(user)
# URLs will have preceding slash, but yarl forbids those
server = user.get("servers", {}).get("", {})
if server.get("ready", False):
return self.app.hub_url / user["servers"][""]["url"][1:]
return self.app.hub_url / user["servers"][server_name if server_name!="" else ""]["url"][1:]
else:
return None

async def start_user_server(self, session, username):
""" """
# REST API reference: https://jupyterhub.readthedocs.io/en/stable/_static/rest-api/index.html#operation--users--name--server-post
# REST API implementation: https://github.com/jupyterhub/jupyterhub/blob/187fe911edce06eb067f736eaf4cc9ea52e69e08/jupyterhub/apihandlers/users.py#L451-L497
create_url = self.app.hub_url / "hub/api/users" / username / "server"

# Checking if username has any dash char "-" which would be then have the name of the named server the user wants to connect to
# For example username would look like admin-mytestserver. Any characters can be used here but chose - just for the sake of it
# If the server name itself has "-" then we would need to split only once. Splitting with split(char, #Occurrence)dash_char = "-"
server_name = ""
if dash_char in username:
username_with_server = username.split(dash_char, 1)
username = username_with_server[0]
server_name = username_with_server[1]

if server_name:
create_url = self.app.hub_url / "hub/api/users" / username / "servers" / server_name
else:
create_url = self.app.hub_url / "hub/api/users" / username / "server"

async with session.post(create_url) as resp:
if resp.status == 201 or resp.status == 400:
Expand All @@ -68,6 +88,8 @@ async def start_user_server(self, session, username):
# We manually generate this, even though it's *bad*
# Mostly because when the server is already running, JupyterHub
# doesn't respond with the whole model!
if server_name:
return self.app.hub_url / "user" / username / server_name
return self.app.hub_url / "user" / username
elif resp.status == 202:
# Server start has been requested, now and potentially earlier,
Expand All @@ -81,6 +103,10 @@ async def start_user_server(self, session, username):
while notebook_url is None:
# FIXME: Exponential backoff + make this configurable
await asyncio.sleep(0.5)
if server_name:
notebook_url = await self.get_user_server_url(
session, username + "/" + server_name
)
notebook_url = await self.get_user_server_url(
session, username
)
Expand Down Expand Up @@ -152,6 +178,7 @@ async def _handle_client(self, stdin, stdout, stderr):
"""
Handle data transfer once session has been fully established.
"""
print ("Notebook URL looks like: ", self.notebook_url)
async with ClientSession() as client, Terminado(
self.notebook_url, self.token, client
) as terminado:
Expand Down