Subclass wsme.exc.ClientSideError

This change avoids importing a wsgi namespace exception class, and
allows the future option of changing the parent class of
exception.ClientSideError when wsme is no longer processing API
requests.

Change-Id: I8165e094fafb91ff94eaa1dd96baba7671487448
Story: 1651346
This commit is contained in:
Steve Baker 2020-01-22 14:43:56 +13:00
parent cc7a9c29c2
commit f192f2c45d
7 changed files with 62 additions and 57 deletions

View File

@ -564,7 +564,7 @@ class NodeStatesController(rest.RestController):
msg = (_('A non-empty "rescue_password" is required when '
'setting target provision state to %s') %
ir_states.VERBS['rescue'])
raise wsme.exc.ClientSideError(
raise exception.ClientSideError(
msg, status_code=http_client.BAD_REQUEST)
api.request.rpcapi.do_node_rescue(
api.request.context, rpc_node.uuid, rescue_password, topic)
@ -578,7 +578,7 @@ class NodeStatesController(rest.RestController):
if not clean_steps:
msg = (_('"clean_steps" is required when setting target '
'provision state to %s') % ir_states.VERBS['clean'])
raise wsme.exc.ClientSideError(
raise exception.ClientSideError(
msg, status_code=http_client.BAD_REQUEST)
_check_clean_steps(clean_steps)
api.request.rpcapi.do_node_clean(
@ -678,14 +678,14 @@ class NodeStatesController(rest.RestController):
if clean_steps and target != ir_states.VERBS['clean']:
msg = (_('"clean_steps" is only valid when setting target '
'provision state to %s') % ir_states.VERBS['clean'])
raise wsme.exc.ClientSideError(
raise exception.ClientSideError(
msg, status_code=http_client.BAD_REQUEST)
if (rescue_password is not None
and target != ir_states.VERBS['rescue']):
msg = (_('"rescue_password" is only valid when setting target '
'provision state to %s') % ir_states.VERBS['rescue'])
raise wsme.exc.ClientSideError(
raise exception.ClientSideError(
msg, status_code=http_client.BAD_REQUEST)
if (rpc_node.provision_state == ir_states.INSPECTWAIT and
@ -1700,10 +1700,10 @@ class NodesController(rest.RestController):
This function will raise an exception for unacceptable names.
:param names: list of node names to check
:param error_msg: error message in case of wsme.exc.ClientSideError,
:param error_msg: error message in case of exception.ClientSideError,
should contain %(name)s placeholder.
:raises: exception.NotAcceptable
:raises: wsme.exc.ClientSideError
:raises: exception.ClientSideError
"""
if not api_utils.allow_node_logical_names():
raise exception.NotAcceptable()
@ -1711,11 +1711,11 @@ class NodesController(rest.RestController):
reserved_names = get_nodes_controller_reserved_names()
for name in names:
if not api_utils.is_valid_node_name(name):
raise wsme.exc.ClientSideError(
raise exception.ClientSideError(
error_msg % {'name': name},
status_code=http_client.BAD_REQUEST)
if name in reserved_names:
raise wsme.exc.ClientSideError(
raise exception.ClientSideError(
'The word "%(name)s" is reserved and can not be used as a '
'node name. Reserved words are: %(reserved)s.' %
{'name': name,
@ -1762,11 +1762,11 @@ class NodesController(rest.RestController):
:param rpc_node: RPC Node object to be verified.
:param node_ident: the UUID or logical name of a node.
:raises: wsme.exc.ClientSideError
:raises: exception.ClientSideError
"""
delta = rpc_node.obj_what_changed()
if 'driver' in delta and rpc_node.console_enabled:
raise wsme.exc.ClientSideError(
raise exception.ClientSideError(
_("Node %s can not update the driver while the console is "
"enabled. Please stop the console first.") % node_ident,
status_code=http_client.CONFLICT)
@ -2107,15 +2107,15 @@ class NodesController(rest.RestController):
not in ir_states.UPDATE_ALLOWED_STATES):
msg = _("Node %s can not be updated while a state transition "
"is in progress.")
raise wsme.exc.ClientSideError(
raise exception.ClientSideError(
msg % node_ident, status_code=http_client.CONFLICT)
elif (rpc_node.provision_state == ir_states.INSPECTING
and api_utils.allow_inspect_wait_state()):
msg = _('Cannot update node "%(node)s" while it is in state '
'"%(state)s".') % {'node': rpc_node.uuid,
'state': ir_states.INSPECTING}
raise wsme.exc.ClientSideError(msg,
status_code=http_client.CONFLICT)
raise exception.ClientSideError(msg,
status_code=http_client.CONFLICT)
elif api_utils.get_patch_values(patch, '/owner'):
# check if updating a provisioned node's owner is allowed
@ -2129,7 +2129,7 @@ class NodesController(rest.RestController):
'is in state "%(state)s".') % {
'node': rpc_node.uuid,
'state': ir_states.ACTIVE}
raise wsme.exc.ClientSideError(
raise exception.ClientSideError(
msg, status_code=http_client.CONFLICT)
# check if node has an associated allocation with an owner
@ -2142,7 +2142,7 @@ class NodesController(rest.RestController):
msg = _('Cannot update owner of node "%(node)s" while '
'it is allocated to an allocation with an '
' owner.') % {'node': rpc_node.uuid}
raise wsme.exc.ClientSideError(
raise exception.ClientSideError(
msg, status_code=http_client.CONFLICT)
except exception.AllocationNotFound:
pass

View File

@ -715,8 +715,8 @@ class PortsController(rest.RestController):
'in state "%(state)s".') % {'port': rpc_port.uuid,
'node': rpc_node.uuid,
'state': ir_states.INSPECTING}
raise wsme.exc.ClientSideError(msg,
status_code=http_client.CONFLICT)
raise exception.ClientSideError(msg,
status_code=http_client.CONFLICT)
notify_extra = {'node_uuid': rpc_node.uuid,
'portgroup_uuid': port.portgroup_uuid}

View File

@ -484,7 +484,7 @@ class PortgroupsController(pecan.rest.RestController):
and not api_utils.is_valid_logical_name(portgroup.name)):
error_msg = _("Cannot create portgroup with invalid name "
"'%(name)s'") % {'name': portgroup.name}
raise wsme.exc.ClientSideError(
raise exception.ClientSideError(
error_msg, status_code=http_client.BAD_REQUEST)
pg_dict = portgroup.as_dict()
@ -544,7 +544,7 @@ class PortgroupsController(pecan.rest.RestController):
" invalid name '%(name)s'") % {'portgroup':
portgroup_ident,
'name': name}
raise wsme.exc.ClientSideError(
raise exception.ClientSideError(
error_msg, status_code=http_client.BAD_REQUEST)
portgroup_dict = rpc_portgroup.as_dict()
@ -578,8 +578,8 @@ class PortgroupsController(pecan.rest.RestController):
'"%(node)s" while it is in state "%(state)s".') % {
'portgroup': rpc_portgroup.uuid, 'node': rpc_node.uuid,
'state': ir_states.INSPECTING}
raise wsme.exc.ClientSideError(msg,
status_code=http_client.CONFLICT)
raise exception.ClientSideError(msg,
status_code=http_client.CONFLICT)
notify.emit_start_notification(context, rpc_portgroup, 'update',
node_uuid=rpc_node.uuid)

View File

@ -246,16 +246,16 @@ class JsonPatchType(wtypes.Base):
_path = '/' + patch.path.split('/')[1]
if _path in patch.internal_attrs():
msg = _("'%s' is an internal attribute and can not be updated")
raise wsme.exc.ClientSideError(msg % patch.path)
raise exception.ClientSideError(msg % patch.path)
if patch.path in patch.non_removable_attrs() and patch.op == 'remove':
msg = _("'%s' is a mandatory attribute and can not be removed")
raise wsme.exc.ClientSideError(msg % patch.path)
raise exception.ClientSideError(msg % patch.path)
if patch.op != 'remove':
if patch.value is wsme.Unset:
msg = _("'add' and 'replace' operations need a value")
raise wsme.exc.ClientSideError(msg)
raise exception.ClientSideError(msg)
ret = {'path': patch.path, 'op': patch.op}
if patch.value is not wsme.Unset:

View File

@ -82,21 +82,21 @@ def validate_limit(limit):
return CONF.api.max_limit
if limit <= 0:
raise wsme.exc.ClientSideError(_("Limit must be positive"))
raise exception.ClientSideError(_("Limit must be positive"))
return min(CONF.api.max_limit, limit)
def validate_sort_dir(sort_dir):
if sort_dir not in ['asc', 'desc']:
raise wsme.exc.ClientSideError(_("Invalid sort direction: %s. "
"Acceptable values are "
"'asc' or 'desc'") % sort_dir)
raise exception.ClientSideError(_("Invalid sort direction: %s. "
"Acceptable values are "
"'asc' or 'desc'") % sort_dir)
return sort_dir
def validate_trait(trait, error_prefix=_('Invalid trait')):
error = wsme.exc.ClientSideError(
error = exception.ClientSideError(
_('%(error_prefix)s. A valid trait must be no longer than 255 '
'characters. Standard traits are defined in the os_traits library. '
'A custom trait must start with the prefix CUSTOM_ and use '
@ -125,7 +125,7 @@ def apply_jsonpatch(doc, patch):
:param patch: The JSON patch to apply.
:returns: The result of the patch operation.
:raises: PatchError if the patch fails to apply.
:raises: wsme.exc.ClientSideError if the patch adds a new root attribute.
:raises: exception.ClientSideError if the patch adds a new root attribute.
"""
# Prevent removal of root attributes.
for p in patch:
@ -133,7 +133,7 @@ def apply_jsonpatch(doc, patch):
if p['path'].lstrip('/') not in doc:
msg = _('Adding a new attribute (%s) to the root of '
'the resource is not allowed')
raise wsme.exc.ClientSideError(msg % p['path'])
raise exception.ClientSideError(msg % p['path'])
# Apply operations one at a time, to improve error reporting.
for patch_op in patch:
@ -403,7 +403,7 @@ def vendor_passthru(ident, method, topic, data=None, driver_passthru=False):
"""
if not method:
raise wsme.exc.ClientSideError(_("Method not specified"))
raise exception.ClientSideError(_("Method not specified"))
if data is None:
data = {}
@ -638,14 +638,14 @@ def check_allow_configdrive(target, configdrive=None):
if target not in allowed_targets:
msg = (_('Adding a config drive is only supported when setting '
'provision state to %s') % ', '.join(allowed_targets))
raise wsme.exc.ClientSideError(
raise exception.ClientSideError(
msg, status_code=http_client.BAD_REQUEST)
try:
jsonschema.validate(configdrive, _CONFIG_DRIVE_SCHEMA)
except json_schema_exc.ValidationError as e:
msg = _('Invalid configdrive format: %s') % e
raise wsme.exc.ClientSideError(
raise exception.ClientSideError(
msg, status_code=http_client.BAD_REQUEST)
if isinstance(configdrive, dict):
@ -654,7 +654,7 @@ def check_allow_configdrive(target, configdrive=None):
' starting with API version %(base)s.%(opr)s') % {
'base': versions.BASE_VERSION,
'opr': versions.MINOR_56_BUILD_CONFIGDRIVE}
raise wsme.exc.ClientSideError(
raise exception.ClientSideError(
msg, status_code=http_client.BAD_REQUEST)
if ('vendor_data' in configdrive and
not allow_configdrive_vendor_data()):
@ -662,7 +662,7 @@ def check_allow_configdrive(target, configdrive=None):
' starting with API version %(base)s.%(opr)s') % {
'base': versions.BASE_VERSION,
'opr': versions.MINOR_59_CONFIGDRIVE_VENDOR_DATA}
raise wsme.exc.ClientSideError(
raise exception.ClientSideError(
msg, status_code=http_client.BAD_REQUEST)
@ -682,7 +682,7 @@ def check_allow_filter_by_fault(fault):
msg = (_('Unrecognized fault "%(fault)s" is specified, allowed faults '
'are %(valid_faults)s') %
{'fault': fault, 'valid_faults': faults.VALID_FAULTS})
raise wsme.exc.ClientSideError(
raise exception.ClientSideError(
msg, status_code=http_client.BAD_REQUEST)

View File

@ -20,6 +20,7 @@ from http import client as http_client
from ironic_lib.exception import IronicException
from oslo_log import log as logging
import wsme
from ironic.common.i18n import _
@ -705,3 +706,7 @@ class IBMCError(DriverOperationError):
class IBMCConnectionError(IBMCError):
_msg_fmt = _("IBMC connection failed for node %(node)s: %(error)s")
class ClientSideError(wsme.exc.ClientSideError):
pass

View File

@ -47,17 +47,17 @@ class TestApiUtils(base.TestCase):
self.assertEqual(CONF.api.max_limit, limit)
# negative
self.assertRaises(wsme.exc.ClientSideError, utils.validate_limit, -1)
self.assertRaises(exception.ClientSideError, utils.validate_limit, -1)
# zero
self.assertRaises(wsme.exc.ClientSideError, utils.validate_limit, 0)
self.assertRaises(exception.ClientSideError, utils.validate_limit, 0)
def test_validate_sort_dir(self):
sort_dir = utils.validate_sort_dir('asc')
self.assertEqual('asc', sort_dir)
# invalid sort_dir parameter
self.assertRaises(wsme.exc.ClientSideError,
self.assertRaises(exception.ClientSideError,
utils.validate_sort_dir,
'fake-sort')
@ -65,25 +65,25 @@ class TestApiUtils(base.TestCase):
utils.validate_trait(os_traits.HW_CPU_X86_AVX2)
utils.validate_trait("CUSTOM_1")
utils.validate_trait("CUSTOM_TRAIT_GOLD")
self.assertRaises(wsme.exc.ClientSideError,
self.assertRaises(exception.ClientSideError,
utils.validate_trait, "A" * 256)
self.assertRaises(wsme.exc.ClientSideError,
self.assertRaises(exception.ClientSideError,
utils.validate_trait, "CuSTOM_1")
self.assertRaises(wsme.exc.ClientSideError,
self.assertRaises(exception.ClientSideError,
utils.validate_trait, "")
self.assertRaises(wsme.exc.ClientSideError,
self.assertRaises(exception.ClientSideError,
utils.validate_trait, "CUSTOM_bob")
self.assertRaises(wsme.exc.ClientSideError,
self.assertRaises(exception.ClientSideError,
utils.validate_trait, "CUSTOM_1-BOB")
self.assertRaises(wsme.exc.ClientSideError,
self.assertRaises(exception.ClientSideError,
utils.validate_trait, "aCUSTOM_1a")
large = "CUSTOM_" + ("1" * 248)
self.assertEqual(255, len(large))
utils.validate_trait(large)
self.assertRaises(wsme.exc.ClientSideError,
self.assertRaises(exception.ClientSideError,
utils.validate_trait, large + "1")
# Check custom error prefix.
self.assertRaisesRegex(wsme.exc.ClientSideError,
self.assertRaisesRegex(exception.ClientSideError,
"spongebob",
utils.validate_trait, "invalid", "spongebob")
@ -97,7 +97,7 @@ class TestApiUtils(base.TestCase):
def test_apply_jsonpatch_no_add_root_attr(self):
doc = {}
patch = [{"op": "add", "path": "/foo", "value": 42}]
self.assertRaisesRegex(wsme.exc.ClientSideError,
self.assertRaisesRegex(exception.ClientSideError,
"Adding a new attribute",
utils.apply_jsonpatch, doc, patch)
@ -488,14 +488,14 @@ class TestCheckAllowFields(base.TestCase):
def test_check_allow_configdrive_fails(self, mock_request):
mock_request.version.minor = 35
self.assertRaises(wsme.exc.ClientSideError,
self.assertRaises(exception.ClientSideError,
utils.check_allow_configdrive, states.DELETED,
"abcd")
self.assertRaises(wsme.exc.ClientSideError,
self.assertRaises(exception.ClientSideError,
utils.check_allow_configdrive, states.ACTIVE,
{'meta_data': {}})
mock_request.version.minor = 34
self.assertRaises(wsme.exc.ClientSideError,
self.assertRaises(exception.ClientSideError,
utils.check_allow_configdrive, states.REBUILD,
"abcd")
@ -518,7 +518,7 @@ class TestCheckAllowFields(base.TestCase):
def test_check_allow_configdrive_vendor_data_failed(self, mock_request):
mock_request.version.minor = 58
self.assertRaises(wsme.exc.ClientSideError,
self.assertRaises(exception.ClientSideError,
utils.check_allow_configdrive,
states.ACTIVE,
{'meta_data': {},
@ -528,15 +528,15 @@ class TestCheckAllowFields(base.TestCase):
def test_check_allow_configdrive_as_dict_invalid(self, mock_request):
mock_request.version.minor = 59
self.assertRaises(wsme.exc.ClientSideError,
self.assertRaises(exception.ClientSideError,
utils.check_allow_configdrive, states.REBUILD,
{'foo': 'bar'})
for key in ['meta_data', 'network_data']:
self.assertRaises(wsme.exc.ClientSideError,
self.assertRaises(exception.ClientSideError,
utils.check_allow_configdrive, states.REBUILD,
{key: 'a string'})
for key in ['meta_data', 'network_data', 'user_data']:
self.assertRaises(wsme.exc.ClientSideError,
self.assertRaises(exception.ClientSideError,
utils.check_allow_configdrive, states.REBUILD,
{key: 42})
@ -654,7 +654,7 @@ class TestNodeIdent(base.TestCase):
class TestVendorPassthru(base.TestCase):
def test_method_not_specified(self):
self.assertRaises(wsme.exc.ClientSideError,
self.assertRaises(exception.ClientSideError,
utils.vendor_passthru, 'fake-ident',
None, 'fake-topic', data='fake-data')