Convert keystoneauth exceptions by ours
This change creates gnocchiclient exceptions and convert keystoneauth exception into our exceptions. Change-Id: I05f059d1d9a7d54740eef8049c5688a41f063bae
This commit is contained in:
parent
071212b241
commit
c4b3be9d8e
|
@ -10,11 +10,30 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from keystoneauth1 import adapter
|
||||
from oslo_utils import importutils
|
||||
|
||||
from gnocchiclient import exceptions
|
||||
|
||||
|
||||
def Client(version, *args, **kwargs):
|
||||
module = 'gnocchiclient.v%s.client' % version
|
||||
module = importutils.import_module(module)
|
||||
client_class = getattr(module, 'Client')
|
||||
return client_class(*args, **kwargs)
|
||||
|
||||
|
||||
class SessionClient(adapter.Adapter):
|
||||
def request(self, url, method, **kwargs):
|
||||
kwargs.setdefault('headers', kwargs.get('headers', {}))
|
||||
# NOTE(sileht): The standard call raises errors from
|
||||
# keystoneauth, where we need to raise the gnocchiclient errors.
|
||||
raise_exc = kwargs.pop('raise_exc', True)
|
||||
resp = super(SessionClient, self).request(url,
|
||||
method,
|
||||
raise_exc=False,
|
||||
**kwargs)
|
||||
|
||||
if raise_exc and resp.status_code >= 400:
|
||||
raise exceptions.from_response(resp, url, method)
|
||||
return resp
|
||||
|
|
|
@ -0,0 +1,200 @@
|
|||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import re
|
||||
|
||||
|
||||
class ClientException(Exception):
|
||||
"""The base exception class for all exceptions this library raises."""
|
||||
message = 'Unknown Error'
|
||||
|
||||
def __init__(self, code, message=None, request_id=None,
|
||||
url=None, method=None):
|
||||
self.code = code
|
||||
self.message = message or self.__class__.message
|
||||
self.request_id = request_id
|
||||
self.url = url
|
||||
self.method = method
|
||||
|
||||
def __str__(self):
|
||||
formatted_string = "%s (HTTP %s)" % (self.message, self.code)
|
||||
if self.request_id:
|
||||
formatted_string += " (Request-ID: %s)" % self.request_id
|
||||
|
||||
return formatted_string
|
||||
|
||||
|
||||
class RetryAfterException(ClientException):
|
||||
"""The base exception for ClientExceptions that use Retry-After header."""
|
||||
def __init__(self, *args, **kwargs):
|
||||
try:
|
||||
self.retry_after = int(kwargs.pop('retry_after'))
|
||||
except (KeyError, ValueError):
|
||||
self.retry_after = 0
|
||||
|
||||
super(RetryAfterException, self).__init__(*args, **kwargs)
|
||||
|
||||
|
||||
class MutipleMeaningException(object):
|
||||
"""An mixin for exception that can be enhanced by reading the details"""
|
||||
|
||||
|
||||
class BadRequest(ClientException):
|
||||
"""HTTP 400 - Bad request: you sent some malformed data."""
|
||||
http_status = 400
|
||||
message = "Bad request"
|
||||
|
||||
|
||||
class Unauthorized(ClientException):
|
||||
"""HTTP 401 - Unauthorized: bad credentials."""
|
||||
http_status = 401
|
||||
message = "Unauthorized"
|
||||
|
||||
|
||||
class Forbidden(ClientException):
|
||||
"""HTTP 403 - Forbidden:
|
||||
|
||||
your credentials don't give you access to this resource.
|
||||
"""
|
||||
http_status = 403
|
||||
message = "Forbidden"
|
||||
|
||||
|
||||
class NotFound(ClientException):
|
||||
"""HTTP 404 - Not found"""
|
||||
http_status = 404
|
||||
message = "Not found"
|
||||
|
||||
|
||||
class MetricNotFound(NotFound, MutipleMeaningException):
|
||||
message = "Metric not found"
|
||||
match = re.compile("Metric .* does not exist")
|
||||
|
||||
|
||||
class ResourceNotFound(NotFound, MutipleMeaningException):
|
||||
message = "Resource not found"
|
||||
match = re.compile("Resource .* does not exist")
|
||||
|
||||
|
||||
class ArchivePolicyNotFound(NotFound, MutipleMeaningException):
|
||||
message = "Archive policy not found"
|
||||
match = re.compile("Archive policy .* does not exist")
|
||||
|
||||
|
||||
class ArchivePolicyRuleNotFound(NotFound, MutipleMeaningException):
|
||||
message = "Archive policy rule not found"
|
||||
match = re.compile("Archive policy rule .* does not exist")
|
||||
|
||||
|
||||
class MethodNotAllowed(ClientException):
|
||||
"""HTTP 405 - Method Not Allowed"""
|
||||
http_status = 405
|
||||
message = "Method Not Allowed"
|
||||
|
||||
|
||||
class NotAcceptable(ClientException):
|
||||
"""HTTP 406 - Not Acceptable"""
|
||||
http_status = 406
|
||||
message = "Not Acceptable"
|
||||
|
||||
|
||||
class Conflict(ClientException):
|
||||
"""HTTP 409 - Conflict"""
|
||||
http_status = 409
|
||||
message = "Conflict"
|
||||
|
||||
|
||||
class OverLimit(RetryAfterException):
|
||||
"""HTTP 413 - Over limit:
|
||||
|
||||
you're over the API limits for this time period.
|
||||
"""
|
||||
http_status = 413
|
||||
message = "Over limit"
|
||||
|
||||
|
||||
class RateLimit(RetryAfterException):
|
||||
"""HTTP 429 - Rate limit:
|
||||
|
||||
you've sent too many requests for this time period.
|
||||
"""
|
||||
http_status = 429
|
||||
message = "Rate limit"
|
||||
|
||||
|
||||
class NotImplemented(ClientException):
|
||||
"""HTTP 501 - Not Implemented:
|
||||
|
||||
the server does not support this operation.
|
||||
"""
|
||||
http_status = 501
|
||||
message = "Not Implemented"
|
||||
|
||||
|
||||
_error_classes = [BadRequest, Unauthorized, Forbidden, NotFound,
|
||||
MethodNotAllowed, NotAcceptable, Conflict, OverLimit,
|
||||
RateLimit, NotImplemented]
|
||||
_error_classes_enhanced = {
|
||||
NotFound: [MetricNotFound, ResourceNotFound, ArchivePolicyNotFound,
|
||||
ArchivePolicyRuleNotFound],
|
||||
}
|
||||
_code_map = dict(
|
||||
(c.http_status, (c, _error_classes_enhanced.get(c, [])))
|
||||
for c in _error_classes)
|
||||
|
||||
|
||||
def from_response(response, url, method=None):
|
||||
"""Return an instance of one of the ClientException on an requests response.
|
||||
|
||||
Usage::
|
||||
|
||||
resp, body = requests.request(...)
|
||||
if resp.status_code != 200:
|
||||
raise exception_from_response(resp)
|
||||
"""
|
||||
|
||||
if response.status_code:
|
||||
cls, enhanced_classes = _code_map.get(response.status_code,
|
||||
(ClientException, []))
|
||||
|
||||
req_id = response.headers.get("x-openstack-request-id")
|
||||
content_type = response.headers.get("Content-Type", "").split(";")[0]
|
||||
|
||||
kwargs = {
|
||||
'code': response.status_code,
|
||||
'method': method,
|
||||
'url': url,
|
||||
'request_id': req_id,
|
||||
}
|
||||
|
||||
if "retry-after" in response.headers:
|
||||
kwargs['retry_after'] = response.headers.get('retry-after')
|
||||
|
||||
if content_type == "application/json":
|
||||
try:
|
||||
body = response.json()
|
||||
except ValueError:
|
||||
pass
|
||||
else:
|
||||
desc = body.get('description')
|
||||
for enhanced_cls in enhanced_classes:
|
||||
if enhanced_cls.match.match(desc):
|
||||
cls = enhanced_cls
|
||||
break
|
||||
kwargs['message'] = desc
|
||||
elif content_type.startswith("text/"):
|
||||
kwargs['message'] = response.text
|
||||
|
||||
if not kwargs['message']:
|
||||
del kwargs['message']
|
||||
return cls(**kwargs)
|
|
@ -20,7 +20,6 @@ import warnings
|
|||
|
||||
from cliff import app
|
||||
from cliff import commandmanager
|
||||
from keystoneauth1 import adapter
|
||||
from keystoneauth1 import exceptions
|
||||
from keystoneauth1 import loading
|
||||
|
||||
|
@ -145,13 +144,11 @@ class GnocchiShell(app.App):
|
|||
session = loading.load_session_from_argparse_arguments(
|
||||
self.options, auth=auth_plugin)
|
||||
|
||||
session = adapter.Adapter(session, service_type='metric',
|
||||
interface=self.options.interface,
|
||||
region_name=self.options.region_name,
|
||||
endpoint_override=endpoint_override)
|
||||
|
||||
self._client = client.Client(self.options.gnocchi_api_version,
|
||||
session=session)
|
||||
session=session,
|
||||
interface=self.options.interface,
|
||||
region_name=self.options.region_name,
|
||||
endpoint_override=endpoint_override)
|
||||
return self._client
|
||||
|
||||
def clean_up(self, cmd, result, err):
|
||||
|
|
|
@ -47,12 +47,14 @@ class ArchivePolicyClientTest(base.ClientTestBase):
|
|||
result = self.gnocchi('archive-policy',
|
||||
params="show low",
|
||||
fail_ok=True, merge_stderr=True)
|
||||
self.assertFirstLineStartsWith(result.split('\n'),
|
||||
"Not Found (HTTP 404)")
|
||||
self.assertFirstLineStartsWith(
|
||||
result.split('\n'),
|
||||
"Archive policy low does not exist (HTTP 404)")
|
||||
|
||||
# DELETE FAIL
|
||||
result = self.gnocchi('archive-policy',
|
||||
params="delete low",
|
||||
fail_ok=True, merge_stderr=True)
|
||||
self.assertFirstLineStartsWith(result.split('\n'),
|
||||
"Not Found (HTTP 404)")
|
||||
self.assertFirstLineStartsWith(
|
||||
result.split('\n'),
|
||||
"Archive policy low does not exist (HTTP 404)")
|
||||
|
|
|
@ -46,12 +46,14 @@ class ArchivePolicyRuleClientTest(base.ClientTestBase):
|
|||
result = self.gnocchi('archive-policy-rule',
|
||||
params="show test",
|
||||
fail_ok=True, merge_stderr=True)
|
||||
self.assertFirstLineStartsWith(result.split('\n'),
|
||||
"Not Found (HTTP 404)")
|
||||
self.assertFirstLineStartsWith(
|
||||
result.split('\n'),
|
||||
"Archive policy rule test does not exist (HTTP 404)")
|
||||
|
||||
# DELETE FAIL
|
||||
result = self.gnocchi('archive-policy-rule',
|
||||
params="delete test",
|
||||
fail_ok=True, merge_stderr=True)
|
||||
self.assertFirstLineStartsWith(result.split('\n'),
|
||||
"Not Found (HTTP 404)")
|
||||
self.assertFirstLineStartsWith(
|
||||
result.split('\n'),
|
||||
"Archive policy rule test does not exist (HTTP 404)")
|
||||
|
|
|
@ -40,11 +40,13 @@ class MetricClientTest(base.ClientTestBase):
|
|||
result = self.gnocchi('metric', params="show %s" % metric1["id"],
|
||||
fail_ok=True, merge_stderr=True)
|
||||
self.assertFirstLineStartsWith(result.split('\n'),
|
||||
"Not Found (HTTP 404)")
|
||||
"Metric %s does not exist (HTTP 404)" %
|
||||
metric1["id"])
|
||||
result = self.gnocchi('metric', params="show %s" % metric2["id"],
|
||||
fail_ok=True, merge_stderr=True)
|
||||
self.assertFirstLineStartsWith(result.split('\n'),
|
||||
"Not Found (HTTP 404)")
|
||||
"Metric %s does not exist (HTTP 404)" %
|
||||
metric2["id"])
|
||||
|
||||
def test_metric_scenario(self):
|
||||
# PREPARE AN ACHIVE POLICY
|
||||
|
@ -138,14 +140,16 @@ class MetricClientTest(base.ClientTestBase):
|
|||
# GET FAIL
|
||||
result = self.gnocchi('metric', params="show %s" % metric["id"],
|
||||
fail_ok=True, merge_stderr=True)
|
||||
self.assertFirstLineStartsWith(result.split('\n'),
|
||||
"Not Found (HTTP 404)")
|
||||
self.assertFirstLineStartsWith(
|
||||
result.split('\n'),
|
||||
"Metric %s does not exist (HTTP 404)" % metric["id"])
|
||||
|
||||
# DELETE FAIL
|
||||
result = self.gnocchi('metric', params="delete %s" % metric["id"],
|
||||
fail_ok=True, merge_stderr=True)
|
||||
self.assertFirstLineStartsWith(result.split('\n'),
|
||||
"Not Found (HTTP 404)")
|
||||
self.assertFirstLineStartsWith(
|
||||
result.split('\n'),
|
||||
"Metric %s does not exist (HTTP 404)" % metric["id"])
|
||||
|
||||
def test_metric_by_name_scenario(self):
|
||||
# PREPARE REQUIREMENT
|
||||
|
@ -230,12 +234,31 @@ class MetricClientTest(base.ClientTestBase):
|
|||
result = self.gnocchi('metric',
|
||||
params="show -r metric-res metric-name",
|
||||
fail_ok=True, merge_stderr=True)
|
||||
self.assertFirstLineStartsWith(result.split('\n'),
|
||||
"Not Found (HTTP 404)")
|
||||
self.assertFirstLineStartsWith(
|
||||
result.split('\n'),
|
||||
"Metric metric-name does not exist (HTTP 404)")
|
||||
|
||||
# DELETE FAIL
|
||||
result = self.gnocchi('metric',
|
||||
params="delete -r metric-res metric-name",
|
||||
fail_ok=True, merge_stderr=True)
|
||||
self.assertFirstLineStartsWith(result.split('\n'),
|
||||
"Not Found (HTTP 404)")
|
||||
self.assertFirstLineStartsWith(
|
||||
result.split('\n'),
|
||||
"Metric metric-name does not exist (HTTP 404)")
|
||||
|
||||
# GET RESOURCE ID
|
||||
result = self.gnocchi(
|
||||
'resource', params="show -t generic metric-res")
|
||||
resource_id = self.details_multiple(result)[0]["id"]
|
||||
|
||||
# DELETE RESOURCE
|
||||
result = self.gnocchi('resource', params="delete metric-res")
|
||||
self.assertEqual("", result)
|
||||
|
||||
# GET FAIL WITH RESOURCE ERROR
|
||||
result = self.gnocchi('metric',
|
||||
params="show metric-name -r metric-res",
|
||||
fail_ok=True, merge_stderr=True)
|
||||
self.assertFirstLineStartsWith(
|
||||
result.split('\n'),
|
||||
"Resource %s does not exist (HTTP 404)" % resource_id)
|
||||
|
|
|
@ -119,15 +119,17 @@ class ResourceClientTest(base.ClientTestBase):
|
|||
params="show --type generic %s" %
|
||||
self.RESOURCE_ID,
|
||||
fail_ok=True, merge_stderr=True)
|
||||
self.assertFirstLineStartsWith(result.split('\n'),
|
||||
"Not Found (HTTP 404)")
|
||||
self.assertFirstLineStartsWith(
|
||||
result.split('\n'),
|
||||
"Resource %s does not exist (HTTP 404)" % self.RESOURCE_ID)
|
||||
|
||||
# DELETE FAIL
|
||||
result = self.gnocchi('resource',
|
||||
params="delete %s" % self.RESOURCE_ID,
|
||||
fail_ok=True, merge_stderr=True)
|
||||
self.assertFirstLineStartsWith(result.split('\n'),
|
||||
"Not Found (HTTP 404)")
|
||||
self.assertFirstLineStartsWith(
|
||||
result.split('\n'),
|
||||
"Resource %s does not exist (HTTP 404)" % self.RESOURCE_ID)
|
||||
|
||||
# LIST EMPTY
|
||||
result = self.gnocchi('resource', params="list -t generic")
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from gnocchiclient import client
|
||||
from gnocchiclient.v1 import archive_policy
|
||||
from gnocchiclient.v1 import archive_policy_rule
|
||||
from gnocchiclient.v1 import capabilities
|
||||
|
@ -28,11 +29,10 @@ class Client(object):
|
|||
:type session: :py:class:`keystoneauth.adapter.Adapter`
|
||||
"""
|
||||
|
||||
def __init__(self, session=None):
|
||||
"""Initialize a new client for the Gnocchi v1 API.
|
||||
|
||||
"""
|
||||
self.api = session
|
||||
def __init__(self, session=None, service_type='metric', **kwargs):
|
||||
"""Initialize a new client for the Gnocchi v1 API."""
|
||||
self.api = client.SessionClient(session, service_type=service_type,
|
||||
**kwargs)
|
||||
self.resource = resource.ResourceManager(self)
|
||||
self.archive_policy = archive_policy.ArchivePolicyManager(self)
|
||||
self.archive_policy_rule = (
|
||||
|
|
Loading…
Reference in New Issue