Handle named servers in UserSpawnHandler, home, admin pages

Made CSS and HTML (and Jinja2) of admin page compatible with named servers.
This commit is contained in:
William Krinsman
2018-08-15 15:11:43 -07:00
committed by Min RK
parent 571ca2dec6
commit 02cb5ec076
9 changed files with 388 additions and 66 deletions

View File

@@ -20,7 +20,7 @@ from sqlalchemy.exc import SQLAlchemyError
from tornado.log import app_log
from tornado.httputil import url_concat, HTTPHeaders
from tornado.ioloop import IOLoop
from tornado.web import RequestHandler
from tornado.web import RequestHandler, MissingArgumentError
from tornado import gen, web
from .. import __version__
@@ -854,10 +854,10 @@ class BaseHandler(RequestHandler):
await self.proxy.delete_user(user, server_name)
await user.stop(server_name)
async def stop_single_user(self, user, name=''):
if name not in user.spawners:
raise KeyError("User %s has no such spawner %r", user.name, name)
spawner = user.spawners[name]
async def stop_single_user(self, user, server_name=''):
if server_name not in user.spawners:
raise KeyError("User %s has no such spawner %r", user.name, server_name)
spawner = user.spawners[server_name]
if spawner.pending:
raise RuntimeError("%s pending %s" % (spawner._log_name, spawner.pending))
# set user._stop_pending before doing anything async
@@ -873,8 +873,8 @@ class BaseHandler(RequestHandler):
"""
tic = IOLoop.current().time()
try:
await self.proxy.delete_user(user, name)
await user.stop(name)
await self.proxy.delete_user(user, server_name)
await user.stop(server_name)
finally:
spawner._stop_pending = False
toc = IOLoop.current().time()
@@ -885,7 +885,7 @@ class BaseHandler(RequestHandler):
await gen.with_timeout(timedelta(seconds=self.slow_stop_timeout), stop())
except gen.TimeoutError:
# hit timeout, but stop is still pending
self.log.warning("User %s:%s server is slow to stop", user.name, name)
self.log.warning("User %s:%s server is slow to stop", user.name, server_name)
#---------------------------------------------------------------
# template rendering
@@ -1019,7 +1019,7 @@ class PrefixRedirectHandler(BaseHandler):
class UserSpawnHandler(BaseHandler):
"""Redirect requests to /user/name/* handled by the Hub.
"""Redirect requests to /user/user_name/* handled by the Hub.
If logged in, spawn a single-user server and redirect request.
If a user, alice, requests /user/bob/notebooks/mynotebook.ipynb,
@@ -1035,21 +1035,21 @@ class UserSpawnHandler(BaseHandler):
self.write(json.dumps({"message": "%s is not running" % user.name}))
self.finish()
async def get(self, name, user_path):
async def get(self, user_name, user_path):
if not user_path:
user_path = '/'
current_user = self.current_user
if (
current_user
and current_user.name != name
and current_user.name != user_name
and current_user.admin
and self.settings.get('admin_access', False)
):
# allow admins to spawn on behalf of users
user = self.find_user(name)
user = self.find_user(user_name)
if user is None:
# no such user
raise web.HTTPError(404, "No such user %s" % name)
raise web.HTTPError(404, "No such user %s" % user_name)
self.log.info("Admin %s requesting spawn on behalf of %s",
current_user.name, user.name)
admin_spawn = True
@@ -1059,7 +1059,7 @@ class UserSpawnHandler(BaseHandler):
admin_spawn = False
# For non-admins, we should spawn if the user matches
# otherwise redirect users to their own server
should_spawn = (current_user and current_user.name == name)
should_spawn = (current_user and current_user.name == user_name)
if "api" in user_path.split("/") and not user.active:
# API request for not-running server (e.g. notebook UI left open)
@@ -1071,7 +1071,7 @@ class UserSpawnHandler(BaseHandler):
# if spawning fails for any reason, point users to /hub/home to retry
self.extra_error_html = self.spawn_home_error
# If people visit /user/:name directly on the Hub,
# If people visit /user/:user_name directly on the Hub,
# the redirects will just loop, because the proxy is bypassed.
# Try to check for that and warn,
# though the user-facing behavior is unchanged
@@ -1087,7 +1087,11 @@ class UserSpawnHandler(BaseHandler):
""", self.request.full_url(), self.proxy.public_url)
# logged in as valid user, check for pending spawn
spawner = user.spawner
if self.allow_named_servers:
server_name = self.get_argument('server', '')
else:
server_name = ''
spawner = user.spawners[server_name]
# First, check for previous failure.
if (
@@ -1152,7 +1156,7 @@ class UserSpawnHandler(BaseHandler):
{'next': self.request.uri}))
return
else:
await self.spawn_single_user(user)
await self.spawn_single_user(user, server_name)
# spawn didn't finish, show pending page
if spawner.pending:
@@ -1208,7 +1212,7 @@ class UserSpawnHandler(BaseHandler):
url_parts = urlparse(target)
query_parts = parse_qs(url_parts.query)
query_parts['redirects'] = redirects + 1
url_parts = url_parts._replace(query=urlencode(query_parts))
url_parts = url_parts._replace(query=urlencode(query_parts, doseq=True))
target = urlunparse(url_parts)
else:
target = url_concat(target, {'redirects': 1})
@@ -1276,7 +1280,7 @@ class AddSlashHandler(BaseHandler):
default_handlers = [
(r'', AddSlashHandler), # add trailing / to `/hub`
(r'/user/([^/]+)(/.*)?', UserSpawnHandler),
(r'/user/(?P<user_name>[^/]+)(?P<user_path>/.*)?', UserSpawnHandler),
(r'/user-redirect/(.*)?', UserRedirectHandler),
(r'/security/csp-report', CSPReportHandler),
]