mirror of
https://github.com/jupyterhub/jupyterhub.git
synced 2025-10-16 14:33:00 +00:00
Unified service model
This commit is contained in:
@@ -298,10 +298,17 @@ class APIHandler(BaseHandler):
|
||||
'name': service.name,
|
||||
'roles': [r.name for r in service.roles],
|
||||
'admin': service.admin,
|
||||
'url': getattr(service, 'url', ''),
|
||||
'prefix': service.server.base_url if getattr(service, 'server', '') else '',
|
||||
'command': getattr(service, 'command', ''),
|
||||
'pid': service.proc.pid if getattr(service, 'proc', '') else 0,
|
||||
'info': getattr(service, 'info', ''),
|
||||
'display': getattr(service, 'display', ''),
|
||||
}
|
||||
# todo: remove admin key now we have roles?
|
||||
# todo: More default keys present?
|
||||
access_map = {
|
||||
'read:services': {'kind', 'name', 'roles', 'admin'},
|
||||
'read:services': set(model.keys()),
|
||||
'read:services:name': {'kind', 'name'},
|
||||
'read:services:roles': {'kind', 'name', 'roles'},
|
||||
}
|
||||
|
@@ -6,34 +6,16 @@ Currently GET-only, no actions can be taken to modify services.
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
import json
|
||||
|
||||
from tornado import web
|
||||
|
||||
from .. import orm
|
||||
from ..scopes import needs_scope
|
||||
from .base import APIHandler
|
||||
|
||||
|
||||
def service_model(service):
|
||||
"""Produce the model for a service"""
|
||||
return {
|
||||
'name': service.name,
|
||||
'admin': service.admin,
|
||||
'roles': [r.name for r in service.roles],
|
||||
'url': service.url,
|
||||
'prefix': service.server.base_url if service.server else '',
|
||||
'command': service.command,
|
||||
'pid': service.proc.pid if service.proc else 0,
|
||||
'info': service.info,
|
||||
'display': service.display,
|
||||
}
|
||||
|
||||
|
||||
class ServiceListAPIHandler(APIHandler):
|
||||
@needs_scope('read:services')
|
||||
@needs_scope('read:services', 'read:services:name', 'read:services:roles')
|
||||
def get(self):
|
||||
scope_filter = self.get_scope_filter('read:services')
|
||||
data = {
|
||||
name: service_model(service)
|
||||
name: self.service_model(service)
|
||||
for name, service in self.services.items()
|
||||
if scope_filter(service, kind='service')
|
||||
}
|
||||
@@ -41,10 +23,10 @@ class ServiceListAPIHandler(APIHandler):
|
||||
|
||||
|
||||
class ServiceAPIHandler(APIHandler):
|
||||
@needs_scope('read:services')
|
||||
@needs_scope('read:services', 'read:services:name', 'read:services:roles')
|
||||
def get(self, service_name):
|
||||
service = self.services[service_name]
|
||||
self.write(json.dumps(service_model(service)))
|
||||
self.write(json.dumps(self.service_model(service)))
|
||||
|
||||
|
||||
default_handlers = [
|
||||
|
@@ -1606,6 +1606,7 @@ async def test_get_services(app, mockservice_url):
|
||||
services = r.json()
|
||||
assert services == {
|
||||
mockservice.name: {
|
||||
'kind': 'service',
|
||||
'name': mockservice.name,
|
||||
'admin': True,
|
||||
'roles': ['admin'],
|
||||
@@ -1631,6 +1632,7 @@ async def test_get_service(app, mockservice_url):
|
||||
|
||||
service = r.json()
|
||||
assert service == {
|
||||
'kind': 'service',
|
||||
'name': mockservice.name,
|
||||
'admin': True,
|
||||
'roles': ['admin'],
|
||||
|
@@ -763,13 +763,39 @@ async def test_resolve_token_permissions(
|
||||
assert token_retained_scopes == intersection_scopes
|
||||
|
||||
|
||||
@mark.parametrize(
|
||||
"scopes, model_keys",
|
||||
[
|
||||
(
|
||||
{'read:services'},
|
||||
{
|
||||
'command',
|
||||
'name',
|
||||
'kind',
|
||||
'info',
|
||||
'display',
|
||||
'pid',
|
||||
'admin',
|
||||
'prefix',
|
||||
'url',
|
||||
'roles',
|
||||
},
|
||||
),
|
||||
({'read:services:roles', 'read:users:names'}, {'name', 'kind', 'roles'}),
|
||||
({'read:services:name'}, {'name', 'kind'}),
|
||||
],
|
||||
)
|
||||
async def test_service_model_filtering(
|
||||
app, scopes, model_keys, create_user_with_scopes, create_service_with_scopes
|
||||
):
|
||||
user = create_user_with_scopes(*scopes, 'teddy')
|
||||
service = create_service_with_scopes()
|
||||
r = await api_request(
|
||||
app, 'services', service.name, headers=auth_header(app.db, user.name)
|
||||
)
|
||||
assert r.status_code == 200
|
||||
assert model_keys == r.json().keys()
|
||||
|
||||
|
||||
async def test_roles_access(app, create_user_with_scopes):
|
||||
pass
|
||||
|
||||
|
||||
async def test_service_model_filtering(app, create_user_with_scopes):
|
||||
pass
|
||||
|
||||
|
||||
async def test_group_model_filtering(app, create_user_with_scopes):
|
||||
pass
|
||||
|
@@ -298,7 +298,8 @@ async def test_hubauth_service_token(app, mockservice_url):
|
||||
)
|
||||
r.raise_for_status()
|
||||
reply = r.json()
|
||||
assert reply == {'kind': 'service', 'name': name, 'admin': False, 'roles': []}
|
||||
service_model = {'kind': 'service', 'name': name, 'admin': False, 'roles': []}
|
||||
assert service_model.items() <= reply.items()
|
||||
assert not r.cookies
|
||||
|
||||
# token in ?token parameter
|
||||
@@ -307,7 +308,7 @@ async def test_hubauth_service_token(app, mockservice_url):
|
||||
)
|
||||
r.raise_for_status()
|
||||
reply = r.json()
|
||||
assert reply == {'kind': 'service', 'name': name, 'admin': False, 'roles': []}
|
||||
assert service_model.items() <= reply.items()
|
||||
|
||||
r = await async_requests.get(
|
||||
public_url(app, mockservice_url) + '/whoami/?token=no-such-token',
|
||||
|
Reference in New Issue
Block a user