Merge pull request #2811 from coreos-inc/joseph.schorr/QUAY-631/repotoken-data-interface
Change repotoken to use a data interface
This commit is contained in:
commit
0ae767d506
3 changed files with 120 additions and 45 deletions
|
@ -6,21 +6,11 @@ from flask import request
|
||||||
|
|
||||||
from endpoints.api import (resource, nickname, require_repo_admin, RepositoryParamResource,
|
from endpoints.api import (resource, nickname, require_repo_admin, RepositoryParamResource,
|
||||||
log_action, validate_json_request, path_param)
|
log_action, validate_json_request, path_param)
|
||||||
|
from endpoints.api.repotoken_models_pre_oci import pre_oci_model as model
|
||||||
from endpoints.exception import NotFound
|
from endpoints.exception import NotFound
|
||||||
from data import model
|
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def token_view(token_obj):
|
|
||||||
return {
|
|
||||||
'friendlyName': token_obj.friendly_name,
|
|
||||||
'code': token_obj.code,
|
|
||||||
'role': token_obj.role.name,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@resource('/v1/repository/<apirepopath:repository>/tokens/')
|
@resource('/v1/repository/<apirepopath:repository>/tokens/')
|
||||||
@path_param('repository', 'The full path of the repository. e.g. namespace/name')
|
@path_param('repository', 'The full path of the repository. e.g. namespace/name')
|
||||||
class RepositoryTokenList(RepositoryParamResource):
|
class RepositoryTokenList(RepositoryParamResource):
|
||||||
|
@ -43,28 +33,25 @@ class RepositoryTokenList(RepositoryParamResource):
|
||||||
|
|
||||||
@require_repo_admin
|
@require_repo_admin
|
||||||
@nickname('listRepoTokens')
|
@nickname('listRepoTokens')
|
||||||
def get(self, namespace, repository):
|
def get(self, namespace_name, repo_name):
|
||||||
""" List the tokens for the specified repository. """
|
""" List the tokens for the specified repository. """
|
||||||
tokens = model.token.get_repository_delegate_tokens(namespace, repository)
|
tokens = model.get_repository_tokens(namespace_name, repo_name)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'tokens': {token.code: token_view(token) for token in tokens}
|
'tokens': {token.code: token.to_dict() for token in tokens}
|
||||||
}
|
}
|
||||||
|
|
||||||
@require_repo_admin
|
@require_repo_admin
|
||||||
@nickname('createToken')
|
@nickname('createToken')
|
||||||
@validate_json_request('NewToken')
|
@validate_json_request('NewToken')
|
||||||
def post(self, namespace, repository):
|
def post(self, namespace_name, repo_name):
|
||||||
""" Create a new repository token. """
|
""" Create a new repository token. """
|
||||||
token_params = request.get_json()
|
token_params = request.get_json()
|
||||||
|
token = model.create_repository_token(namespace_name, repo_name, token_params['friendlyName'])
|
||||||
|
log_action('add_repo_accesstoken', namespace_name,
|
||||||
|
{'repo': repo_name, 'token': token_params['friendlyName']},
|
||||||
|
repo_name=repo_name)
|
||||||
|
|
||||||
token = model.token.create_delegate_token(namespace, repository, token_params['friendlyName'])
|
return token.to_dict(), 201
|
||||||
|
|
||||||
log_action('add_repo_accesstoken', namespace,
|
|
||||||
{'repo': repository, 'token': token_params['friendlyName']},
|
|
||||||
repo=model.repository.get_repository(namespace, repository))
|
|
||||||
|
|
||||||
return token_view(token), 201
|
|
||||||
|
|
||||||
|
|
||||||
@resource('/v1/repository/<apirepopath:repository>/tokens/<code>')
|
@resource('/v1/repository/<apirepopath:repository>/tokens/<code>')
|
||||||
|
@ -92,46 +79,41 @@ class RepositoryToken(RepositoryParamResource):
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@require_repo_admin
|
@require_repo_admin
|
||||||
@nickname('getTokens')
|
@nickname('getTokens')
|
||||||
def get(self, namespace, repository, code):
|
def get(self, namespace_name, repo_name, code):
|
||||||
""" Fetch the specified repository token information. """
|
""" Fetch the specified repository token information. """
|
||||||
try:
|
token = model.get_repository_token(namespace_name, repo_name, code)
|
||||||
perm = model.token.get_repo_delegate_token(namespace, repository, code)
|
if token is None:
|
||||||
except model.InvalidTokenException:
|
|
||||||
raise NotFound()
|
raise NotFound()
|
||||||
|
|
||||||
return token_view(perm)
|
return token.to_dict()
|
||||||
|
|
||||||
@require_repo_admin
|
@require_repo_admin
|
||||||
@nickname('changeToken')
|
@nickname('changeToken')
|
||||||
@validate_json_request('TokenPermission')
|
@validate_json_request('TokenPermission')
|
||||||
def put(self, namespace, repository, code):
|
def put(self, namespace_name, repo_name, code):
|
||||||
""" Update the permissions for the specified repository token. """
|
""" Update the permissions for the specified repository token. """
|
||||||
new_permission = request.get_json()
|
new_permission = request.get_json()
|
||||||
|
logger.debug('Setting permission to: %s for code %s', new_permission['role'], code)
|
||||||
|
|
||||||
logger.debug('Setting permission to: %s for code %s' %
|
token = model.set_repository_token_role(namespace_name, repo_name, code, new_permission['role'])
|
||||||
(new_permission['role'], code))
|
log_action('change_repo_permission', namespace_name,
|
||||||
|
{'repo': repo_name, 'token': token.friendly_name, 'code': code,
|
||||||
token = model.token.set_repo_delegate_token_role(namespace, repository, code,
|
|
||||||
new_permission['role'])
|
|
||||||
|
|
||||||
log_action('change_repo_permission', namespace,
|
|
||||||
{'repo': repository, 'token': token.friendly_name, 'code': code,
|
|
||||||
'role': new_permission['role']},
|
'role': new_permission['role']},
|
||||||
repo=model.repository.get_repository(namespace, repository))
|
repo_name=repo_name)
|
||||||
|
|
||||||
return token_view(token)
|
return token.to_dict()
|
||||||
|
|
||||||
@require_repo_admin
|
@require_repo_admin
|
||||||
@nickname('deleteToken')
|
@nickname('deleteToken')
|
||||||
def delete(self, namespace, repository, code):
|
def delete(self, namespace_name, repo_name, code):
|
||||||
""" Delete the repository token. """
|
""" Delete the repository token. """
|
||||||
token = model.token.delete_delegate_token(namespace, repository, code)
|
token = model.delete_repository_token(namespace_name, repo_name, code)
|
||||||
|
log_action('delete_repo_accesstoken', namespace_name,
|
||||||
log_action('delete_repo_accesstoken', namespace,
|
{'repo': repo_name, 'token': token.friendly_name,
|
||||||
{'repo': repository, 'token': token.friendly_name,
|
|
||||||
'code': code},
|
'code': code},
|
||||||
repo=model.repository.get_repository(namespace, repository))
|
repo_name=repo_name)
|
||||||
|
|
||||||
return '', 204
|
return '', 204
|
||||||
|
|
60
endpoints/api/repotoken_models_interface.py
Normal file
60
endpoints/api/repotoken_models_interface.py
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
from abc import ABCMeta, abstractmethod
|
||||||
|
from collections import namedtuple
|
||||||
|
from six import add_metaclass
|
||||||
|
|
||||||
|
class RepositoryToken(namedtuple('RepositoryToken', ['friendly_name', 'code', 'role'])):
|
||||||
|
"""
|
||||||
|
RepositoryToken represents a (deprecated) repository access token.
|
||||||
|
:type friendly_name: string
|
||||||
|
:type code: string
|
||||||
|
:type role: string
|
||||||
|
"""
|
||||||
|
|
||||||
|
def to_dict(self):
|
||||||
|
return {
|
||||||
|
'friendlyName': self.friendly_name,
|
||||||
|
'code': self.code,
|
||||||
|
'role': self.role.name,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@add_metaclass(ABCMeta)
|
||||||
|
class RepoTokenDataInterface(object):
|
||||||
|
"""
|
||||||
|
Interface that represents all data store interactions required by the repository tokens API.
|
||||||
|
Note that this API is *deprecated*.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def get_repository_tokens(self, namespace_name, repository_name):
|
||||||
|
"""
|
||||||
|
Returns an iterator of all the RepositoryToken's found for the repository with the given
|
||||||
|
namespace and name. If the repository doesn't exist, an empty iterator is returned.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def create_repository_token(self, namespace_name, repository_name, friendly_name):
|
||||||
|
"""
|
||||||
|
Creates and returns a new RepositoryToken under the matching repository.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def get_repository_token(self, namespace_name, repository_name, code):
|
||||||
|
"""
|
||||||
|
Returns the repository access token with the given code under the matching repository or None
|
||||||
|
if none.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def delete_repository_token(self, namespace_name, repository_name, code):
|
||||||
|
"""
|
||||||
|
Deletes the repository access token with the given code under the matching repository, if any.
|
||||||
|
Returns the token deleted or None if none.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def set_repository_token_role(self, namespace_name, repository_name, code, role_name):
|
||||||
|
"""
|
||||||
|
Sets the role of the repository token with the given code under the matching repository, to the
|
||||||
|
role given.
|
||||||
|
"""
|
33
endpoints/api/repotoken_models_pre_oci.py
Normal file
33
endpoints/api/repotoken_models_pre_oci.py
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
from data import model
|
||||||
|
from endpoints.api.repotoken_models_interface import RepoTokenDataInterface, RepositoryToken
|
||||||
|
|
||||||
|
def _token(t):
|
||||||
|
return RepositoryToken(friendly_name=t.friendly_name, code=t.code, role=t.role)
|
||||||
|
|
||||||
|
class RepoTokenPreOCIModel(RepoTokenDataInterface):
|
||||||
|
def get_repository_tokens(self, namespace_name, repository_name):
|
||||||
|
tokens = model.token.get_repository_delegate_tokens(namespace_name, repository_name)
|
||||||
|
return [_token(t) for t in tokens]
|
||||||
|
|
||||||
|
def create_repository_token(self, namespace_name, repository_name, friendly_name):
|
||||||
|
token = model.token.create_delegate_token(namespace_name, repository_name, friendly_name)
|
||||||
|
return _token(token)
|
||||||
|
|
||||||
|
def get_repository_token(self, namespace_name, repository_name, code):
|
||||||
|
try:
|
||||||
|
token = model.token.get_repo_delegate_token(namespace_name, repository_name, code)
|
||||||
|
return _token(token)
|
||||||
|
except model.InvalidTokenException:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def delete_repository_token(self, namespace_name, repository_name, code):
|
||||||
|
token = model.token.delete_delegate_token(namespace_name, repository_name, code)
|
||||||
|
return _token(token)
|
||||||
|
|
||||||
|
def set_repository_token_role(self, namespace_name, repository_name, code, role_name):
|
||||||
|
token = model.token.set_repo_delegate_token_role(namespace_name, repository_name, code,
|
||||||
|
role_name)
|
||||||
|
return _token(token)
|
||||||
|
|
||||||
|
|
||||||
|
pre_oci_model = RepoTokenPreOCIModel()
|
Reference in a new issue