summaryrefslogtreecommitdiffstats
path: root/nova
diff options
context:
space:
mode:
authorBrian Waldon <bcwaldon@gmail.com>2012-02-03 13:29:57 -0800
committerBrian Waldon <bcwaldon@gmail.com>2012-02-14 12:20:20 -0800
commitafd5b22368076fc640563b7df6fb71dab57fe627 (patch)
tree9656e48da966bcb95106d99b3a1f43725870a627 /nova
parentc9ca372b0b9fe887dd3ac6bdb02514b5495a1917 (diff)
Replace ApiError with new exceptions
* Convert ApiError to EC2APIError * Add new exceptions to replace ApiError where it didn't belong * Fixes bug 926250 Change-Id: Ia711440ee0313faf8ea8c87e2c0a2f5b39cc55a2
Diffstat (limited to 'nova')
-rw-r--r--nova/api/ec2/__init__.py4
-rw-r--r--nova/api/ec2/cloud.py38
-rw-r--r--nova/api/openstack/compute/contrib/cloudpipe.py2
-rw-r--r--nova/api/openstack/compute/contrib/console_output.py4
-rw-r--r--nova/api/openstack/compute/contrib/consoles.py4
-rw-r--r--nova/api/openstack/compute/contrib/floating_ips.py10
-rw-r--r--nova/api/openstack/compute/contrib/server_start_stop.py32
-rw-r--r--nova/api/openstack/compute/contrib/volumetypes.py2
-rw-r--r--nova/api/openstack/compute/server_metadata.py2
-rw-r--r--nova/api/openstack/compute/servers.py8
-rw-r--r--nova/api/openstack/volume/types.py2
-rw-r--r--nova/compute/api.py56
-rw-r--r--nova/compute/instance_types.py20
-rw-r--r--nova/exception.py44
-rw-r--r--nova/network/manager.py6
-rw-r--r--nova/tests/api/ec2/test_cloud.py15
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_console_output.py13
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_consoles.py13
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_server_start_stop.py7
-rw-r--r--nova/tests/scheduler/test_vsa_scheduler.py2
-rw-r--r--nova/tests/test_SolidFireSanISCSIDriver.py2
-rw-r--r--nova/tests/test_compute.py4
-rw-r--r--nova/tests/test_exception.py6
-rw-r--r--nova/tests/test_instance_types.py14
-rw-r--r--nova/tests/test_volume.py2
-rw-r--r--nova/tests/test_volume_types.py2
-rw-r--r--nova/tests/test_vsa.py8
-rw-r--r--nova/tests/test_vsa_volumes.py4
-rw-r--r--nova/virt/baremetal/proxy.py4
-rw-r--r--nova/virt/vmwareapi/vmops.py12
-rw-r--r--nova/volume/api.py25
-rw-r--r--nova/volume/san.py28
-rw-r--r--nova/volume/volume_types.py30
-rw-r--r--nova/vsa/api.py39
34 files changed, 236 insertions, 228 deletions
diff --git a/nova/api/ec2/__init__.py b/nova/api/ec2/__init__.py
index ddb3a2044..416783c45 100644
--- a/nova/api/ec2/__init__.py
+++ b/nova/api/ec2/__init__.py
@@ -598,8 +598,8 @@ class Executor(wsgi.Application):
except exception.NotFound as ex:
LOG.info(_('NotFound raised: %s'), unicode(ex), context=context)
return ec2_error(req, request_id, type(ex).__name__, unicode(ex))
- except exception.ApiError as ex:
- LOG.exception(_('ApiError raised: %s'), unicode(ex),
+ except exception.EC2APIError as ex:
+ LOG.exception(_('EC2APIError raised: %s'), unicode(ex),
context=context)
if ex.code:
return ec2_error(req, request_id, ex.code, unicode(ex))
diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py
index 5ac69b1a7..560a2d0dd 100644
--- a/nova/api/ec2/cloud.py
+++ b/nova/api/ec2/cloud.py
@@ -600,7 +600,7 @@ class CloudController(object):
group_id=None, **kwargs):
if not group_name and not group_id:
err = "Not enough parameters, need group_name or group_id"
- raise exception.ApiError(_(err))
+ raise exception.EC2APIError(_(err))
self.compute_api.ensure_default_security_group(context)
notfound = exception.SecurityGroupNotFound
if group_name:
@@ -626,7 +626,7 @@ class CloudController(object):
rulesvalues = self._rule_args_to_dict(context, values)
if not rulesvalues:
err = "%s Not enough parameters to build a valid rule"
- raise exception.ApiError(_(err % rulesvalues))
+ raise exception.EC2APIError(_(err % rulesvalues))
for values_for_rule in rulesvalues:
values_for_rule['parent_group_id'] = security_group.id
@@ -640,7 +640,7 @@ class CloudController(object):
context,
security_group_id=security_group['id'])
return True
- raise exception.ApiError(_("No rule for the specified parameters."))
+ raise exception.EC2APIError(_("No rule for the specified parameters."))
# TODO(soren): This has only been tested with Boto as the client.
# Unfortunately, it seems Boto is using an old API
@@ -650,7 +650,7 @@ class CloudController(object):
group_id=None, **kwargs):
if not group_name and not group_id:
err = "Not enough parameters, need group_name or group_id"
- raise exception.ApiError(_(err))
+ raise exception.EC2APIError(_(err))
self.compute_api.ensure_default_security_group(context)
notfound = exception.SecurityGroupNotFound
if group_name:
@@ -676,13 +676,13 @@ class CloudController(object):
rulesvalues = self._rule_args_to_dict(context, values)
if not rulesvalues:
err = "%s Not enough parameters to build a valid rule"
- raise exception.ApiError(_(err % rulesvalues))
+ raise exception.EC2APIError(_(err % rulesvalues))
for values_for_rule in rulesvalues:
values_for_rule['parent_group_id'] = security_group.id
if self._security_group_rule_exists(security_group,
values_for_rule):
err = '%s - This rule already exists in group'
- raise exception.ApiError(_(err) % values_for_rule)
+ raise exception.EC2APIError(_(err) % values_for_rule)
postvalues.append(values_for_rule)
for values_for_rule in postvalues:
@@ -696,7 +696,7 @@ class CloudController(object):
security_group_id=security_group['id'])
return True
- raise exception.ApiError(_("No rule for the specified parameters."))
+ raise exception.EC2APIError(_("No rule for the specified parameters."))
def _get_source_project_id(self, context, source_security_group_owner_id):
if source_security_group_owner_id:
@@ -735,7 +735,8 @@ class CloudController(object):
LOG.audit(_("Create Security Group %s"), group_name, context=context)
self.compute_api.ensure_default_security_group(context)
if db.security_group_exists(context, context.project_id, group_name):
- raise exception.ApiError(_('group %s already exists') % group_name)
+ msg = _('group %s already exists')
+ raise exception.EC2APIError(msg % group_name)
group = {'user_id': context.user_id,
'project_id': context.project_id,
@@ -750,7 +751,7 @@ class CloudController(object):
**kwargs):
if not group_name and not group_id:
err = "Not enough parameters, need group_name or group_id"
- raise exception.ApiError(_(err))
+ raise exception.EC2APIError(_(err))
notfound = exception.SecurityGroupNotFound
if group_name:
security_group = db.security_group_get_by_name(context,
@@ -906,7 +907,7 @@ class CloudController(object):
def describe_instance_attribute(self, context, instance_id, attribute,
**kwargs):
def _unsupported_attribute(instance, result):
- raise exception.ApiError(_('attribute not supported: %s') %
+ raise exception.EC2APIError(_('attribute not supported: %s') %
attribute)
def _format_attr_block_device_mapping(instance, result):
@@ -962,7 +963,7 @@ class CloudController(object):
fn = attribute_formatter.get(attribute)
if fn is None:
- raise exception.ApiError(
+ raise exception.EC2APIError(
_('attribute not supported: %s') % attribute)
ec2_instance_id = instance_id
@@ -1225,7 +1226,7 @@ class CloudController(object):
raise exception.ImageNotFound(image_id=kwargs['image_id'])
if image_state != 'available':
- raise exception.ApiError(_('Image must be available'))
+ raise exception.EC2APIError(_('Image must be available'))
(instances, resv_id) = self.compute_api.create(context,
instance_type=instance_types.get_instance_type_by_name(
@@ -1425,7 +1426,7 @@ class CloudController(object):
fn = supported_attributes.get(attribute)
if fn is None:
- raise exception.ApiError(_('attribute not supported: %s')
+ raise exception.EC2APIError(_('attribute not supported: %s')
% attribute)
try:
image = self._get_image(context, image_id)
@@ -1440,14 +1441,15 @@ class CloudController(object):
operation_type, **kwargs):
# TODO(devcamcar): Support users and groups other than 'all'.
if attribute != 'launchPermission':
- raise exception.ApiError(_('attribute not supported: %s')
+ raise exception.EC2APIError(_('attribute not supported: %s')
% attribute)
if not 'user_group' in kwargs:
- raise exception.ApiError(_('user or group not specified'))
+ raise exception.EC2APIError(_('user or group not specified'))
if len(kwargs['user_group']) != 1 and kwargs['user_group'][0] != 'all':
- raise exception.ApiError(_('only group "all" is supported'))
+ raise exception.EC2APIError(_('only group "all" is supported'))
if not operation_type in ['add', 'remove']:
- raise exception.ApiError(_('operation_type must be add or remove'))
+ msg = _('operation_type must be add or remove')
+ raise exception.EC2APIError(msg)
LOG.audit(_("Updating image %s publicity"), image_id, context=context)
try:
@@ -1504,7 +1506,7 @@ class CloudController(object):
# Or is there any better way?
timeout = 1 * 60 * 60 * 60
if time.time() > start_time + timeout:
- raise exception.ApiError(
+ raise exception.EC2APIError(
_('Couldn\'t stop instance with in %d sec') % timeout)
src_image = self._get_image(context, instance['image_ref'])
diff --git a/nova/api/openstack/compute/contrib/cloudpipe.py b/nova/api/openstack/compute/contrib/cloudpipe.py
index d5a975840..83c4bb47a 100644
--- a/nova/api/openstack/compute/contrib/cloudpipe.py
+++ b/nova/api/openstack/compute/contrib/cloudpipe.py
@@ -116,7 +116,7 @@ class CloudpipeController(object):
except db.NoMoreNetworks:
msg = _("Unable to claim IP for VPN instances, ensure it "
"isn't running, and try again in a few minutes")
- raise exception.ApiError(msg)
+ raise exception.HTTPBadRequest(explanation=msg)
instance = self._get_cloudpipe_for_project(ctxt, proj)
return {'instance_id': instance['uuid']}
diff --git a/nova/api/openstack/compute/contrib/console_output.py b/nova/api/openstack/compute/contrib/console_output.py
index a9db43358..0752c3c70 100644
--- a/nova/api/openstack/compute/contrib/console_output.py
+++ b/nova/api/openstack/compute/contrib/console_output.py
@@ -54,8 +54,8 @@ class ConsoleOutputController(wsgi.Controller):
output = self.compute_api.get_console_output(context,
instance,
length)
- except exception.ApiError, e:
- raise webob.exc.HTTPBadRequest(explanation=e.message)
+ except exception.NotFound:
+ raise webob.exc.HTTPNotFound(_('Instance not found'))
return {'output': output}
diff --git a/nova/api/openstack/compute/contrib/consoles.py b/nova/api/openstack/compute/contrib/consoles.py
index 7cf757fd1..f308c6717 100644
--- a/nova/api/openstack/compute/contrib/consoles.py
+++ b/nova/api/openstack/compute/contrib/consoles.py
@@ -54,10 +54,10 @@ class ConsolesController(wsgi.Controller):
console_type)
except exception.ConsoleTypeInvalid, e:
raise webob.exc.HTTPBadRequest(_('Invalid type specification'))
- except exception.ApiError, e:
- raise webob.exc.HTTPBadRequest(explanation=e.message)
except exception.NotAuthorized, e:
raise webob.exc.HTTPUnauthorized()
+ except exception.NotFound:
+ raise webob.exc.HTTPNotFound(_('Instance not found'))
return {'console': {'type': console_type, 'url': output['url']}}
diff --git a/nova/api/openstack/compute/contrib/floating_ips.py b/nova/api/openstack/compute/contrib/floating_ips.py
index 291d09554..ad74bc8a8 100644
--- a/nova/api/openstack/compute/contrib/floating_ips.py
+++ b/nova/api/openstack/compute/contrib/floating_ips.py
@@ -204,14 +204,14 @@ class FloatingIPActionController(wsgi.Controller):
msg = _("Address not specified")
raise webob.exc.HTTPBadRequest(explanation=msg)
+ instance = self.compute_api.get(context, id)
+
try:
- instance = self.compute_api.get(context, id)
self.compute_api.associate_floating_ip(context, instance,
address)
- except exception.ApiError, e:
- raise webob.exc.HTTPBadRequest(explanation=e.message)
- except exception.NotAuthorized, e:
- raise webob.exc.HTTPUnauthorized()
+ except exception.FixedIpNotFoundForInstance:
+ msg = _("No fixed ips associated to instance")
+ raise webob.exc.HTTPBadRequest(explanation=msg)
except rpc.RemoteError:
msg = _("Associate floating ip failed")
raise webob.exc.HTTPInternalServerError(explanation=msg)
diff --git a/nova/api/openstack/compute/contrib/server_start_stop.py b/nova/api/openstack/compute/contrib/server_start_stop.py
index 9bf71fdc5..5729a2b30 100644
--- a/nova/api/openstack/compute/contrib/server_start_stop.py
+++ b/nova/api/openstack/compute/contrib/server_start_stop.py
@@ -31,35 +31,29 @@ class ServerStartStopActionController(wsgi.Controller):
super(ServerStartStopActionController, self).__init__(*args, **kwargs)
self.compute_api = compute.API()
+ def _get_instance(self, context, instance_uuid):
+ try:
+ return self.compute_api.get(context, instance_uuid)
+ except exception.NotFound:
+ msg = _("Instance not found")
+ raise webob.exc.HTTPNotFound(explanation=msg)
+
@wsgi.action('os-start')
def _start_server(self, req, id, body):
"""Start an instance. """
context = req.environ['nova.context']
-
- try:
- LOG.debug(_("start instance %r"), id)
- instance = self.compute_api.get(context, id)
- self.compute_api.start(context, instance)
- except exception.ApiError, e:
- raise webob.exc.HTTPBadRequest(explanation=e.message)
- except exception.NotAuthorized, e:
- raise webob.exc.HTTPUnauthorized()
+ LOG.debug(_("start instance %r"), id)
+ instance = self._get_instance(context, id)
+ self.compute_api.start(context, instance)
return webob.Response(status_int=202)
@wsgi.action('os-stop')
def _stop_server(self, req, id, body):
"""Stop an instance."""
context = req.environ['nova.context']
-
- try:
- LOG.debug(_("stop instance %r"), id)
- instance = self.compute_api.get(context, id)
- self.compute_api.stop(context, instance)
- except exception.ApiError, e:
- raise webob.exc.HTTPBadRequest(explanation=e.message)
- except exception.NotAuthorized, e:
- raise webob.exc.HTTPUnauthorized()
-
+ LOG.debug(_("stop instance %r"), id)
+ instance = self._get_instance(context, id)
+ self.compute_api.stop(context, instance)
return webob.Response(status_int=202)
diff --git a/nova/api/openstack/compute/contrib/volumetypes.py b/nova/api/openstack/compute/contrib/volumetypes.py
index cbc205ea7..af68b3adb 100644
--- a/nova/api/openstack/compute/contrib/volumetypes.py
+++ b/nova/api/openstack/compute/contrib/volumetypes.py
@@ -100,7 +100,7 @@ class VolumeTypesController(object):
try:
vol_type = volume_types.get_volume_type(context, id)
- except exception.NotFound or exception.ApiError:
+ except exception.NotFound:
raise exc.HTTPNotFound()
return {'volume_type': vol_type}
diff --git a/nova/api/openstack/compute/server_metadata.py b/nova/api/openstack/compute/server_metadata.py
index 52a90f96e..cd7ebb545 100644
--- a/nova/api/openstack/compute/server_metadata.py
+++ b/nova/api/openstack/compute/server_metadata.py
@@ -165,7 +165,7 @@ class Controller(object):
def _handle_quota_error(self, error):
"""Reraise quota errors as api-specific http exceptions."""
- if error.code == "MetadataLimitExceeded":
+ if error.kwargs['code'] == "MetadataLimitExceeded":
raise exc.HTTPRequestEntityTooLarge(explanation=error.message,
headers={'Retry-After': 0})
raise error
diff --git a/nova/api/openstack/compute/servers.py b/nova/api/openstack/compute/servers.py
index b55e8c6a3..a9d3a93a2 100644
--- a/nova/api/openstack/compute/servers.py
+++ b/nova/api/openstack/compute/servers.py
@@ -496,12 +496,8 @@ class Controller(wsgi.Controller):
"InstanceLimitExceeded": error.message,
}
- expl = code_mappings.get(error.code)
- if expl:
- raise exc.HTTPRequestEntityTooLarge(explanation=expl,
- headers={'Retry-After': 0})
- # if the original error is okay, just reraise it
- raise exc.HTTPRequestEntityTooLarge(explanation=error.msg,
+ expl = code_mappings.get(error.kwargs['code'], error.message)
+ raise exc.HTTPRequestEntityTooLarge(explanation=expl,
headers={'Retry-After': 0})
def _validate_server_name(self, value):
diff --git a/nova/api/openstack/volume/types.py b/nova/api/openstack/volume/types.py
index 609a6cfc9..97fb52497 100644
--- a/nova/api/openstack/volume/types.py
+++ b/nova/api/openstack/volume/types.py
@@ -64,7 +64,7 @@ class VolumeTypesController(object):
try:
vol_type = volume_types.get_volume_type(context, id)
- except exception.NotFound or exception.ApiError:
+ except exception.NotFound:
raise exc.HTTPNotFound()
return {'volume_type': vol_type}
diff --git a/nova/compute/api.py b/nova/compute/api.py
index 6ba022b65..30fe911ff 100644
--- a/nova/compute/api.py
+++ b/nova/compute/api.py
@@ -136,8 +136,8 @@ class API(base.Base):
content_limit = quota.allowed_injected_file_content_bytes(
context, len(content))
if len(content) > content_limit:
- raise exception.QuotaError(
- code="OnsetFileContentLimitExceeded")
+ code = "OnsetFileContentLimitExceeded"
+ raise exception.QuotaError(code=code)
def _check_metadata_properties_quota(self, context, metadata=None):
"""Enforce quota limits on metadata properties."""
@@ -150,7 +150,7 @@ class API(base.Base):
msg = _("Quota exceeded for %(pid)s, tried to set "
"%(num_metadata)s metadata properties") % locals()
LOG.warn(msg)
- raise exception.QuotaError(msg, "MetadataLimitExceeded")
+ raise exception.QuotaError(code="MetadataLimitExceeded")
# Because metadata is stored in the DB, we hard-code the size limits
# In future, we may support more variable length strings, so we act
@@ -161,7 +161,7 @@ class API(base.Base):
msg = _("Quota exceeded for %(pid)s, metadata property "
"key or value too long") % locals()
LOG.warn(msg)
- raise exception.QuotaError(msg, "MetadataLimitExceeded")
+ raise exception.QuotaError(code="MetadataLimitExceeded")
def _check_requested_networks(self, context, requested_networks):
""" Check if the networks requested belongs to the project
@@ -218,7 +218,7 @@ class API(base.Base):
else:
message = _("Instance quota exceeded. You can only run %s "
"more instances of this type.") % num_instances
- raise exception.QuotaError(message, "InstanceLimitExceeded")
+ raise exception.QuotaError(code="InstanceLimitExceeded")
self._check_metadata_properties_quota(context, metadata)
self._check_injected_file_quota(context, injected_files)
@@ -1631,8 +1631,7 @@ class API(base.Base):
def attach_volume(self, context, instance, volume_id, device):
"""Attach an existing volume to an existing instance."""
if not re.match("^/dev/x{0,1}[a-z]d[a-z]+$", device):
- raise exception.ApiError(_("Invalid device specified: %s. "
- "Example device: /dev/vdb") % device)
+ raise exception.InvalidDevicePath(path=device)
volume = self.volume_api.get(context, volume_id)
self.volume_api.check_attach(context, volume)
params = {"volume_id": volume_id,
@@ -1647,7 +1646,7 @@ class API(base.Base):
"""Detach a volume from an instance."""
instance = self.db.volume_get_instance(context.elevated(), volume_id)
if not instance:
- raise exception.ApiError(_("Volume isn't attached to anything!"))
+ raise exception.VolumeUnattached(volume_id=volume_id)
check_policy(context, 'detach_volume', instance)
@@ -1672,30 +1671,29 @@ class API(base.Base):
# in its info, if this changes, the next few lines will need to
# accommodate the info containing floating as well as fixed ip
# addresses
-
- fail_bag = _('instance |%s| has no fixed ips. '
- 'unable to associate floating ip') % instance_uuid
-
nw_info = self.network_api.get_instance_nw_info(context.elevated(),
instance)
- if nw_info:
- ips = [ip for ip in nw_info[0].fixed_ips()]
-
- # TODO(tr3buchet): this will associate the floating IP with the
- # first # fixed_ip (lowest id) an instance has. This should be
- # changed to # support specifying a particular fixed_ip if
- # multiple exist.
- if not ips:
- raise exception.ApiError(fail_bag)
- if len(ips) > 1:
- LOG.warning(_('multiple fixedips exist, using the first: %s'),
- ips[0]['address'])
- self.network_api.associate_floating_ip(context,
- floating_address=address,
- fixed_address=ips[0]['address'])
- return
- raise exception.ApiError(fail_bag)
+ if not nw_info:
+ raise exception.FixedIpNotFoundForInstance(
+ instance_id=instance_uuid)
+
+ ips = [ip for ip in nw_info[0].fixed_ips()]
+
+ if not ips:
+ raise exception.FixedIpNotFoundForInstance(
+ instance_id=instance_uuid)
+
+ # TODO(tr3buchet): this will associate the floating IP with the
+ # first fixed_ip (lowest id) an instance has. This should be
+ # changed to support specifying a particular fixed_ip if
+ # multiple exist.
+ if len(ips) > 1:
+ msg = _('multiple fixedips exist, using the first: %s')
+ LOG.warning(msg, ips[0]['address'])
+
+ self.network_api.associate_floating_ip(context,
+ floating_address=address, fixed_address=ips[0]['address'])
@wrap_check_policy
def get_instance_metadata(self, context, instance):
diff --git a/nova/compute/instance_types.py b/nova/compute/instance_types.py
index 3b550502f..fa001f2cd 100644
--- a/nova/compute/instance_types.py
+++ b/nova/compute/instance_types.py
@@ -72,9 +72,7 @@ def create(name, memory, vcpus, root_gb, ephemeral_gb, flavorid, swap=None,
return db.instance_type_create(context.get_admin_context(), kwargs)
except exception.DBError, e:
LOG.exception(_('DB error: %s') % e)
- msg = _("Cannot create instance_type with name %(name)s and "
- "flavorid %(flavorid)s") % locals()
- raise exception.ApiError(msg)
+ raise exception.InstanceTypeCreateFailed()
def destroy(name):
@@ -106,10 +104,7 @@ get_all_flavors = get_all_types
def get_default_instance_type():
"""Get the default instance type."""
name = FLAGS.default_instance_type
- try:
- return get_instance_type_by_name(name)
- except exception.InstanceTypeNotFound as e:
- raise exception.ApiError(e)
+ return get_instance_type_by_name(name)
def get_instance_type(instance_type_id):
@@ -118,10 +113,7 @@ def get_instance_type(instance_type_id):
return get_default_instance_type()
ctxt = context.get_admin_context()
- try:
- return db.instance_type_get(ctxt, instance_type_id)
- except exception.InstanceTypeNotFound as e:
- raise exception.ApiError(e)
+ return db.instance_type_get(ctxt, instance_type_id)
def get_instance_type_by_name(name):
@@ -130,11 +122,7 @@ def get_instance_type_by_name(name):
return get_default_instance_type()
ctxt = context.get_admin_context()
-
- try:
- return db.instance_type_get_by_name(ctxt, name)
- except exception.InstanceTypeNotFound as e:
- raise exception.ApiError(e)
+ return db.instance_type_get_by_name(ctxt, name)
# TODO(termie): flavor-specific code should probably be in the API that uses
diff --git a/nova/exception.py b/nova/exception.py
index 6f3d84717..dfa20dd25 100644
--- a/nova/exception.py
+++ b/nova/exception.py
@@ -80,7 +80,7 @@ class Error(Exception):
super(Error, self).__init__(message)
-class ApiError(Error):
+class EC2APIError(Error):
def __init__(self, message='Unknown', code=None):
self.msg = message
self.code = code
@@ -88,7 +88,7 @@ class ApiError(Error):
outstr = '%s: %s' % (code, message)
else:
outstr = '%s' % message
- super(ApiError, self).__init__(outstr)
+ super(EC2APIError, self).__init__(outstr)
class DBError(Error):
@@ -223,6 +223,14 @@ class Invalid(NovaException):
message = _("Unacceptable parameters.")
+class InvalidSnapshot(Invalid):
+ message = _("Invalid snapshot") + ": %(reason)s"
+
+
+class VolumeUnattached(Invalid):
+ message = _("Volume %(volume_id)s is not attached to anything")
+
+
class InvalidKeypair(Invalid):
message = _("Keypair data is invalid")
@@ -248,7 +256,11 @@ class InvalidInstanceType(Invalid):
class InvalidVolumeType(Invalid):
- message = _("Invalid volume type %(volume_type)s.")
+ message = _("Invalid volume type") + ": %(reason)s"
+
+
+class InvalidVolume(Invalid):
+ message = _("Invalid volume") + ": %(reason)s"
class InvalidPortRange(Invalid):
@@ -930,9 +942,8 @@ class WillNotSchedule(NovaException):
message = _("Host %(host)s is not up or doesn't exist.")
-class QuotaError(ApiError):
- """Quota Exceeded."""
- pass
+class QuotaError(NovaException):
+ message = _("Quota exceeded") + ": code=%(code)s"
class AggregateNotFound(NotFound):
@@ -962,3 +973,24 @@ class AggregateHostExists(Duplicate):
class DuplicateSfVolumeNames(Duplicate):
message = _("Detected more than one volume with name %(vol_name)")
+
+
+class VolumeTypeCreateFailed(NovaException):
+ message = _("Cannot create volume_type with "
+ "name %(name)s and specs %(extra_specs)s")
+
+
+class InstanceTypeCreateFailed(NovaException):
+ message = _("Unable to create instance type")
+
+
+class SolidFireAPIException(NovaException):
+ message = _("Bad response from SolidFire API")
+
+
+class SolidFireAPIStatusException(SolidFireAPIException):
+ message = _("Error in SolidFire API response: status=%(status)s")
+
+
+class SolidFireAPIDataException(SolidFireAPIException):
+ message = _("Error in SolidFire API response: data=%(data)s")
diff --git a/nova/network/manager.py b/nova/network/manager.py
index e42e06692..a8d5593d9 100644
--- a/nova/network/manager.py
+++ b/nova/network/manager.py
@@ -368,11 +368,9 @@ class FloatingIP(object):
# NOTE(tr3buchet): all network hosts in zone now use the same pool
LOG.debug("QUOTA: %s" % quota.allowed_floating_ips(context, 1))
if quota.allowed_floating_ips(context, 1) < 1:
- LOG.warn(_('Quota exceeded for %s, tried to allocate '
- 'address'),
+ LOG.warn(_('Quota exceeded for %s, tried to allocate address'),
context.project_id)
- raise exception.QuotaError(_('Address quota exceeded. You cannot '
- 'allocate any more addresses'))
+ raise exception.QuotaError(code='AddressLimitExceeded')
pool = pool or FLAGS.default_floating_pool
return self.db.floating_ip_allocate_address(context,
project_id,
diff --git a/nova/tests/api/ec2/test_cloud.py b/nova/tests/api/ec2/test_cloud.py
index d24f1321b..168088150 100644
--- a/nova/tests/api/ec2/test_cloud.py
+++ b/nova/tests/api/ec2/test_cloud.py
@@ -285,7 +285,7 @@ class CloudTestCase(test.TestCase):
def test_delete_security_group_no_params(self):
delete = self.cloud.delete_security_group
- self.assertRaises(exception.ApiError, delete, self.context)
+ self.assertRaises(exception.EC2APIError, delete, self.context)
def test_authorize_security_group_ingress(self):
kwargs = {'project_id': self.context.project_id, 'name': 'test'}
@@ -415,12 +415,12 @@ class CloudTestCase(test.TestCase):
{'project_id': self.context.project_id,
'name': 'test'})
authz = self.cloud.authorize_security_group_ingress
- self.assertRaises(exception.ApiError, authz, self.context, 'test')
+ self.assertRaises(exception.EC2APIError, authz, self.context, 'test')
def test_authorize_security_group_ingress_missing_group_name_or_id(self):
kwargs = {'project_id': self.context.project_id, 'name': 'test'}
authz = self.cloud.authorize_security_group_ingress
- self.assertRaises(exception.ApiError, authz, self.context, **kwargs)
+ self.assertRaises(exception.EC2APIError, authz, self.context, **kwargs)
def test_authorize_security_group_ingress_already_exists(self):
kwargs = {'project_id': self.context.project_id, 'name': 'test'}
@@ -428,13 +428,14 @@ class CloudTestCase(test.TestCase):
authz = self.cloud.authorize_security_group_ingress
kwargs = {'to_port': '999', 'from_port': '999', 'ip_protocol': 'tcp'}
authz(self.context, group_name=sec['name'], **kwargs)
- self.assertRaises(exception.ApiError, authz, self.context,
+ self.assertRaises(exception.EC2APIError, authz, self.context,
group_name=sec['name'], **kwargs)
def test_revoke_security_group_ingress_missing_group_name_or_id(self):
kwargs = {'to_port': '999', 'from_port': '999', 'ip_protocol': 'tcp'}
revoke = self.cloud.revoke_security_group_ingress
- self.assertRaises(exception.ApiError, revoke, self.context, **kwargs)
+ self.assertRaises(exception.EC2APIError, revoke,
+ self.context, **kwargs)
def test_describe_volumes(self):
"""Makes sure describe_volumes works and filters results."""
@@ -1315,7 +1316,7 @@ class CloudTestCase(test.TestCase):
self.stubs.UnsetAll()
self.stubs.Set(fake._FakeImageService, 'show', fake_show_no_state)
- self.assertRaises(exception.ApiError, run_instances,
+ self.assertRaises(exception.EC2APIError, run_instances,
self.context, **kwargs)
def test_run_instances_image_state_invalid(self):
@@ -1334,7 +1335,7 @@ class CloudTestCase(test.TestCase):
self.stubs.UnsetAll()
self.stubs.Set(fake._FakeImageService, 'show', fake_show_decrypt)
- self.assertRaises(exception.ApiError, run_instances,
+ self.assertRaises(exception.EC2APIError, run_instances,
self.context, **kwargs)
def test_run_instances_image_status_active(self):
diff --git a/nova/tests/api/openstack/compute/contrib/test_console_output.py b/nova/tests/api/openstack/compute/contrib/test_console_output.py
index ad22ff4cf..c553df0ca 100644
--- a/nova/tests/api/openstack/compute/contrib/test_console_output.py
+++ b/nova/tests/api/openstack/compute/contrib/test_console_output.py
@@ -40,7 +40,7 @@ def fake_get(self, context, instance_uuid):
return {'uuid': instance_uuid}
-def fake_get_not_found(self, context, instance_uuid):
+def fake_get_not_found(*args, **kwargs):
raise exception.NotFound()
@@ -86,6 +86,17 @@ class ConsoleOutputExtensionTest(test.TestCase):
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 404)
+ def test_get_text_console_no_instance_on_get_output(self):
+ self.stubs.Set(compute.API, 'get_console_output', fake_get_not_found)
+ body = {'os-getConsoleOutput': {}}
+ req = webob.Request.blank('/v2/fake/servers/1/action')
+ req.method = "POST"
+ req.body = json.dumps(body)
+ req.headers["content-type"] = "application/json"
+
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 404)
+
def test_get_text_console_bad_body(self):
body = {}
req = webob.Request.blank('/v2/fake/servers/1/action')
diff --git a/nova/tests/api/openstack/compute/contrib/test_consoles.py b/nova/tests/api/openstack/compute/contrib/test_consoles.py
index 0ed177a33..668d896ec 100644
--- a/nova/tests/api/openstack/compute/contrib/test_consoles.py
+++ b/nova/tests/api/openstack/compute/contrib/test_consoles.py
@@ -36,7 +36,7 @@ def fake_get(self, context, instance_uuid):
return {'uuid': instance_uuid}
-def fake_get_not_found(self, context, instance_uuid):
+def fake_get_not_found(*args, **kwargs):
raise exception.NotFound()
@@ -83,6 +83,17 @@ class ConsolesExtensionTest(test.TestCase):
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 404)
+ def test_get_vnc_console_no_instance_on_console_get(self):
+ self.stubs.Set(compute.API, 'get_vnc_console', fake_get_not_found)
+ body = {'os-getVNCConsole': {'type': 'novnc'}}
+ req = webob.Request.blank('/v2/fake/servers/1/action')
+ req.method = "POST"
+ req.body = json.dumps(body)
+ req.headers["content-type"] = "application/json"
+
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 404)
+
def test_get_vnc_console_invalid_type(self):
self.stubs.Set(compute.API, 'get', fake_get)
body = {'os-getVNCConsole': {'type': 'invalid'}}
diff --git a/nova/tests/api/openstack/compute/contrib/test_server_start_stop.py b/nova/tests/api/openstack/compute/contrib/test_server_start_stop.py
index 31b2b7308..44ea00e9e 100644
--- a/nova/tests/api/openstack/compute/contrib/test_server_start_stop.py
+++ b/nova/tests/api/openstack/compute/contrib/test_server_start_stop.py
@@ -13,11 +13,12 @@
# under the License.
import unittest
+
import mox
+import webob
from nova.api.openstack.compute.contrib import server_start_stop
from nova import context
-from nova import exception
from nova import compute
from nova import test
from nova.tests.api.openstack import fakes
@@ -60,13 +61,13 @@ class ServerStartStopTest(test.TestCase):
def test_start_with_bogus_id(self):
req = fakes.HTTPRequest.blank('/v2/fake/servers/test_inst/action')
body = dict(start="")
- self.assertRaises(exception.InstanceNotFound,
+ self.assertRaises(webob.exc.HTTPNotFound,
self.controller._start_server, req, 'test_inst', body)
def test_stop_with_bogus_id(self):
req = fakes.HTTPRequest.blank('/v2/fake/servers/test_inst/action')
body = dict(start="")
- self.assertRaises(exception.InstanceNotFound,
+ self.assertRaises(webob.exc.HTTPNotFound,
self.controller._stop_server, req, 'test_inst', body)
diff --git a/nova/tests/scheduler/test_vsa_scheduler.py b/nova/tests/scheduler/test_vsa_scheduler.py
index c4cf1fd3c..8e465271d 100644
--- a/nova/tests/scheduler/test_vsa_scheduler.py
+++ b/nova/tests/scheduler/test_vsa_scheduler.py
@@ -13,14 +13,12 @@
# License for the specific language governing permissions and limitations
# under the License.
-from nova import context
from nova import db
from nova import exception
from nova import flags
from nova import log as logging
from nova import rpc
from nova.scheduler import vsa as vsa_sched
-from nova import test
from nova.tests.scheduler import test_scheduler
from nova import utils
from nova.volume import volume_types
diff --git a/nova/tests/test_SolidFireSanISCSIDriver.py b/nova/tests/test_SolidFireSanISCSIDriver.py
index f5f4f47eb..0f3addddc 100644
--- a/nova/tests/test_SolidFireSanISCSIDriver.py
+++ b/nova/tests/test_SolidFireSanISCSIDriver.py
@@ -176,5 +176,5 @@ class SolidFireVolumeTestCase(test.TestCase):
def test_get_cluster_info_fail(self):
SFID._issue_api_request = self.fake_issue_api_request_fails
sfv = SFID()
- self.assertRaises(exception.ApiError,
+ self.assertRaises(exception.SolidFireAPIException,
sfv._get_cluster_info)
diff --git a/nova/tests/test_compute.py b/nova/tests/test_compute.py
index 3bab360c4..c6e3201d3 100644
--- a/nova/tests/test_compute.py
+++ b/nova/tests/test_compute.py
@@ -2357,7 +2357,7 @@ class ComputeAPITestCase(BaseTestCase):
address = '0.1.2.3'
self.compute.run_instance(self.context, instance_uuid)
- self.assertRaises(exception.ApiError,
+ self.assertRaises(exception.FixedIpNotFoundForInstance,
self.compute_api.associate_floating_ip,
self.context,
instance,
@@ -2967,7 +2967,7 @@ class ComputeAPITestCase(BaseTestCase):
self.compute_api.delete(self.context, instance)
def test_attach_volume_invalid(self):
- self.assertRaises(exception.ApiError,
+ self.assertRaises(exception.InvalidDevicePath,
self.compute_api.attach_volume,
self.context,
None,
diff --git a/nova/tests/test_exception.py b/nova/tests/test_exception.py
index d3bc1f6e8..3a1327065 100644
--- a/nova/tests/test_exception.py
+++ b/nova/tests/test_exception.py
@@ -20,15 +20,15 @@ from nova import test
from nova import exception
-class ApiErrorTestCase(test.TestCase):
+class EC2APIErrorTestCase(test.TestCase):
def test_return_valid_error(self):
# without 'code' arg
- err = exception.ApiError('fake error')
+ err = exception.EC2APIError('fake error')
self.assertEqual(err.__str__(), 'fake error')
self.assertEqual(err.code, None)
self.assertEqual(err.msg, 'fake error')
# with 'code' arg
- err = exception.ApiError('fake error', 'blah code')
+ err = exception.EC2APIError('fake error', 'blah code')
self.assertEqual(err.__str__(), 'blah code: fake error')
self.assertEqual(err.code, 'blah code')
self.assertEqual(err.msg, 'fake error')
diff --git a/nova/tests/test_instance_types.py b/nova/tests/test_instance_types.py
index 7baa9542f..dfa7d6136 100644
--- a/nova/tests/test_instance_types.py
+++ b/nova/tests/test_instance_types.py
@@ -85,7 +85,7 @@ class InstanceTypeTestCase(test.TestCase):
'instance type was not created')
instance_types.destroy(name)
- self.assertRaises(exception.ApiError,
+ self.assertRaises(exception.InstanceTypeNotFound,
instance_types.get_instance_type, inst_type_id)
# deleted instance should not be in list anymoer
@@ -133,7 +133,7 @@ class InstanceTypeTestCase(test.TestCase):
'unknown_flavor')
def test_duplicate_names_fail(self):
- """Ensures that name duplicates raise ApiError"""
+ """Ensures that name duplicates raise InstanceTypeCreateFailed"""
name = 'some_name'
instance_types.create(name, 256, 1, 120, 200, 'flavor1')
self.assertRaises(exception.InstanceTypeExists,
@@ -141,7 +141,7 @@ class InstanceTypeTestCase(test.TestCase):
name, 256, 1, 120, 200, 'flavor2')
def test_duplicate_flavorids_fail(self):
- """Ensures that flavorid duplicates raise ApiError"""
+ """Ensures that flavorid duplicates raise InstanceTypeCreateFailed"""
flavorid = 'flavor1'
instance_types.create('name one', 256, 1, 120, 200, flavorid)
self.assertRaises(exception.InstanceTypeExists,
@@ -156,7 +156,7 @@ class InstanceTypeTestCase(test.TestCase):
def test_will_not_get_bad_default_instance_type(self):
"""ensures error raised on bad default instance type"""
self.flags(default_instance_type='unknown_flavor')
- self.assertRaises(exception.ApiError,
+ self.assertRaises(exception.InstanceTypeNotFound,
instance_types.get_default_instance_type)
def test_will_get_instance_type_by_id(self):
@@ -167,12 +167,12 @@ class InstanceTypeTestCase(test.TestCase):
def test_will_not_get_instance_type_by_unknown_id(self):
"""Ensure get by name returns default flavor with no name"""
- self.assertRaises(exception.ApiError,
+ self.assertRaises(exception.InstanceTypeNotFound,
instance_types.get_instance_type, 10000)
def test_will_not_get_instance_type_with_bad_id(self):
"""Ensure get by name returns default flavor with bad name"""
- self.assertRaises(exception.ApiError,
+ self.assertRaises(exception.InstanceTypeNotFound,
instance_types.get_instance_type, 'asdf')
def test_instance_type_get_by_None_name_returns_default(self):
@@ -183,7 +183,7 @@ class InstanceTypeTestCase(test.TestCase):
def test_will_not_get_instance_type_with_bad_name(self):
"""Ensure get by name returns default flavor with bad name"""
- self.assertRaises(exception.ApiError,
+ self.assertRaises(exception.InstanceTypeNotFound,
instance_types.get_instance_type_by_name, 10000)
def test_will_not_get_instance_by_unknown_flavor_id(self):
diff --git a/nova/tests/test_volume.py b/nova/tests/test_volume.py
index 3f3893e39..7d7ed614c 100644
--- a/nova/tests/test_volume.py
+++ b/nova/tests/test_volume.py
@@ -249,7 +249,7 @@ class VolumeTestCase(test.TestCase):
volume_api = nova.volume.api.API()
volume = volume_api.get(self.context, volume['id'])
- self.assertRaises(exception.ApiError,
+ self.assertRaises(exception.InvalidVolume,
volume_api.create_snapshot,
self.context, volume,
'fake_name', 'fake_description')
diff --git a/nova/tests/test_volume_types.py b/nova/tests/test_volume_types.py
index 7702d0ecc..b0663d1b6 100644
--- a/nova/tests/test_volume_types.py
+++ b/nova/tests/test_volume_types.py
@@ -85,7 +85,7 @@ class VolumeTypeTestCase(test.TestCase):
def test_non_existant_vol_type_shouldnt_delete(self):
"""Ensures that volume type creation fails with invalid args"""
- self.assertRaises(exception.ApiError,
+ self.assertRaises(exception.VolumeTypeNotFoundByName,
volume_types.destroy, self.ctxt, "sfsfsdfdfs")
def test_repeated_vol_types_shouldnt_raise(self):
diff --git a/nova/tests/test_vsa.py b/nova/tests/test_vsa.py
index 21084d378..0089d8a2f 100644
--- a/nova/tests/test_vsa.py
+++ b/nova/tests/test_vsa.py
@@ -90,7 +90,7 @@ class VsaTestCase(test.TestCase):
def test_vsa_create_wrong_image_name(self):
param = {'image_name': 'wrong_image_name'}
- self.assertRaises(exception.ApiError,
+ self.assertRaises(exception.ImageNotFound,
self.vsa_api.create, self.context, **param)
def test_vsa_create_db_error(self):
@@ -100,19 +100,19 @@ class VsaTestCase(test.TestCase):
raise exception.Error
self.stubs.Set(nova.db, 'vsa_create', fake_vsa_create)
- self.assertRaises(exception.ApiError,
+ self.assertRaises(exception.Error,
self.vsa_api.create, self.context)
def test_vsa_create_wrong_storage_params(self):
vsa_list1 = self.vsa_api.get_all(self.context)
param = {'storage': [{'stub': 1}]}
- self.assertRaises(exception.ApiError,
+ self.assertRaises(exception.InvalidVolumeType,
self.vsa_api.create, self.context, **param)
vsa_list2 = self.vsa_api.get_all(self.context)
self.assertEqual(len(vsa_list2), len(vsa_list1))
param = {'storage': [{'drive_name': 'wrong name'}]}
- self.assertRaises(exception.ApiError,
+ self.assertRaises(exception.InvalidVolumeType,
self.vsa_api.create, self.context, **param)
def test_vsa_create_with_storage(self, multi_vol_creation=True):
diff --git a/nova/tests/test_vsa_volumes.py b/nova/tests/test_vsa_volumes.py
index a4bab624a..bd0ce2921 100644
--- a/nova/tests/test_vsa_volumes.py
+++ b/nova/tests/test_vsa_volumes.py
@@ -107,14 +107,14 @@ class VsaVolumesTestCase(test.TestCase):
'deleting')
def test_vsa_volume_delete_nonavail_volume(self):
- """ Check volume deleton in different states. """
+ """ Check volume deletion in different states. """
volume_param = self._default_volume_param()
volume_ref = self.volume_api.create(self.context, **volume_param)
self.volume_api.update(self.context,
volume_ref,
{'status': 'in-use'})
- self.assertRaises(exception.ApiError,
+ self.assertRaises(exception.InvalidVolume,
self.volume_api.delete,
self.context, volume_ref)
diff --git a/nova/virt/baremetal/proxy.py b/nova/virt/baremetal/proxy.py
index 306875964..64df617bb 100644
--- a/nova/virt/baremetal/proxy.py
+++ b/nova/virt/baremetal/proxy.py
@@ -551,8 +551,8 @@ class ProxyConnection(driver.ComputeDriver):
raise NotImplementedError()
def get_diagnostics(self, instance_name):
- raise exception.ApiError(_("diagnostics are not supported "
- "for baremetal"))
+ # diagnostics are not supported for baremetal
+ raise NotImplementedError()
def get_disks(self, instance_name):
raise NotImplementedError()
diff --git a/nova/virt/vmwareapi/vmops.py b/nova/virt/vmwareapi/vmops.py
index f04411e19..2810b3b71 100644
--- a/nova/virt/vmwareapi/vmops.py
+++ b/nova/virt/vmwareapi/vmops.py
@@ -610,12 +610,12 @@ class VMWareVMOps(object):
LOG.exception(exc)
def pause(self, instance):
- """Pause a VM instance."""
- raise exception.ApiError("pause not supported for vmwareapi")
+ msg = _("pause not supported for vmwareapi")
+ raise NotImplementedError(msg)
def unpause(self, instance):
- """Un-Pause a VM instance."""
- raise exception.ApiError("unpause not supported for vmwareapi")
+ msg = _("unpause not supported for vmwareapi")
+ raise NotImplementedError(msg)
def suspend(self, instance):
"""Suspend the specified instance."""
@@ -694,8 +694,8 @@ class VMWareVMOps(object):
def get_diagnostics(self, instance):
"""Return data about VM diagnostics."""
- raise exception.ApiError("get_diagnostics not implemented for "
- "vmwareapi")
+ msg = _("get_diagnostics not implemented for vmwareapi")
+ raise NotImplementedError(msg)
def get_console_output(self, instance):
"""Return snapshot of console."""
diff --git a/nova/volume/api.py b/nova/volume/api.py
index b5198137f..8646f65e9 100644
--- a/nova/volume/api.py
+++ b/nova/volume/api.py
@@ -71,8 +71,8 @@ class API(base.Base):
check_policy(context, 'create')
if snapshot is not None:
if snapshot['status'] != "available":
- raise exception.ApiError(
- _("Snapshot status must be available"))
+ msg = _("status must be available")
+ raise exception.InvalidSnapshot(reason=msg)
if not size:
size = snapshot['volume_size']
@@ -84,8 +84,7 @@ class API(base.Base):
pid = context.project_id
LOG.warn(_("Quota exceeded for %(pid)s, tried to create"
" %(size)sG volume") % locals())
- raise exception.QuotaError(_("Volume quota exceeded. You cannot "
- "create a volume of size %sG") % size)
+ raise exception.QuotaError(code="VolumeSizeTooLarge")
if availability_zone is None:
availability_zone = FLAGS.storage_availability_zone
@@ -131,7 +130,8 @@ class API(base.Base):
def delete(self, context, volume):
volume_id = volume['id']
if volume['status'] != "available":
- raise exception.ApiError(_("Volume status must be available"))
+ msg = _("Volume status must be available")
+ raise exception.InvalidVolume(reason=msg)
now = utils.utcnow()
self.db.volume_update(context, volume_id, {'status': 'deleting',
'terminated_at': now})
@@ -207,15 +207,18 @@ class API(base.Base):
def check_attach(self, context, volume):
# TODO(vish): abstract status checking?
if volume['status'] != "available":
- raise exception.ApiError(_("Volume status must be available"))
+ msg = _("status must be available")
+ raise exception.InvalidVolume(reason=msg)
if volume['attach_status'] == "attached":
- raise exception.ApiError(_("Volume is already attached"))
+ msg = _("already attached")
+ raise exception.InvalidVolume(reason=msg)
@wrap_check_policy
def check_detach(self, context, volume):
# TODO(vish): abstract status checking?
if volume['status'] == "available":
- raise exception.ApiError(_("Volume is already detached"))
+ msg = _("already detached")
+ raise exception.InvalidVolume(reason=msg)
def remove_from_compute(self, context, volume, instance_id, host):
"""Remove volume from specified compute host."""
@@ -266,7 +269,8 @@ class API(base.Base):
check_policy(context, 'create_snapshot', volume)
if ((not force) and (volume['status'] != "available")):
- raise exception.ApiError(_("Volume status must be available"))
+ msg = _("must be available")
+ raise exception.InvalidVolume(reason=msg)
options = {
'volume_id': volume['id'],
@@ -298,7 +302,8 @@ class API(base.Base):
@wrap_check_policy
def delete_snapshot(self, context, snapshot):
if snapshot['status'] != "available":
- raise exception.ApiError(_("Snapshot status must be available"))
+ msg = _("must be available")
+ raise exception.InvalidVolume(reason=msg)
self.db.snapshot_update(context, snapshot['id'],
{'status': 'deleting'})
rpc.cast(context,
diff --git a/nova/volume/san.py b/nova/volume/san.py
index 84dcef708..b76f224d5 100644
--- a/nova/volume/san.py
+++ b/nova/volume/san.py
@@ -702,9 +702,7 @@ class SolidFireSanISCSIDriver(SanISCSIDriver):
if response.status != 200:
connection.close()
- msg = _("Error in SolidFire API response, status was: %s"
- % response.status)
- raise exception.ApiError(msg)
+ raise exception.SolidFireAPIException(status=response.status)
else:
data = response.read()
@@ -763,9 +761,7 @@ class SolidFireSanISCSIDriver(SanISCSIDriver):
params = {}
data = self._issue_api_request('GetClusterInfo', params)
if 'result' not in data:
- msg = _("Error in SolidFire API response data was: %s"
- % data)
- raise exception.ApiError(msg)
+ raise exception.SolidFireAPIDataException(data=data)
return data['result']
@@ -827,14 +823,10 @@ class SolidFireSanISCSIDriver(SanISCSIDriver):
'attributes': attributes}
data = self._issue_api_request('CreateVolume', params)
- if 'result' not in data:
- msg = _("Error in SolidFire API response data was: %s"
- % data)
- raise exception.ApiError(msg)
- if 'volumeID' not in data['result']:
- msg = _("Error in SolidFire API response data was: %s"
- % data)
- raise exception.ApiError(msg)
+
+ if 'result' not in data or 'volumeID' not in data['result']:
+ raise exception.SolidFireAPIDataException(data=data)
+
volume_id = data['result']['volumeID']
volume_list = self._get_volumes_by_sfaccount(account_id)
@@ -873,9 +865,7 @@ class SolidFireSanISCSIDriver(SanISCSIDriver):
params = {'accountID': sfaccount['accountID']}
data = self._issue_api_request('ListVolumesForAccount', params)
if 'result' not in data:
- msg = _("Error in SolidFire API response, data was: %s"
- % data)
- raise exception.ApiError(msg)
+ raise exception.SolidFireAPIDataException(data=data)
found_count = 0
volid = -1
@@ -891,9 +881,7 @@ class SolidFireSanISCSIDriver(SanISCSIDriver):
params = {'volumeID': volid}
data = self._issue_api_request('DeleteVolume', params)
if 'result' not in data:
- msg = _("Error in SolidFire API response, data was: %s"
- % data)
- raise exception.ApiError(msg)
+ raise exception.SolidFireAPIDataException(data=data)
LOG.debug(_("Leaving SolidFire delete_volume"))
diff --git a/nova/volume/volume_types.py b/nova/volume/volume_types.py
index 9f33f7854..1e1ce2191 100644
--- a/nova/volume/volume_types.py
+++ b/nova/volume/volume_types.py
@@ -39,21 +39,17 @@ def create(context, name, extra_specs={}):
extra_specs=extra_specs))
except exception.DBError, e:
LOG.exception(_('DB error: %s') % e)
- raise exception.ApiError(_("Cannot create volume_type with "
- "name %(name)s and specs %(extra_specs)s")
- % locals())
+ raise exception.VolumeTypeCreateFailed(name=name,
+ extra_specs=extra_specs)
def destroy(context, name):
"""Marks volume types as deleted."""
if name is None:
- raise exception.InvalidVolumeType(volume_type=name)
+ msg = _("name cannot be None")
+ raise exception.InvalidVolumeType(reason=msg)
else:
- try:
- db.volume_type_destroy(context, name)
- except exception.NotFound:
- LOG.exception(_('Volume type %s not found for deletion') % name)
- raise exception.ApiError(_("Unknown volume type: %s") % name)
+ db.volume_type_destroy(context, name)
def get_all_types(context, inactive=0, search_opts={}):
@@ -97,26 +93,22 @@ def get_all_types(context, inactive=0, search_opts={}):
def get_volume_type(ctxt, id):
"""Retrieves single volume type by id."""
if id is None:
- raise exception.InvalidVolumeType(volume_type=id)
+ msg = _("id cannot be None")
+ raise exception.InvalidVolumeType(reason=msg)
if ctxt is None:
ctxt = context.get_admin_context()
- try:
- return db.volume_type_get(ctxt, id)
- except exception.DBError:
- raise exception.ApiError(_("Unknown volume type: %s") % id)
+ return db.volume_type_get(ctxt, id)
def get_volume_type_by_name(context, name):
"""Retrieves single volume type by name."""
if name is None:
- raise exception.InvalidVolumeType(volume_type=name)
+ msg = _("name cannot be None")
+ raise exception.InvalidVolumeType(reason=msg)
- try:
- return db.volume_type_get_by_name(context, name)
- except exception.DBError:
- raise exception.ApiError(_("Unknown volume type: %s") % name)
+ return db.volume_type_get_by_name(context, name)
def is_key_value_present(volume_type_id, key, value, volume_type=None):
diff --git a/nova/vsa/api.py b/nova/vsa/api.py
index 63e8e6bee..6482a11c1 100644
--- a/nova/vsa/api.py
+++ b/nova/vsa/api.py
@@ -23,8 +23,6 @@ For assistance and guidelines pls contact
Zadara Storage Inc & Openstack community
"""
-import sys
-
from nova import compute
from nova import exception
from nova import flags
@@ -81,8 +79,8 @@ class API(base.Base):
vol_type['extra_specs'].get('drive_type') is None or
vol_type['extra_specs'].get('drive_size') is None):
- raise exception.ApiError(_("Invalid drive type %s")
- % vol_type['name'])
+ msg = _("invalid drive data")
+ raise exception.InvalidVolumeType(reason=msg)
def _get_default_vsa_instance_type(self):
return instance_types.get_instance_type_by_name(
@@ -104,13 +102,14 @@ class API(base.Base):
num_disks = node.get('num_drives', 1)
if name is None:
- raise exception.ApiError(_("No drive_name param found in %s")
- % node)
+ msg = _("drive_name not defined")
+ raise exception.InvalidVolumeType(reason=msg)
+
try:
vol_type = volume_types.get_volume_type_by_name(context, name)
except exception.NotFound:
- raise exception.ApiError(_("Invalid drive type name %s")
- % name)
+ msg = _("invalid drive type name %s")
+ raise exception.InvalidVolumeType(reason=msg % name)
self._check_volume_type_correctness(vol_type)
@@ -177,13 +176,10 @@ class API(base.Base):
# check if image is ready before starting any work
if image_name is None:
image_name = FLAGS.vc_image_name
- try:
- image_service = self.compute_api.image_service
- vc_image = image_service.show_by_name(context, image_name)
- vc_image_href = vc_image['id']
- except exception.ImageNotFound:
- raise exception.ApiError(_("Failed to find configured image %s")
- % image_name)
+
+ image_service = self.compute_api.image_service
+ vc_image = image_service.show_by_name(context, image_name)
+ vc_image_href = vc_image['id']
options = {
'display_name': display_name,
@@ -198,10 +194,8 @@ class API(base.Base):
LOG.info(_("Creating VSA: %s") % options)
# create DB entry for VSA instance
- try:
- vsa_ref = self.db.vsa_create(context, options)
- except exception.Error:
- raise exception.ApiError(_(sys.exc_info()[1]))
+ vsa_ref = self.db.vsa_create(context, options)
+
vsa_id = vsa_ref['id']
vsa_name = vsa_ref['name']
@@ -209,10 +203,9 @@ class API(base.Base):
try:
volume_params = self._check_storage_parameters(context, vsa_name,
storage, shared)
- except exception.ApiError:
+ except exception.InvalidVolumeType:
self.db.vsa_destroy(context, vsa_id)
- raise exception.ApiError(_("Error in storage parameters: %s")
- % storage)
+ raise
# after creating DB entry, re-check and set some defaults
updates = {}
@@ -358,7 +351,7 @@ class API(base.Base):
LOG.info(_("VSA ID %(vsa_id)s: Deleting %(direction)s "
"volume %(vol_name)s"), locals())
self.volume_api.delete(context, volume)
- except exception.ApiError:
+ except exception.InvalidVolume:
LOG.info(_("Unable to delete volume %s"), volume['name'])
if force_delete:
LOG.info(_("VSA ID %(vsa_id)s: Forced delete. "