HTTP errors have full error message

If HTTP error contains error message in json response, it is appended to
an exception raised.

exceptions_decorator is not used in fuel2, cliff has it's own error
handling

Change-Id: I8582e67e2061f5c941a22d32b0f4339f30142be2
Closes-bug: 1514906
This commit is contained in:
Maciej Kwiek
2016-01-25 16:45:02 +01:00
parent 599965b78e
commit d423387f9f
5 changed files with 38 additions and 25 deletions

View File

@@ -14,16 +14,18 @@
from functools import wraps
import json
import os
import sys
from keystoneclient.exceptions import Unauthorized
import requests
import sys
import textwrap
def exit_with_error(message):
"""exit_with_error - writes message to stderr and exits with exit code 1.
"""
sys.stderr.write(message + "\n")
sys.stderr.write("{}{}".format(message, os.linesep))
exit(1)
@@ -101,6 +103,10 @@ class InvalidFileException(FuelClientException):
pass
class HTTPError(FuelClientException):
pass
class EnvironmentException(Exception):
pass
@@ -116,8 +122,8 @@ def exceptions_decorator(func):
# when server returns to us bad request check that
# and print meaningful reason
except requests.HTTPError as exc:
exit_with_error("{0} ({1})".format(exc, get_error_body(exc)))
except HTTPError as exc:
exit_with_error(exc)
except requests.ConnectionError:
message = """
Can't connect to Nailgun server!
@@ -143,3 +149,7 @@ def get_error_body(error):
error_body = error.response.text
return error_body
def get_full_error_message(error):
return "{} ({})".format(error, get_error_body(error))

View File

@@ -19,6 +19,7 @@ import requests
from keystoneclient.v2_0 import client as auth_client
from six.moves.urllib import parse as urlparse
from fuelclient.cli import error
from fuelclient import fuelclient_settings
from fuelclient.logs import NullHandler
@@ -109,7 +110,7 @@ class Client(object):
if self._auth_required is None:
url = self.api_root + 'version'
resp = requests.get(url)
resp.raise_for_status()
self._raise_for_status_with_info(resp)
self._auth_required = resp.json().get('auth_required', False)
return self._auth_required
@@ -150,7 +151,7 @@ class Client(object):
self.print_debug('DELETE {0}'.format(url))
resp = self.session.delete(url)
resp.raise_for_status()
self._raise_for_status_with_info(resp)
if resp.status_code == 204:
return {}
@@ -166,7 +167,7 @@ class Client(object):
self.print_debug('PUT {0} data={1}'.format(url, data_json))
resp = self.session.put(url, data=data_json)
resp.raise_for_status()
self._raise_for_status_with_info(resp)
return resp.json()
@@ -189,7 +190,7 @@ class Client(object):
params = params or {}
resp = self.get_request_raw(api, ostf, params)
resp.raise_for_status()
self._raise_for_status_with_info(resp)
return resp.json()
@@ -212,13 +213,19 @@ class Client(object):
"""Make POST request to specific API with some data
"""
resp = self.post_request_raw(api, data, ostf=ostf)
resp.raise_for_status()
self._raise_for_status_with_info(resp)
return resp.json()
def get_fuel_version(self):
return self.get_request("version")
def _raise_for_status_with_info(self, response):
try:
response.raise_for_status()
except requests.exceptions.HTTPError as e:
raise error.HTTPError(error.get_full_error_message(e))
# This line is single point of instantiation for 'Client' class,
# which intended to implement Singleton design pattern.
APIClient = Client()

View File

@@ -19,7 +19,6 @@ from cliff import app
from cliff.commandmanager import CommandManager
from fuelclient.actions import fuel_version
from fuelclient.cli.error import exceptions_decorator
LOG = logging.getLogger(__name__)
@@ -67,7 +66,6 @@ class FuelClient(app.App):
logging.getLogger(logger_name).setLevel(logging.WARNING)
@exceptions_decorator
def main(argv=sys.argv[1:]):
fuelclient_app = FuelClient(
description='Command line interface and Python API wrapper for Fuel.',

View File

@@ -23,6 +23,7 @@ import mock
import requests
from fuelclient.cli import error
from fuelclient import client
from fuelclient.common import data_utils
from fuelclient.tests.unit.v1 import base
from fuelclient import utils
@@ -242,3 +243,14 @@ class TestUtils(base.UnitTestCase):
result = utils.str_to_unicode(test_data)
self.assertIsInstance(result, six.text_type)
self.assertEqual(result, expected_data)
def test_HTTP_error_message(self):
text = 'message text'
self.m_request.post('/api/v1/address',
json={'message': text},
status_code=403)
with self.assertRaisesRegexp(error.HTTPError,
'403.*{}'.format(text)):
client.Client().post_request('address')

View File

@@ -21,7 +21,6 @@ import mock
from oslotest import base as oslo_base
import fuelclient
from fuelclient.cli import error
from fuelclient.commands import environment as env
from fuelclient import main as main_mod
@@ -72,19 +71,6 @@ class BaseCLITest(oslo_base.BaseTestCase):
self.exec_command(*args)
m_run_command.assert_called_once_with(args)
@mock.patch.object(sys, 'stderr')
@mock.patch('cliff.app.App.run_subcommand')
def test_exec_command_error_handle(self, m_run, m_stderr):
error_msg = 'Test error'
expected_output = error_msg + '\n'
m_run.side_effect = error.FuelClientException(error_msg)
self.assertRaises(SystemExit,
self.exec_command,
'some command --fail True')
m_stderr.write.assert_called_once_with(expected_output)
@mock.patch('cliff.commandmanager.CommandManager.find_command')
def test_command_interactive(self, m_find_command):
commands = ['quit']