Do not use endpoint's names
Use the URL structure directly to build the requests directly The mapping name <-> endpoint is no longer used See discusion in #1 for details
This commit is contained in:
parent
2deb99c51c
commit
c3277c2e6e
3 changed files with 39 additions and 215 deletions
|
@ -174,7 +174,7 @@ class Re2oAPIClient:
|
||||||
|
|
||||||
# Perform the authentication request
|
# Perform the authentication request
|
||||||
response = requests.post(
|
response = requests.post(
|
||||||
self.get_url_for('token'),
|
self.get_url_for('token-auth'),
|
||||||
data={'username': self._username, 'password': self._password}
|
data={'username': self._username, 'password': self._password}
|
||||||
)
|
)
|
||||||
self.log.debug("Response code: "+str(response.status_code))
|
self.log.debug("Response code: "+str(response.status_code))
|
||||||
|
@ -423,11 +423,11 @@ class Re2oAPIClient:
|
||||||
"""
|
"""
|
||||||
return self._request('put', *args, **kwargs)
|
return self._request('put', *args, **kwargs)
|
||||||
|
|
||||||
def get_url_for(self, name, **kwargs):
|
def get_url_for(self, endpoint):
|
||||||
"""Retrieve the complete URL to use for a given endpoint's name.
|
"""Retrieve the complete URL to use for a given endpoint's name.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
name: The name of the endpoint to look for.
|
endpoint: The path of the endpoint.
|
||||||
**kwargs: A dictionnary with the parameter to use to build the
|
**kwargs: A dictionnary with the parameter to use to build the
|
||||||
URL (using .format() syntax)
|
URL (using .format() syntax)
|
||||||
|
|
||||||
|
@ -438,23 +438,24 @@ class Re2oAPIClient:
|
||||||
re2oapi.exception.NameNotExists: The provided name does not
|
re2oapi.exception.NameNotExists: The provided name does not
|
||||||
correspond to any endpoint.
|
correspond to any endpoint.
|
||||||
"""
|
"""
|
||||||
return '{proto}://{host}{endpoint}'.format(
|
return '{proto}://{host}/{namespace}/{endpoint}'.format(
|
||||||
proto=('https' if self.use_tls else 'http'),
|
proto=('https' if self.use_tls else 'http'),
|
||||||
host=self.hostname,
|
host=self.hostname,
|
||||||
endpoint=endpoints.get_endpoint_for(name, self.log, **kwargs)
|
namespace='api',
|
||||||
|
endpoint=endpoint
|
||||||
)
|
)
|
||||||
|
|
||||||
def _list_for(self, obj_name, max_results=None, params={}, **kwargs):
|
def list(self, endpoint, max_results=None, params={}):
|
||||||
"""List all '{obj_name}' objects on the server.
|
"""List all objects on the server that corresponds to the given
|
||||||
|
endpoint. The endpoint must be valid for listing objects.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
endpoint: The path of the endpoint.
|
||||||
|
max_results: A limit on the number of result to return
|
||||||
params: See `requests.get` params.
|
params: See `requests.get` params.
|
||||||
**kwargs: A dictionnary used to defines the required parameters
|
|
||||||
in order to build the URL (using `.format()`).
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The list of all the {obj_name} objects serialized
|
The list of all the objects serialized as returned by the API.
|
||||||
as returned by the API.
|
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
requests.exceptions.RequestException: An error occured while
|
requests.exceptions.RequestException: An error occured while
|
||||||
|
@ -462,18 +463,19 @@ class Re2oAPIClient:
|
||||||
exceptions.PermissionDenied: The user does not have the right
|
exceptions.PermissionDenied: The user does not have the right
|
||||||
to perform this request.
|
to perform this request.
|
||||||
"""
|
"""
|
||||||
self.log.info("Starting listing {} objects".format(obj_name))
|
self.log.info("Starting listing objects under '{}'"
|
||||||
|
.format(endpoint))
|
||||||
self.log.debug("max_results = "+str(max_results))
|
self.log.debug("max_results = "+str(max_results))
|
||||||
|
|
||||||
# For optimization, list all results in one page unless the user
|
# For optimization, list all results in one page unless the user
|
||||||
# is forcing the use of a different `page_size`.
|
# is forcing the use of a different `page_size`.
|
||||||
if not 'page_size' in params.keys():
|
if not 'page_size' in params.keys():
|
||||||
self.log.debug("Forcing 'page_size' parameter to 'all'.")
|
self.log.debug("Forcing 'page_size' parameter to 'all'.")
|
||||||
params['page_size'] = 'all'
|
params['page_size'] = max_results or 'all'
|
||||||
|
|
||||||
# Performs the request for the first page
|
# Performs the request for the first page
|
||||||
response = self.get(
|
response = self.get(
|
||||||
self.get_url_for('%s-list' % obj_name, **kwargs),
|
self.get_url_for(endpoint),
|
||||||
params=params
|
params=params
|
||||||
)
|
)
|
||||||
results = response['results']
|
results = response['results']
|
||||||
|
@ -486,20 +488,20 @@ class Re2oAPIClient:
|
||||||
|
|
||||||
# Returns the exact number of results if applicable
|
# Returns the exact number of results if applicable
|
||||||
ret = results[:max_results] if max_results else results
|
ret = results[:max_results] if max_results else results
|
||||||
self.log.debug("Listing {} objects successful".format(obj_name))
|
self.log.debug("Listing objects under '{}' successful"
|
||||||
|
.format(endpoint))
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def _count_for(self, obj_name, params={}, **kwargs):
|
def count(self, endpoint, params={}):
|
||||||
"""Count all '{obj_name}' objects on the server:
|
"""Count all objects on the server that corresponds to the given
|
||||||
|
endpoint. The endpoint must be valid for listing objects.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
endpoint: The path of the endpoint.
|
||||||
params: See `requests.get` params.
|
params: See `requests.get` params.
|
||||||
**kwargs: A dictionnary used to defines the required parameters
|
|
||||||
in order to build the URL (using `.format()`).
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The number of {obj_name} objects on the server as returned by the
|
The number of objects on the server as returned by the API.
|
||||||
API.
|
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
requests.exceptions.RequestException: An error occured while
|
requests.exceptions.RequestException: An error occured while
|
||||||
|
@ -507,9 +509,10 @@ class Re2oAPIClient:
|
||||||
exceptions.PermissionDenied: The user does not have the right
|
exceptions.PermissionDenied: The user does not have the right
|
||||||
to perform this request.
|
to perform this request.
|
||||||
"""
|
"""
|
||||||
self.log.info("Starting counting {} objects".format(obj_name))
|
self.log.info("Starting counting objects under '{}'"
|
||||||
|
.format(endpoint))
|
||||||
|
|
||||||
# For optimization, ask fo only 1 result (so the server will take
|
# For optimization, ask for only 1 result (so the server will take
|
||||||
# less time to process the request) unless the user is forcing the
|
# less time to process the request) unless the user is forcing the
|
||||||
# use of a different `page_size`.
|
# use of a different `page_size`.
|
||||||
if not 'page_size' in params.keys():
|
if not 'page_size' in params.keys():
|
||||||
|
@ -518,24 +521,24 @@ class Re2oAPIClient:
|
||||||
|
|
||||||
# Performs the request and return the `count` value in the response.
|
# Performs the request and return the `count` value in the response.
|
||||||
ret = self.get(
|
ret = self.get(
|
||||||
self.get_url_for('%s-list' % obj_name, **kwargs),
|
self.get_url_for(endpoint),
|
||||||
params=params
|
params=params
|
||||||
)['count']
|
)['count']
|
||||||
|
|
||||||
self.log.debug("Counting {} objects successful".format(obj_name))
|
self.log.debug("Counting objects under '{}' successful"
|
||||||
|
.format(endpoint))
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def _view_for(self, obj_name, params={}, **kwargs):
|
def view(self, endpoint, params={}):
|
||||||
"""Retrieved the details of a '{obj_name}' object from the server.
|
"""Retrieved the details of an object from the server that corresponds
|
||||||
|
to the given endpoint.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
endpoint: The path of the endpoint.
|
||||||
params: See `requests.get` params.
|
params: See `requests.get` params.
|
||||||
**kwargs: A dictionnary used to defines the required parameters
|
|
||||||
in order to build the URL (using `.format()`).
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The serialized data of the queried {obj_name} object as returned
|
The serialized data of the queried object as returned by the API.
|
||||||
by the API.
|
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
requests.exceptions.RequestException: An error occured while
|
requests.exceptions.RequestException: An error occured while
|
||||||
|
@ -543,53 +546,13 @@ class Re2oAPIClient:
|
||||||
exceptions.PermissionDenied: The user does not have the right
|
exceptions.PermissionDenied: The user does not have the right
|
||||||
to perform this request.
|
to perform this request.
|
||||||
"""
|
"""
|
||||||
self.log.info("Starting viewing a {} object".format(obj_name))
|
self.log.info("Starting viewing an object under '{}'"
|
||||||
|
.format(endpoint))
|
||||||
ret = self.get(
|
ret = self.get(
|
||||||
self.get_url_for('%s-detail' % obj_name, **kwargs),
|
self.get_url_for(endpoint),
|
||||||
params=params
|
params=params
|
||||||
)
|
)
|
||||||
|
|
||||||
self.log.debug("Viewing {} object successful".format(obj_name))
|
self.log.debug("Viewing object under '{}' successful"
|
||||||
|
.format(endpoint))
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def __getattr__(self, item):
|
|
||||||
|
|
||||||
if item.startswith('list_'):
|
|
||||||
obj_name = item[len('list_'):]
|
|
||||||
def f(*args, **kwargs):
|
|
||||||
return self._list_for(obj_name, *args, **kwargs)
|
|
||||||
f.__doc__ = self._list_for.__doc__.format(obj_name=obj_name)
|
|
||||||
f.__name__ = "list_"+obj_name
|
|
||||||
return f
|
|
||||||
|
|
||||||
elif item.startswith('count_'):
|
|
||||||
obj_name = item[len('count_'):]
|
|
||||||
def f(*args, **kwargs):
|
|
||||||
return self._count_for(obj_name, *args, **kwargs)
|
|
||||||
f.__doc__ = self._count_for.__doc__.format(obj_name=obj_name)
|
|
||||||
f.__name__ = "count_"+obj_name
|
|
||||||
return f
|
|
||||||
|
|
||||||
elif item.startswith('view_'):
|
|
||||||
obj_name = item[len('view_'):]
|
|
||||||
def f(*args, **kwargs):
|
|
||||||
return self._view_for(obj_name, *args, **kwargs)
|
|
||||||
f.__doc__ = self._view_for.__doc__.format(obj_name=obj_name)
|
|
||||||
f.__name__ = "view_"+obj_name
|
|
||||||
return f
|
|
||||||
|
|
||||||
else:
|
|
||||||
raise AttributeError(item)
|
|
||||||
|
|
||||||
def __dir__(self):
|
|
||||||
ret = ['use_tls', 'token_file', 'hostname', 'token',
|
|
||||||
'need_renew_token', 'get_token', 'delete', 'get', 'patch',
|
|
||||||
'post', 'put', 'get_url_for']
|
|
||||||
for name in endpoints.get_names():
|
|
||||||
if name.endswith('-list'):
|
|
||||||
ret.append('list_%s' % name[:-len('-list')])
|
|
||||||
ret.append('count_%s' % name[:-len('-list')])
|
|
||||||
elif name.endswith('-detail'):
|
|
||||||
ret.append('view_%s' % name[:-len('-detail')])
|
|
||||||
return ret
|
|
||||||
|
|
||||||
|
|
|
@ -1,131 +0,0 @@
|
||||||
from . import exceptions
|
|
||||||
|
|
||||||
urls = {
|
|
||||||
'root': '/api/',
|
|
||||||
'article-list': '/api/cotisations/article/',
|
|
||||||
'article-detail': '/api/cotisations/article/{pk}/',
|
|
||||||
'banque-list': '/api/cotisations/banque/',
|
|
||||||
'banque-detail': '/api/cotisations/banque/{pk}/',
|
|
||||||
'cotisation-list': '/api/cotisations/cotisation/',
|
|
||||||
'cotisation-detail': '/api/cotisations/cotisation/{pk}/',
|
|
||||||
'facture-list': '/api/cotisations/facture/',
|
|
||||||
'facture-detail': '/api/cotisations/facture/{pk}/',
|
|
||||||
'paiment-list': '/api/cotisations/paiement/',
|
|
||||||
'paiement-detail': '/api/cotisations/paiement/{pk}/',
|
|
||||||
'vente-list': '/api/cotisations/vente/',
|
|
||||||
'vente-detail': '/api/cotisations/vente/{pk}/',
|
|
||||||
'domain-list': '/api/machines/domain/',
|
|
||||||
'domain-detail': '/api/machines/domain/{pk}/',
|
|
||||||
'extension-list': '/api/machines/extension/',
|
|
||||||
'extension-detail': '/api/machines/extension/{pk}/',
|
|
||||||
'interface-list': '/api/machines/interface/',
|
|
||||||
'interface-detail': '/api/machines/interface/{pk}/',
|
|
||||||
'iplist-list': '/api/machines/iplist/',
|
|
||||||
'iplist-detail': '/api/machines/iplist/{pk}/',
|
|
||||||
'iptype-list': '/api/machines/iptype/',
|
|
||||||
'iptype-detail': '/api/machines/iptype/{pk}/',
|
|
||||||
'ipv6list-list': '/api/machines/ipv6list/',
|
|
||||||
'ipv6list-detail': '/api/machines/ipv6list/{pk}/',
|
|
||||||
'machine-list': '/api/machines/machine/',
|
|
||||||
'machine-detail': '/api/machines/machine/{pk}/',
|
|
||||||
'machinetype-list': '/api/machines/machinetype/',
|
|
||||||
'machinetype-detail': '/api/machines/machinetype/{pk}/',
|
|
||||||
'mx-list': '/api/machines/mx/',
|
|
||||||
'mx-detail': '/api/machines/mx/{pk}/',
|
|
||||||
'nas-list': '/api/machines/nas/',
|
|
||||||
'nas-detail': '/api/machines/nas/{pk}/',
|
|
||||||
'ns-list': '/api/machines/ns/',
|
|
||||||
'ns-detail': '/api/machines/ns/{pk}/',
|
|
||||||
'ouvertureportlist-list': '/api/machines/ouvertureportlist/',
|
|
||||||
'ouvertureportlist-detail': '/api/machines/ouvertureportlist/{pk}/',
|
|
||||||
'ouvertureport-list': '/api/machines/ouvertureport/',
|
|
||||||
'ouvertureport-detail': '/api/machines/ouvertureport/{pk}/',
|
|
||||||
'servicelink-list': '/api/machines/servicelink/',
|
|
||||||
'servicelink-detail': '/api/machines/servicelink/{pk}/',
|
|
||||||
'service-list': '/api/machines/service/',
|
|
||||||
'service-detail': '/api/machines/service/{pk}/',
|
|
||||||
'soa-list': '/api/machines/soa/',
|
|
||||||
'soa-detail': '/api/machines/soa/{pk}/',
|
|
||||||
'srv-list': '/api/machines/srv/',
|
|
||||||
'srv-detail': '/api/machines/srv/{pk}/',
|
|
||||||
'txt-list': '/api/machines/txt/',
|
|
||||||
'txt-detail': '/api/machines/txt/{pk}/',
|
|
||||||
'vlan-list': '/api/machines/vlan/',
|
|
||||||
'vlan-detail': '/api/machines/vlan/{pk}/',
|
|
||||||
'optionaluser-detail': '/api/preferences/optionaluser/',
|
|
||||||
'optionalmachine-detail': '/api/preferences/optionalmachine/',
|
|
||||||
'optionaltopologie-detail': '/api/preferences/optionaltopologie/',
|
|
||||||
'generaloption-detail': '/api/preferences/generaloption/',
|
|
||||||
'homeservice-list': '/api/preferences/service/',
|
|
||||||
'homeservice-detail': '/api/preferences/service/{pk}/',
|
|
||||||
'assooption-detail': '/api/preferences/assooption/',
|
|
||||||
'homeoption-detail': '/api/preferences/homeoption/',
|
|
||||||
'mailmessageoption-detail': '/api/preferences/mailmessageoption/',
|
|
||||||
'accesspoint-list': '/api/topologie/acesspoint/',
|
|
||||||
'accesspoint-detail': '/api/topologie/acesspoint/{pk}/',
|
|
||||||
'building-list': '/api/topologie/building/',
|
|
||||||
'building-detail': '/api/topologie/building/{pk}/',
|
|
||||||
'constructorswitch-list': '/api/topologie/constructorswitch/',
|
|
||||||
'constructorswitch-detail': '/api/topologie/constructorswitch/{pk}/',
|
|
||||||
'modelswitch-list': '/api/topologie/modelswitch/',
|
|
||||||
'modelswitch-detail': '/api/topologie/modelswitch/{pk}/',
|
|
||||||
'room-list': '/api/topologie/room/',
|
|
||||||
'room-detail': '/api/topologie/room/{pk}/',
|
|
||||||
'server-list': '/api/topologie/server/',
|
|
||||||
'server-detail': '/api/topologie/server/{pk}/',
|
|
||||||
'stack-list': '/api/topologie/stack/',
|
|
||||||
'stack-detail': '/api/topologie/stack/{pk}/',
|
|
||||||
'switch-list': '/api/topologie/switch/',
|
|
||||||
'switch-detail': '/api/topologie/switch/{pk}/',
|
|
||||||
'switchbay-list': '/api/topologie/switchbay/',
|
|
||||||
'switchbay-detail': '/api/topologie/switchbay/{pk}/',
|
|
||||||
'switchport-list': '/api/topologie/switchport/',
|
|
||||||
'switchport-detail': '/api/topologie/switchport/{pk}/',
|
|
||||||
'adherent-list': '/api/users/adherent/',
|
|
||||||
'adherent-detail': '/api/users/adherent/{pk}/',
|
|
||||||
'ban-list': '/api/users/ban/',
|
|
||||||
'ban-detail': '/api/users/ban/{pk}/',
|
|
||||||
'club-list': '/api/users/club/',
|
|
||||||
'club-detail': '/api/users/club/{pk}/',
|
|
||||||
'listright-list': '/api/users/listright/',
|
|
||||||
'listright-detail': '/api/users/listright/{pk}/',
|
|
||||||
'school-list': '/api/users/school/',
|
|
||||||
'school-detail': '/api/users/school/{pk}/',
|
|
||||||
'serviceuser-list': '/api/users/serviceuser/',
|
|
||||||
'serviceuser-detail': '/api/users/serviceuser/{pk}/',
|
|
||||||
'shell-list': '/api/users/shell/',
|
|
||||||
'shell-detail': '/api/users/shell/{pk}/',
|
|
||||||
'user-list': '/api/users/user/',
|
|
||||||
'user-detail': '/api/users/user/{pk}/',
|
|
||||||
'whitelist-list': '/api/users/whitelist/',
|
|
||||||
'whitelist-detail': '/api/users/whitelist/{pk}/',
|
|
||||||
'dnszones-list': '/api/dns/zones/',
|
|
||||||
'hostmacip-list': '/api/dhcp/hostmacip/',
|
|
||||||
'mailingstandard-list': '/api/mailing/standard/',
|
|
||||||
'mailingclub-list': '/api/mailing/club/',
|
|
||||||
'servicesregen-list': '/api/services/regen/',
|
|
||||||
'servicesregen-detail': '/api/services/regen/{pk}/',
|
|
||||||
'token': '/api/token-auth/',
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def get_names():
|
|
||||||
return urls.keys()
|
|
||||||
|
|
||||||
|
|
||||||
def get_endpoint_for(name, logger=None, **kwargs):
|
|
||||||
try:
|
|
||||||
url=urls[name]
|
|
||||||
except KeyError:
|
|
||||||
e = exceptions.URLNameDoesNotExists(name)
|
|
||||||
if logger is not None:
|
|
||||||
logger.warning(e)
|
|
||||||
raise e
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
return url.format_map(kwargs)
|
|
||||||
except KeyError as e:
|
|
||||||
e = exceptions.URLParameterMissing(name, e)
|
|
||||||
if logger is not None:
|
|
||||||
logger.warning(e)
|
|
||||||
raise e
|
|
|
@ -7,14 +7,6 @@ class APIClientGenericError(ValueError):
|
||||||
super(APIClientGenericError, self).__init__(self.message)
|
super(APIClientGenericError, self).__init__(self.message)
|
||||||
|
|
||||||
|
|
||||||
class URLNameDoesNotExists(APIClientGenericError):
|
|
||||||
template = "The name '{}' was not foud among the possible endpoints."
|
|
||||||
|
|
||||||
|
|
||||||
class URLParameterMissing(APIClientGenericError):
|
|
||||||
template = "The url named '{}' requires the parameter {} to be built."
|
|
||||||
|
|
||||||
|
|
||||||
class InvalidCredentials(APIClientGenericError):
|
class InvalidCredentials(APIClientGenericError):
|
||||||
template = "The credentials for {}@{} are not valid."
|
template = "The credentials for {}@{} are not valid."
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue