Merge pull request #675 from minrk/api-info

Add /api/ and /api/info endpoints
This commit is contained in:
Kyle Kelley
2016-08-02 22:26:10 -05:00
committed by GitHub
4 changed files with 154 additions and 0 deletions

1
.gitignore vendored
View File

@@ -6,6 +6,7 @@ node_modules
build
dist
docs/_build
docs/source/_static/rest-api
.ipynb_checkpoints
# ignore config file at the top-level of the repo
# but not sub-dirs

View File

@@ -21,6 +21,60 @@ produces:
consumes:
- application/json
paths:
/:
get:
summary: See the version of JupyterHub itself
description: |
This endpoint is not authenticated,
so clients can identify the version of JupyterHub before setting up authentication.
responses:
'200':
description: The version of JupyterHub itself
schema:
type: object
properties:
version:
type: string
description: The version of JupyterHub itself
/info:
get:
summary: Get detailed info about JupyterHub
description: |
Detailed information about JupyterHub,
including information about Python, JupyterHub's version,
and what Authenticators and Spawners are in use.
responses:
'200':
schema:
type: object
properties:
version:
type: string
description: The version of JupyterHub itself
python:
type: string
description: The version of Python, as returned by sys.version
sys_executable:
type: string
description: The path to sys.executable running JupyterHub
authenticator:
type: object
properties:
class:
type: string
description: The Python class currently in use
version:
type: string
description: The version of the package providing the Authenticator class
spawner:
type: object
properties:
class:
type: string
description: The Python class currently in use for spawning single-user servers
version:
type: string
description: The version of the package providing the Spawner class
/users:
get:
summary: List users
@@ -332,6 +386,15 @@ paths:
/shutdown:
post:
summary: Shutdown the Hub
parameters:
- name: proxy
in: body
type: bool
description: Whether the proxy should be shutdown as well (default from Hub config)
- name: servers
in: body
type: bool
description: Whether users's servers should be shutdown as well (default from Hub config)
responses:
'200':
description: Hub has shutdown

View File

@@ -4,12 +4,15 @@
# Distributed under the terms of the Modified BSD License.
import json
import sys
from tornado import web
from tornado.ioloop import IOLoop
from ..utils import admin_only
from .base import APIHandler
from ..version import __version__
class ShutdownAPIHandler(APIHandler):
@@ -49,6 +52,56 @@ class ShutdownAPIHandler(APIHandler):
loop.add_callback(loop.stop)
class RootAPIHandler(APIHandler):
def get(self):
"""GET /api/ returns info about the Hub and its API.
It is not an authenticated endpoint.
For now, it just returns the version of JupyterHub itself.
"""
data = {
'version': __version__,
}
self.finish(json.dumps(data))
class InfoAPIHandler(APIHandler):
@admin_only
def get(self):
"""GET /api/info returns detailed info about the Hub and its API.
It is not an authenticated endpoint.
For now, it just returns the version of JupyterHub itself.
"""
def _class_info(typ):
"""info about a class (Spawner or Authenticator)"""
info = {
'class': '{mod}.{name}'.format(mod=typ.__module__, name=typ.__name__),
}
pkg = typ.__module__.split('.')[0]
try:
version = sys.modules[pkg].__version__
except (KeyError, AttributeError):
version = 'unknown'
info['version'] = version
return info
data = {
'version': __version__,
'python': sys.version,
'sys_executable': sys.executable,
'spawner': _class_info(self.settings['spawner_class']),
'authenticator': _class_info(self.authenticator.__class__),
}
self.finish(json.dumps(data))
default_handlers = [
(r"/api/shutdown", ShutdownAPIHandler),
(r"/api/?", RootAPIHandler),
(r"/api/info", InfoAPIHandler),
]

View File

@@ -3,12 +3,14 @@
import json
import time
from queue import Queue
import sys
from urllib.parse import urlparse, quote
import requests
from tornado import gen
import jupyterhub
from .. import orm
from ..user import User
from ..utils import url_path_join as ujoin
@@ -657,6 +659,41 @@ def test_group_delete_users(app):
assert sorted([ u.name for u in group.users ]) == sorted(names[2:])
def test_root_api(app):
base_url = app.hub.server.url
url = ujoin(base_url, 'api')
r = requests.get(url)
r.raise_for_status()
expected = {
'version': jupyterhub.__version__
}
assert r.json() == expected
def test_info(app):
r = api_request(app, 'info')
r.raise_for_status()
data = r.json()
assert data['version'] == jupyterhub.__version__
assert sorted(data) == [
'authenticator',
'python',
'spawner',
'sys_executable',
'version',
]
assert data['python'] == sys.version
assert data['sys_executable'] == sys.executable
assert data['authenticator'] == {
'class': 'jupyterhub.tests.mocking.MockPAMAuthenticator',
'version': jupyterhub.__version__,
}
assert data['spawner'] == {
'class': 'jupyterhub.tests.mocking.MockSpawner',
'version': jupyterhub.__version__,
}
# general API tests
def test_options(app):