Unified service model

This commit is contained in:
0mar
2021-06-08 15:18:57 +02:00
parent 2ac1cfe4ac
commit 18623dc9de
5 changed files with 51 additions and 33 deletions

View File

@@ -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'},
}

View File

@@ -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 = [

View File

@@ -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'],

View File

@@ -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

View File

@@ -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',