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
This commit is contained in:
Brian Waldon
2012-02-03 13:29:57 -08:00
parent c9ca372b0b
commit afd5b22368
35 changed files with 237 additions and 229 deletions

View File

@@ -1607,7 +1607,7 @@ class VsaDriveTypeCommands(object):
"""Marks volume types as deleted""" """Marks volume types as deleted"""
try: try:
volume_types.destroy(self.context, name) volume_types.destroy(self.context, name)
except exception.ApiError: except exception.InvalidVolumeType:
print "Valid volume type name is required" print "Valid volume type name is required"
sys.exit(1) sys.exit(1)
except exception.DBError, e: except exception.DBError, e:
@@ -1786,7 +1786,7 @@ class InstanceTypeCommands(object):
"""Marks instance types / flavors as deleted""" """Marks instance types / flavors as deleted"""
try: try:
instance_types.destroy(name) instance_types.destroy(name)
except exception.ApiError: except exception.InstanceTypeNotFound:
print "Valid instance type name is required" print "Valid instance type name is required"
sys.exit(1) sys.exit(1)
except exception.DBError, e: except exception.DBError, e:

View File

@@ -598,8 +598,8 @@ class Executor(wsgi.Application):
except exception.NotFound as ex: except exception.NotFound as ex:
LOG.info(_('NotFound raised: %s'), unicode(ex), context=context) LOG.info(_('NotFound raised: %s'), unicode(ex), context=context)
return ec2_error(req, request_id, type(ex).__name__, unicode(ex)) return ec2_error(req, request_id, type(ex).__name__, unicode(ex))
except exception.ApiError as ex: except exception.EC2APIError as ex:
LOG.exception(_('ApiError raised: %s'), unicode(ex), LOG.exception(_('EC2APIError raised: %s'), unicode(ex),
context=context) context=context)
if ex.code: if ex.code:
return ec2_error(req, request_id, ex.code, unicode(ex)) return ec2_error(req, request_id, ex.code, unicode(ex))

View File

@@ -600,7 +600,7 @@ class CloudController(object):
group_id=None, **kwargs): group_id=None, **kwargs):
if not group_name and not group_id: if not group_name and not group_id:
err = "Not enough parameters, need group_name or 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) self.compute_api.ensure_default_security_group(context)
notfound = exception.SecurityGroupNotFound notfound = exception.SecurityGroupNotFound
if group_name: if group_name:
@@ -626,7 +626,7 @@ class CloudController(object):
rulesvalues = self._rule_args_to_dict(context, values) rulesvalues = self._rule_args_to_dict(context, values)
if not rulesvalues: if not rulesvalues:
err = "%s Not enough parameters to build a valid rule" 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: for values_for_rule in rulesvalues:
values_for_rule['parent_group_id'] = security_group.id values_for_rule['parent_group_id'] = security_group.id
@@ -640,7 +640,7 @@ class CloudController(object):
context, context,
security_group_id=security_group['id']) security_group_id=security_group['id'])
return True 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. # TODO(soren): This has only been tested with Boto as the client.
# Unfortunately, it seems Boto is using an old API # Unfortunately, it seems Boto is using an old API
@@ -650,7 +650,7 @@ class CloudController(object):
group_id=None, **kwargs): group_id=None, **kwargs):
if not group_name and not group_id: if not group_name and not group_id:
err = "Not enough parameters, need group_name or 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) self.compute_api.ensure_default_security_group(context)
notfound = exception.SecurityGroupNotFound notfound = exception.SecurityGroupNotFound
if group_name: if group_name:
@@ -676,13 +676,13 @@ class CloudController(object):
rulesvalues = self._rule_args_to_dict(context, values) rulesvalues = self._rule_args_to_dict(context, values)
if not rulesvalues: if not rulesvalues:
err = "%s Not enough parameters to build a valid rule" 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: for values_for_rule in rulesvalues:
values_for_rule['parent_group_id'] = security_group.id values_for_rule['parent_group_id'] = security_group.id
if self._security_group_rule_exists(security_group, if self._security_group_rule_exists(security_group,
values_for_rule): values_for_rule):
err = '%s - This rule already exists in group' 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) postvalues.append(values_for_rule)
for values_for_rule in postvalues: for values_for_rule in postvalues:
@@ -696,7 +696,7 @@ class CloudController(object):
security_group_id=security_group['id']) security_group_id=security_group['id'])
return True 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): def _get_source_project_id(self, context, source_security_group_owner_id):
if 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) LOG.audit(_("Create Security Group %s"), group_name, context=context)
self.compute_api.ensure_default_security_group(context) self.compute_api.ensure_default_security_group(context)
if db.security_group_exists(context, context.project_id, group_name): 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, group = {'user_id': context.user_id,
'project_id': context.project_id, 'project_id': context.project_id,
@@ -750,7 +751,7 @@ class CloudController(object):
**kwargs): **kwargs):
if not group_name and not group_id: if not group_name and not group_id:
err = "Not enough parameters, need group_name or group_id" err = "Not enough parameters, need group_name or group_id"
raise exception.ApiError(_(err)) raise exception.EC2APIError(_(err))
notfound = exception.SecurityGroupNotFound notfound = exception.SecurityGroupNotFound
if group_name: if group_name:
security_group = db.security_group_get_by_name(context, 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, def describe_instance_attribute(self, context, instance_id, attribute,
**kwargs): **kwargs):
def _unsupported_attribute(instance, result): def _unsupported_attribute(instance, result):
raise exception.ApiError(_('attribute not supported: %s') % raise exception.EC2APIError(_('attribute not supported: %s') %
attribute) attribute)
def _format_attr_block_device_mapping(instance, result): def _format_attr_block_device_mapping(instance, result):
@@ -962,7 +963,7 @@ class CloudController(object):
fn = attribute_formatter.get(attribute) fn = attribute_formatter.get(attribute)
if fn is None: if fn is None:
raise exception.ApiError( raise exception.EC2APIError(
_('attribute not supported: %s') % attribute) _('attribute not supported: %s') % attribute)
ec2_instance_id = instance_id ec2_instance_id = instance_id
@@ -1225,7 +1226,7 @@ class CloudController(object):
raise exception.ImageNotFound(image_id=kwargs['image_id']) raise exception.ImageNotFound(image_id=kwargs['image_id'])
if image_state != 'available': 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, (instances, resv_id) = self.compute_api.create(context,
instance_type=instance_types.get_instance_type_by_name( instance_type=instance_types.get_instance_type_by_name(
@@ -1425,7 +1426,7 @@ class CloudController(object):
fn = supported_attributes.get(attribute) fn = supported_attributes.get(attribute)
if fn is None: if fn is None:
raise exception.ApiError(_('attribute not supported: %s') raise exception.EC2APIError(_('attribute not supported: %s')
% attribute) % attribute)
try: try:
image = self._get_image(context, image_id) image = self._get_image(context, image_id)
@@ -1440,14 +1441,15 @@ class CloudController(object):
operation_type, **kwargs): operation_type, **kwargs):
# TODO(devcamcar): Support users and groups other than 'all'. # TODO(devcamcar): Support users and groups other than 'all'.
if attribute != 'launchPermission': if attribute != 'launchPermission':
raise exception.ApiError(_('attribute not supported: %s') raise exception.EC2APIError(_('attribute not supported: %s')
% attribute) % attribute)
if not 'user_group' in kwargs: 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': 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']: 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) LOG.audit(_("Updating image %s publicity"), image_id, context=context)
try: try:
@@ -1504,7 +1506,7 @@ class CloudController(object):
# Or is there any better way? # Or is there any better way?
timeout = 1 * 60 * 60 * 60 timeout = 1 * 60 * 60 * 60
if time.time() > start_time + timeout: if time.time() > start_time + timeout:
raise exception.ApiError( raise exception.EC2APIError(
_('Couldn\'t stop instance with in %d sec') % timeout) _('Couldn\'t stop instance with in %d sec') % timeout)
src_image = self._get_image(context, instance['image_ref']) src_image = self._get_image(context, instance['image_ref'])

View File

@@ -116,7 +116,7 @@ class CloudpipeController(object):
except db.NoMoreNetworks: except db.NoMoreNetworks:
msg = _("Unable to claim IP for VPN instances, ensure it " msg = _("Unable to claim IP for VPN instances, ensure it "
"isn't running, and try again in a few minutes") "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) instance = self._get_cloudpipe_for_project(ctxt, proj)
return {'instance_id': instance['uuid']} return {'instance_id': instance['uuid']}

View File

@@ -54,8 +54,8 @@ class ConsoleOutputController(wsgi.Controller):
output = self.compute_api.get_console_output(context, output = self.compute_api.get_console_output(context,
instance, instance,
length) length)
except exception.ApiError, e: except exception.NotFound:
raise webob.exc.HTTPBadRequest(explanation=e.message) raise webob.exc.HTTPNotFound(_('Instance not found'))
return {'output': output} return {'output': output}

View File

@@ -54,10 +54,10 @@ class ConsolesController(wsgi.Controller):
console_type) console_type)
except exception.ConsoleTypeInvalid, e: except exception.ConsoleTypeInvalid, e:
raise webob.exc.HTTPBadRequest(_('Invalid type specification')) raise webob.exc.HTTPBadRequest(_('Invalid type specification'))
except exception.ApiError, e:
raise webob.exc.HTTPBadRequest(explanation=e.message)
except exception.NotAuthorized, e: except exception.NotAuthorized, e:
raise webob.exc.HTTPUnauthorized() raise webob.exc.HTTPUnauthorized()
except exception.NotFound:
raise webob.exc.HTTPNotFound(_('Instance not found'))
return {'console': {'type': console_type, 'url': output['url']}} return {'console': {'type': console_type, 'url': output['url']}}

View File

@@ -204,14 +204,14 @@ class FloatingIPActionController(wsgi.Controller):
msg = _("Address not specified") msg = _("Address not specified")
raise webob.exc.HTTPBadRequest(explanation=msg) raise webob.exc.HTTPBadRequest(explanation=msg)
instance = self.compute_api.get(context, id)
try: try:
instance = self.compute_api.get(context, id)
self.compute_api.associate_floating_ip(context, instance, self.compute_api.associate_floating_ip(context, instance,
address) address)
except exception.ApiError, e: except exception.FixedIpNotFoundForInstance:
raise webob.exc.HTTPBadRequest(explanation=e.message) msg = _("No fixed ips associated to instance")
except exception.NotAuthorized, e: raise webob.exc.HTTPBadRequest(explanation=msg)
raise webob.exc.HTTPUnauthorized()
except rpc.RemoteError: except rpc.RemoteError:
msg = _("Associate floating ip failed") msg = _("Associate floating ip failed")
raise webob.exc.HTTPInternalServerError(explanation=msg) raise webob.exc.HTTPInternalServerError(explanation=msg)

View File

@@ -31,35 +31,29 @@ class ServerStartStopActionController(wsgi.Controller):
super(ServerStartStopActionController, self).__init__(*args, **kwargs) super(ServerStartStopActionController, self).__init__(*args, **kwargs)
self.compute_api = compute.API() 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') @wsgi.action('os-start')
def _start_server(self, req, id, body): def _start_server(self, req, id, body):
"""Start an instance. """ """Start an instance. """
context = req.environ['nova.context'] context = req.environ['nova.context']
LOG.debug(_("start instance %r"), id)
try: instance = self._get_instance(context, id)
LOG.debug(_("start instance %r"), id) self.compute_api.start(context, instance)
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()
return webob.Response(status_int=202) return webob.Response(status_int=202)
@wsgi.action('os-stop') @wsgi.action('os-stop')
def _stop_server(self, req, id, body): def _stop_server(self, req, id, body):
"""Stop an instance.""" """Stop an instance."""
context = req.environ['nova.context'] context = req.environ['nova.context']
LOG.debug(_("stop instance %r"), id)
try: instance = self._get_instance(context, id)
LOG.debug(_("stop instance %r"), id) self.compute_api.stop(context, instance)
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()
return webob.Response(status_int=202) return webob.Response(status_int=202)

View File

@@ -100,7 +100,7 @@ class VolumeTypesController(object):
try: try:
vol_type = volume_types.get_volume_type(context, id) vol_type = volume_types.get_volume_type(context, id)
except exception.NotFound or exception.ApiError: except exception.NotFound:
raise exc.HTTPNotFound() raise exc.HTTPNotFound()
return {'volume_type': vol_type} return {'volume_type': vol_type}

View File

@@ -165,7 +165,7 @@ class Controller(object):
def _handle_quota_error(self, error): def _handle_quota_error(self, error):
"""Reraise quota errors as api-specific http exceptions.""" """Reraise quota errors as api-specific http exceptions."""
if error.code == "MetadataLimitExceeded": if error.kwargs['code'] == "MetadataLimitExceeded":
raise exc.HTTPRequestEntityTooLarge(explanation=error.message, raise exc.HTTPRequestEntityTooLarge(explanation=error.message,
headers={'Retry-After': 0}) headers={'Retry-After': 0})
raise error raise error

View File

@@ -496,12 +496,8 @@ class Controller(wsgi.Controller):
"InstanceLimitExceeded": error.message, "InstanceLimitExceeded": error.message,
} }
expl = code_mappings.get(error.code) expl = code_mappings.get(error.kwargs['code'], error.message)
if expl: raise exc.HTTPRequestEntityTooLarge(explanation=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,
headers={'Retry-After': 0}) headers={'Retry-After': 0})
def _validate_server_name(self, value): def _validate_server_name(self, value):

View File

@@ -64,7 +64,7 @@ class VolumeTypesController(object):
try: try:
vol_type = volume_types.get_volume_type(context, id) vol_type = volume_types.get_volume_type(context, id)
except exception.NotFound or exception.ApiError: except exception.NotFound:
raise exc.HTTPNotFound() raise exc.HTTPNotFound()
return {'volume_type': vol_type} return {'volume_type': vol_type}

View File

@@ -136,8 +136,8 @@ class API(base.Base):
content_limit = quota.allowed_injected_file_content_bytes( content_limit = quota.allowed_injected_file_content_bytes(
context, len(content)) context, len(content))
if len(content) > content_limit: 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): def _check_metadata_properties_quota(self, context, metadata=None):
"""Enforce quota limits on metadata properties.""" """Enforce quota limits on metadata properties."""
@@ -150,7 +150,7 @@ class API(base.Base):
msg = _("Quota exceeded for %(pid)s, tried to set " msg = _("Quota exceeded for %(pid)s, tried to set "
"%(num_metadata)s metadata properties") % locals() "%(num_metadata)s metadata properties") % locals()
LOG.warn(msg) 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 # 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 # 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 " msg = _("Quota exceeded for %(pid)s, metadata property "
"key or value too long") % locals() "key or value too long") % locals()
LOG.warn(msg) LOG.warn(msg)
raise exception.QuotaError(msg, "MetadataLimitExceeded") raise exception.QuotaError(code="MetadataLimitExceeded")
def _check_requested_networks(self, context, requested_networks): def _check_requested_networks(self, context, requested_networks):
""" Check if the networks requested belongs to the project """ Check if the networks requested belongs to the project
@@ -218,7 +218,7 @@ class API(base.Base):
else: else:
message = _("Instance quota exceeded. You can only run %s " message = _("Instance quota exceeded. You can only run %s "
"more instances of this type.") % num_instances "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_metadata_properties_quota(context, metadata)
self._check_injected_file_quota(context, injected_files) 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): def attach_volume(self, context, instance, volume_id, device):
"""Attach an existing volume to an existing instance.""" """Attach an existing volume to an existing instance."""
if not re.match("^/dev/x{0,1}[a-z]d[a-z]+$", device): if not re.match("^/dev/x{0,1}[a-z]d[a-z]+$", device):
raise exception.ApiError(_("Invalid device specified: %s. " raise exception.InvalidDevicePath(path=device)
"Example device: /dev/vdb") % device)
volume = self.volume_api.get(context, volume_id) volume = self.volume_api.get(context, volume_id)
self.volume_api.check_attach(context, volume) self.volume_api.check_attach(context, volume)
params = {"volume_id": volume_id, params = {"volume_id": volume_id,
@@ -1647,7 +1646,7 @@ class API(base.Base):
"""Detach a volume from an instance.""" """Detach a volume from an instance."""
instance = self.db.volume_get_instance(context.elevated(), volume_id) instance = self.db.volume_get_instance(context.elevated(), volume_id)
if not instance: 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) 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 # in its info, if this changes, the next few lines will need to
# accommodate the info containing floating as well as fixed ip # accommodate the info containing floating as well as fixed ip
# addresses # 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(), nw_info = self.network_api.get_instance_nw_info(context.elevated(),
instance) instance)
if nw_info: if not nw_info:
ips = [ip for ip in nw_info[0].fixed_ips()] raise exception.FixedIpNotFoundForInstance(
instance_id=instance_uuid)
# TODO(tr3buchet): this will associate the floating IP with the ips = [ip for ip in nw_info[0].fixed_ips()]
# first # fixed_ip (lowest id) an instance has. This should be
# changed to # support specifying a particular fixed_ip if if not ips:
# multiple exist. raise exception.FixedIpNotFoundForInstance(
if not ips: instance_id=instance_uuid)
raise exception.ApiError(fail_bag)
if len(ips) > 1: # TODO(tr3buchet): this will associate the floating IP with the
LOG.warning(_('multiple fixedips exist, using the first: %s'), # first fixed_ip (lowest id) an instance has. This should be
ips[0]['address']) # changed to support specifying a particular fixed_ip if
self.network_api.associate_floating_ip(context, # multiple exist.
floating_address=address, if len(ips) > 1:
fixed_address=ips[0]['address']) msg = _('multiple fixedips exist, using the first: %s')
return LOG.warning(msg, ips[0]['address'])
raise exception.ApiError(fail_bag)
self.network_api.associate_floating_ip(context,
floating_address=address, fixed_address=ips[0]['address'])
@wrap_check_policy @wrap_check_policy
def get_instance_metadata(self, context, instance): def get_instance_metadata(self, context, instance):

View File

@@ -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) return db.instance_type_create(context.get_admin_context(), kwargs)
except exception.DBError, e: except exception.DBError, e:
LOG.exception(_('DB error: %s') % e) LOG.exception(_('DB error: %s') % e)
msg = _("Cannot create instance_type with name %(name)s and " raise exception.InstanceTypeCreateFailed()
"flavorid %(flavorid)s") % locals()
raise exception.ApiError(msg)
def destroy(name): def destroy(name):
@@ -106,10 +104,7 @@ get_all_flavors = get_all_types
def get_default_instance_type(): def get_default_instance_type():
"""Get the default instance type.""" """Get the default instance type."""
name = FLAGS.default_instance_type name = FLAGS.default_instance_type
try: return get_instance_type_by_name(name)
return get_instance_type_by_name(name)
except exception.InstanceTypeNotFound as e:
raise exception.ApiError(e)
def get_instance_type(instance_type_id): def get_instance_type(instance_type_id):
@@ -118,10 +113,7 @@ def get_instance_type(instance_type_id):
return get_default_instance_type() return get_default_instance_type()
ctxt = context.get_admin_context() ctxt = context.get_admin_context()
try: return db.instance_type_get(ctxt, instance_type_id)
return db.instance_type_get(ctxt, instance_type_id)
except exception.InstanceTypeNotFound as e:
raise exception.ApiError(e)
def get_instance_type_by_name(name): def get_instance_type_by_name(name):
@@ -130,11 +122,7 @@ def get_instance_type_by_name(name):
return get_default_instance_type() return get_default_instance_type()
ctxt = context.get_admin_context() ctxt = context.get_admin_context()
return db.instance_type_get_by_name(ctxt, name)
try:
return db.instance_type_get_by_name(ctxt, name)
except exception.InstanceTypeNotFound as e:
raise exception.ApiError(e)
# TODO(termie): flavor-specific code should probably be in the API that uses # TODO(termie): flavor-specific code should probably be in the API that uses

View File

@@ -80,7 +80,7 @@ class Error(Exception):
super(Error, self).__init__(message) super(Error, self).__init__(message)
class ApiError(Error): class EC2APIError(Error):
def __init__(self, message='Unknown', code=None): def __init__(self, message='Unknown', code=None):
self.msg = message self.msg = message
self.code = code self.code = code
@@ -88,7 +88,7 @@ class ApiError(Error):
outstr = '%s: %s' % (code, message) outstr = '%s: %s' % (code, message)
else: else:
outstr = '%s' % message outstr = '%s' % message
super(ApiError, self).__init__(outstr) super(EC2APIError, self).__init__(outstr)
class DBError(Error): class DBError(Error):
@@ -223,6 +223,14 @@ class Invalid(NovaException):
message = _("Unacceptable parameters.") 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): class InvalidKeypair(Invalid):
message = _("Keypair data is invalid") message = _("Keypair data is invalid")
@@ -248,7 +256,11 @@ class InvalidInstanceType(Invalid):
class InvalidVolumeType(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): class InvalidPortRange(Invalid):
@@ -930,9 +942,8 @@ class WillNotSchedule(NovaException):
message = _("Host %(host)s is not up or doesn't exist.") message = _("Host %(host)s is not up or doesn't exist.")
class QuotaError(ApiError): class QuotaError(NovaException):
"""Quota Exceeded.""" message = _("Quota exceeded") + ": code=%(code)s"
pass
class AggregateNotFound(NotFound): class AggregateNotFound(NotFound):
@@ -962,3 +973,24 @@ class AggregateHostExists(Duplicate):
class DuplicateSfVolumeNames(Duplicate): class DuplicateSfVolumeNames(Duplicate):
message = _("Detected more than one volume with name %(vol_name)") 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")

View File

@@ -368,11 +368,9 @@ class FloatingIP(object):
# NOTE(tr3buchet): all network hosts in zone now use the same pool # NOTE(tr3buchet): all network hosts in zone now use the same pool
LOG.debug("QUOTA: %s" % quota.allowed_floating_ips(context, 1)) LOG.debug("QUOTA: %s" % quota.allowed_floating_ips(context, 1))
if quota.allowed_floating_ips(context, 1) < 1: if quota.allowed_floating_ips(context, 1) < 1:
LOG.warn(_('Quota exceeded for %s, tried to allocate ' LOG.warn(_('Quota exceeded for %s, tried to allocate address'),
'address'),
context.project_id) context.project_id)
raise exception.QuotaError(_('Address quota exceeded. You cannot ' raise exception.QuotaError(code='AddressLimitExceeded')
'allocate any more addresses'))
pool = pool or FLAGS.default_floating_pool pool = pool or FLAGS.default_floating_pool
return self.db.floating_ip_allocate_address(context, return self.db.floating_ip_allocate_address(context,
project_id, project_id,

View File

@@ -285,7 +285,7 @@ class CloudTestCase(test.TestCase):
def test_delete_security_group_no_params(self): def test_delete_security_group_no_params(self):
delete = self.cloud.delete_security_group 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): def test_authorize_security_group_ingress(self):
kwargs = {'project_id': self.context.project_id, 'name': 'test'} kwargs = {'project_id': self.context.project_id, 'name': 'test'}
@@ -415,12 +415,12 @@ class CloudTestCase(test.TestCase):
{'project_id': self.context.project_id, {'project_id': self.context.project_id,
'name': 'test'}) 'name': 'test'})
authz = self.cloud.authorize_security_group_ingress 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): def test_authorize_security_group_ingress_missing_group_name_or_id(self):
kwargs = {'project_id': self.context.project_id, 'name': 'test'} kwargs = {'project_id': self.context.project_id, 'name': 'test'}
authz = self.cloud.authorize_security_group_ingress 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): def test_authorize_security_group_ingress_already_exists(self):
kwargs = {'project_id': self.context.project_id, 'name': 'test'} kwargs = {'project_id': self.context.project_id, 'name': 'test'}
@@ -428,13 +428,14 @@ class CloudTestCase(test.TestCase):
authz = self.cloud.authorize_security_group_ingress authz = self.cloud.authorize_security_group_ingress
kwargs = {'to_port': '999', 'from_port': '999', 'ip_protocol': 'tcp'} kwargs = {'to_port': '999', 'from_port': '999', 'ip_protocol': 'tcp'}
authz(self.context, group_name=sec['name'], **kwargs) 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) group_name=sec['name'], **kwargs)
def test_revoke_security_group_ingress_missing_group_name_or_id(self): def test_revoke_security_group_ingress_missing_group_name_or_id(self):
kwargs = {'to_port': '999', 'from_port': '999', 'ip_protocol': 'tcp'} kwargs = {'to_port': '999', 'from_port': '999', 'ip_protocol': 'tcp'}
revoke = self.cloud.revoke_security_group_ingress 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): def test_describe_volumes(self):
"""Makes sure describe_volumes works and filters results.""" """Makes sure describe_volumes works and filters results."""
@@ -1315,7 +1316,7 @@ class CloudTestCase(test.TestCase):
self.stubs.UnsetAll() self.stubs.UnsetAll()
self.stubs.Set(fake._FakeImageService, 'show', fake_show_no_state) 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) self.context, **kwargs)
def test_run_instances_image_state_invalid(self): def test_run_instances_image_state_invalid(self):
@@ -1334,7 +1335,7 @@ class CloudTestCase(test.TestCase):
self.stubs.UnsetAll() self.stubs.UnsetAll()
self.stubs.Set(fake._FakeImageService, 'show', fake_show_decrypt) self.stubs.Set(fake._FakeImageService, 'show', fake_show_decrypt)
self.assertRaises(exception.ApiError, run_instances, self.assertRaises(exception.EC2APIError, run_instances,
self.context, **kwargs) self.context, **kwargs)
def test_run_instances_image_status_active(self): def test_run_instances_image_status_active(self):

View File

@@ -40,7 +40,7 @@ def fake_get(self, context, instance_uuid):
return {'uuid': 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() raise exception.NotFound()
@@ -86,6 +86,17 @@ class ConsoleOutputExtensionTest(test.TestCase):
res = req.get_response(fakes.wsgi_app()) res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 404) 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): def test_get_text_console_bad_body(self):
body = {} body = {}
req = webob.Request.blank('/v2/fake/servers/1/action') req = webob.Request.blank('/v2/fake/servers/1/action')

View File

@@ -36,7 +36,7 @@ def fake_get(self, context, instance_uuid):
return {'uuid': 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() raise exception.NotFound()
@@ -83,6 +83,17 @@ class ConsolesExtensionTest(test.TestCase):
res = req.get_response(fakes.wsgi_app()) res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 404) 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): def test_get_vnc_console_invalid_type(self):
self.stubs.Set(compute.API, 'get', fake_get) self.stubs.Set(compute.API, 'get', fake_get)
body = {'os-getVNCConsole': {'type': 'invalid'}} body = {'os-getVNCConsole': {'type': 'invalid'}}

View File

@@ -13,11 +13,12 @@
# under the License. # under the License.
import unittest import unittest
import mox import mox
import webob
from nova.api.openstack.compute.contrib import server_start_stop from nova.api.openstack.compute.contrib import server_start_stop
from nova import context from nova import context
from nova import exception
from nova import compute from nova import compute
from nova import test from nova import test
from nova.tests.api.openstack import fakes from nova.tests.api.openstack import fakes
@@ -60,13 +61,13 @@ class ServerStartStopTest(test.TestCase):
def test_start_with_bogus_id(self): def test_start_with_bogus_id(self):
req = fakes.HTTPRequest.blank('/v2/fake/servers/test_inst/action') req = fakes.HTTPRequest.blank('/v2/fake/servers/test_inst/action')
body = dict(start="") body = dict(start="")
self.assertRaises(exception.InstanceNotFound, self.assertRaises(webob.exc.HTTPNotFound,
self.controller._start_server, req, 'test_inst', body) self.controller._start_server, req, 'test_inst', body)
def test_stop_with_bogus_id(self): def test_stop_with_bogus_id(self):
req = fakes.HTTPRequest.blank('/v2/fake/servers/test_inst/action') req = fakes.HTTPRequest.blank('/v2/fake/servers/test_inst/action')
body = dict(start="") body = dict(start="")
self.assertRaises(exception.InstanceNotFound, self.assertRaises(webob.exc.HTTPNotFound,
self.controller._stop_server, req, 'test_inst', body) self.controller._stop_server, req, 'test_inst', body)

View File

@@ -13,14 +13,12 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from nova import context
from nova import db from nova import db
from nova import exception from nova import exception
from nova import flags from nova import flags
from nova import log as logging from nova import log as logging
from nova import rpc from nova import rpc
from nova.scheduler import vsa as vsa_sched from nova.scheduler import vsa as vsa_sched
from nova import test
from nova.tests.scheduler import test_scheduler from nova.tests.scheduler import test_scheduler
from nova import utils from nova import utils
from nova.volume import volume_types from nova.volume import volume_types

View File

@@ -176,5 +176,5 @@ class SolidFireVolumeTestCase(test.TestCase):
def test_get_cluster_info_fail(self): def test_get_cluster_info_fail(self):
SFID._issue_api_request = self.fake_issue_api_request_fails SFID._issue_api_request = self.fake_issue_api_request_fails
sfv = SFID() sfv = SFID()
self.assertRaises(exception.ApiError, self.assertRaises(exception.SolidFireAPIException,
sfv._get_cluster_info) sfv._get_cluster_info)

View File

@@ -2357,7 +2357,7 @@ class ComputeAPITestCase(BaseTestCase):
address = '0.1.2.3' address = '0.1.2.3'
self.compute.run_instance(self.context, instance_uuid) self.compute.run_instance(self.context, instance_uuid)
self.assertRaises(exception.ApiError, self.assertRaises(exception.FixedIpNotFoundForInstance,
self.compute_api.associate_floating_ip, self.compute_api.associate_floating_ip,
self.context, self.context,
instance, instance,
@@ -2967,7 +2967,7 @@ class ComputeAPITestCase(BaseTestCase):
self.compute_api.delete(self.context, instance) self.compute_api.delete(self.context, instance)
def test_attach_volume_invalid(self): def test_attach_volume_invalid(self):
self.assertRaises(exception.ApiError, self.assertRaises(exception.InvalidDevicePath,
self.compute_api.attach_volume, self.compute_api.attach_volume,
self.context, self.context,
None, None,

View File

@@ -20,15 +20,15 @@ from nova import test
from nova import exception from nova import exception
class ApiErrorTestCase(test.TestCase): class EC2APIErrorTestCase(test.TestCase):
def test_return_valid_error(self): def test_return_valid_error(self):
# without 'code' arg # without 'code' arg
err = exception.ApiError('fake error') err = exception.EC2APIError('fake error')
self.assertEqual(err.__str__(), 'fake error') self.assertEqual(err.__str__(), 'fake error')
self.assertEqual(err.code, None) self.assertEqual(err.code, None)
self.assertEqual(err.msg, 'fake error') self.assertEqual(err.msg, 'fake error')
# with 'code' arg # 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.__str__(), 'blah code: fake error')
self.assertEqual(err.code, 'blah code') self.assertEqual(err.code, 'blah code')
self.assertEqual(err.msg, 'fake error') self.assertEqual(err.msg, 'fake error')

View File

@@ -85,7 +85,7 @@ class InstanceTypeTestCase(test.TestCase):
'instance type was not created') 'instance type was not created')
instance_types.destroy(name) instance_types.destroy(name)
self.assertRaises(exception.ApiError, self.assertRaises(exception.InstanceTypeNotFound,
instance_types.get_instance_type, inst_type_id) instance_types.get_instance_type, inst_type_id)
# deleted instance should not be in list anymoer # deleted instance should not be in list anymoer
@@ -133,7 +133,7 @@ class InstanceTypeTestCase(test.TestCase):
'unknown_flavor') 'unknown_flavor')
def test_duplicate_names_fail(self): def test_duplicate_names_fail(self):
"""Ensures that name duplicates raise ApiError""" """Ensures that name duplicates raise InstanceTypeCreateFailed"""
name = 'some_name' name = 'some_name'
instance_types.create(name, 256, 1, 120, 200, 'flavor1') instance_types.create(name, 256, 1, 120, 200, 'flavor1')
self.assertRaises(exception.InstanceTypeExists, self.assertRaises(exception.InstanceTypeExists,
@@ -141,7 +141,7 @@ class InstanceTypeTestCase(test.TestCase):
name, 256, 1, 120, 200, 'flavor2') name, 256, 1, 120, 200, 'flavor2')
def test_duplicate_flavorids_fail(self): def test_duplicate_flavorids_fail(self):
"""Ensures that flavorid duplicates raise ApiError""" """Ensures that flavorid duplicates raise InstanceTypeCreateFailed"""
flavorid = 'flavor1' flavorid = 'flavor1'
instance_types.create('name one', 256, 1, 120, 200, flavorid) instance_types.create('name one', 256, 1, 120, 200, flavorid)
self.assertRaises(exception.InstanceTypeExists, self.assertRaises(exception.InstanceTypeExists,
@@ -156,7 +156,7 @@ class InstanceTypeTestCase(test.TestCase):
def test_will_not_get_bad_default_instance_type(self): def test_will_not_get_bad_default_instance_type(self):
"""ensures error raised on bad default instance type""" """ensures error raised on bad default instance type"""
self.flags(default_instance_type='unknown_flavor') self.flags(default_instance_type='unknown_flavor')
self.assertRaises(exception.ApiError, self.assertRaises(exception.InstanceTypeNotFound,
instance_types.get_default_instance_type) instance_types.get_default_instance_type)
def test_will_get_instance_type_by_id(self): 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): def test_will_not_get_instance_type_by_unknown_id(self):
"""Ensure get by name returns default flavor with no name""" """Ensure get by name returns default flavor with no name"""
self.assertRaises(exception.ApiError, self.assertRaises(exception.InstanceTypeNotFound,
instance_types.get_instance_type, 10000) instance_types.get_instance_type, 10000)
def test_will_not_get_instance_type_with_bad_id(self): def test_will_not_get_instance_type_with_bad_id(self):
"""Ensure get by name returns default flavor with bad name""" """Ensure get by name returns default flavor with bad name"""
self.assertRaises(exception.ApiError, self.assertRaises(exception.InstanceTypeNotFound,
instance_types.get_instance_type, 'asdf') instance_types.get_instance_type, 'asdf')
def test_instance_type_get_by_None_name_returns_default(self): 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): def test_will_not_get_instance_type_with_bad_name(self):
"""Ensure get by name returns default flavor with bad name""" """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) instance_types.get_instance_type_by_name, 10000)
def test_will_not_get_instance_by_unknown_flavor_id(self): def test_will_not_get_instance_by_unknown_flavor_id(self):

View File

@@ -249,7 +249,7 @@ class VolumeTestCase(test.TestCase):
volume_api = nova.volume.api.API() volume_api = nova.volume.api.API()
volume = volume_api.get(self.context, volume['id']) volume = volume_api.get(self.context, volume['id'])
self.assertRaises(exception.ApiError, self.assertRaises(exception.InvalidVolume,
volume_api.create_snapshot, volume_api.create_snapshot,
self.context, volume, self.context, volume,
'fake_name', 'fake_description') 'fake_name', 'fake_description')

View File

@@ -85,7 +85,7 @@ class VolumeTypeTestCase(test.TestCase):
def test_non_existant_vol_type_shouldnt_delete(self): def test_non_existant_vol_type_shouldnt_delete(self):
"""Ensures that volume type creation fails with invalid args""" """Ensures that volume type creation fails with invalid args"""
self.assertRaises(exception.ApiError, self.assertRaises(exception.VolumeTypeNotFoundByName,
volume_types.destroy, self.ctxt, "sfsfsdfdfs") volume_types.destroy, self.ctxt, "sfsfsdfdfs")
def test_repeated_vol_types_shouldnt_raise(self): def test_repeated_vol_types_shouldnt_raise(self):

View File

@@ -90,7 +90,7 @@ class VsaTestCase(test.TestCase):
def test_vsa_create_wrong_image_name(self): def test_vsa_create_wrong_image_name(self):
param = {'image_name': 'wrong_image_name'} param = {'image_name': 'wrong_image_name'}
self.assertRaises(exception.ApiError, self.assertRaises(exception.ImageNotFound,
self.vsa_api.create, self.context, **param) self.vsa_api.create, self.context, **param)
def test_vsa_create_db_error(self): def test_vsa_create_db_error(self):
@@ -100,19 +100,19 @@ class VsaTestCase(test.TestCase):
raise exception.Error raise exception.Error
self.stubs.Set(nova.db, 'vsa_create', fake_vsa_create) self.stubs.Set(nova.db, 'vsa_create', fake_vsa_create)
self.assertRaises(exception.ApiError, self.assertRaises(exception.Error,
self.vsa_api.create, self.context) self.vsa_api.create, self.context)
def test_vsa_create_wrong_storage_params(self): def test_vsa_create_wrong_storage_params(self):
vsa_list1 = self.vsa_api.get_all(self.context) vsa_list1 = self.vsa_api.get_all(self.context)
param = {'storage': [{'stub': 1}]} param = {'storage': [{'stub': 1}]}
self.assertRaises(exception.ApiError, self.assertRaises(exception.InvalidVolumeType,
self.vsa_api.create, self.context, **param) self.vsa_api.create, self.context, **param)
vsa_list2 = self.vsa_api.get_all(self.context) vsa_list2 = self.vsa_api.get_all(self.context)
self.assertEqual(len(vsa_list2), len(vsa_list1)) self.assertEqual(len(vsa_list2), len(vsa_list1))
param = {'storage': [{'drive_name': 'wrong name'}]} param = {'storage': [{'drive_name': 'wrong name'}]}
self.assertRaises(exception.ApiError, self.assertRaises(exception.InvalidVolumeType,
self.vsa_api.create, self.context, **param) self.vsa_api.create, self.context, **param)
def test_vsa_create_with_storage(self, multi_vol_creation=True): def test_vsa_create_with_storage(self, multi_vol_creation=True):

View File

@@ -107,14 +107,14 @@ class VsaVolumesTestCase(test.TestCase):
'deleting') 'deleting')
def test_vsa_volume_delete_nonavail_volume(self): 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_param = self._default_volume_param()
volume_ref = self.volume_api.create(self.context, **volume_param) volume_ref = self.volume_api.create(self.context, **volume_param)
self.volume_api.update(self.context, self.volume_api.update(self.context,
volume_ref, volume_ref,
{'status': 'in-use'}) {'status': 'in-use'})
self.assertRaises(exception.ApiError, self.assertRaises(exception.InvalidVolume,
self.volume_api.delete, self.volume_api.delete,
self.context, volume_ref) self.context, volume_ref)

View File

@@ -551,8 +551,8 @@ class ProxyConnection(driver.ComputeDriver):
raise NotImplementedError() raise NotImplementedError()
def get_diagnostics(self, instance_name): def get_diagnostics(self, instance_name):
raise exception.ApiError(_("diagnostics are not supported " # diagnostics are not supported for baremetal
"for baremetal")) raise NotImplementedError()
def get_disks(self, instance_name): def get_disks(self, instance_name):
raise NotImplementedError() raise NotImplementedError()

View File

@@ -610,12 +610,12 @@ class VMWareVMOps(object):
LOG.exception(exc) LOG.exception(exc)
def pause(self, instance): def pause(self, instance):
"""Pause a VM instance.""" msg = _("pause not supported for vmwareapi")
raise exception.ApiError("pause not supported for vmwareapi") raise NotImplementedError(msg)
def unpause(self, instance): def unpause(self, instance):
"""Un-Pause a VM instance.""" msg = _("unpause not supported for vmwareapi")
raise exception.ApiError("unpause not supported for vmwareapi") raise NotImplementedError(msg)
def suspend(self, instance): def suspend(self, instance):
"""Suspend the specified instance.""" """Suspend the specified instance."""
@@ -694,8 +694,8 @@ class VMWareVMOps(object):
def get_diagnostics(self, instance): def get_diagnostics(self, instance):
"""Return data about VM diagnostics.""" """Return data about VM diagnostics."""
raise exception.ApiError("get_diagnostics not implemented for " msg = _("get_diagnostics not implemented for vmwareapi")
"vmwareapi") raise NotImplementedError(msg)
def get_console_output(self, instance): def get_console_output(self, instance):
"""Return snapshot of console.""" """Return snapshot of console."""

View File

@@ -71,8 +71,8 @@ class API(base.Base):
check_policy(context, 'create') check_policy(context, 'create')
if snapshot is not None: if snapshot is not None:
if snapshot['status'] != "available": if snapshot['status'] != "available":
raise exception.ApiError( msg = _("status must be available")
_("Snapshot status must be available")) raise exception.InvalidSnapshot(reason=msg)
if not size: if not size:
size = snapshot['volume_size'] size = snapshot['volume_size']
@@ -84,8 +84,7 @@ class API(base.Base):
pid = context.project_id pid = context.project_id
LOG.warn(_("Quota exceeded for %(pid)s, tried to create" LOG.warn(_("Quota exceeded for %(pid)s, tried to create"
" %(size)sG volume") % locals()) " %(size)sG volume") % locals())
raise exception.QuotaError(_("Volume quota exceeded. You cannot " raise exception.QuotaError(code="VolumeSizeTooLarge")
"create a volume of size %sG") % size)
if availability_zone is None: if availability_zone is None:
availability_zone = FLAGS.storage_availability_zone availability_zone = FLAGS.storage_availability_zone
@@ -131,7 +130,8 @@ class API(base.Base):
def delete(self, context, volume): def delete(self, context, volume):
volume_id = volume['id'] volume_id = volume['id']
if volume['status'] != "available": 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() now = utils.utcnow()
self.db.volume_update(context, volume_id, {'status': 'deleting', self.db.volume_update(context, volume_id, {'status': 'deleting',
'terminated_at': now}) 'terminated_at': now})
@@ -207,15 +207,18 @@ class API(base.Base):
def check_attach(self, context, volume): def check_attach(self, context, volume):
# TODO(vish): abstract status checking? # TODO(vish): abstract status checking?
if volume['status'] != "available": 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": if volume['attach_status'] == "attached":
raise exception.ApiError(_("Volume is already attached")) msg = _("already attached")
raise exception.InvalidVolume(reason=msg)
@wrap_check_policy @wrap_check_policy
def check_detach(self, context, volume): def check_detach(self, context, volume):
# TODO(vish): abstract status checking? # TODO(vish): abstract status checking?
if volume['status'] == "available": 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): def remove_from_compute(self, context, volume, instance_id, host):
"""Remove volume from specified compute host.""" """Remove volume from specified compute host."""
@@ -266,7 +269,8 @@ class API(base.Base):
check_policy(context, 'create_snapshot', volume) check_policy(context, 'create_snapshot', volume)
if ((not force) and (volume['status'] != "available")): 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 = { options = {
'volume_id': volume['id'], 'volume_id': volume['id'],
@@ -298,7 +302,8 @@ class API(base.Base):
@wrap_check_policy @wrap_check_policy
def delete_snapshot(self, context, snapshot): def delete_snapshot(self, context, snapshot):
if snapshot['status'] != "available": 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'], self.db.snapshot_update(context, snapshot['id'],
{'status': 'deleting'}) {'status': 'deleting'})
rpc.cast(context, rpc.cast(context,

View File

@@ -702,9 +702,7 @@ class SolidFireSanISCSIDriver(SanISCSIDriver):
if response.status != 200: if response.status != 200:
connection.close() connection.close()
msg = _("Error in SolidFire API response, status was: %s" raise exception.SolidFireAPIException(status=response.status)
% response.status)
raise exception.ApiError(msg)
else: else:
data = response.read() data = response.read()
@@ -763,9 +761,7 @@ class SolidFireSanISCSIDriver(SanISCSIDriver):
params = {} params = {}
data = self._issue_api_request('GetClusterInfo', params) data = self._issue_api_request('GetClusterInfo', params)
if 'result' not in data: if 'result' not in data:
msg = _("Error in SolidFire API response data was: %s" raise exception.SolidFireAPIDataException(data=data)
% data)
raise exception.ApiError(msg)
return data['result'] return data['result']
@@ -827,14 +823,10 @@ class SolidFireSanISCSIDriver(SanISCSIDriver):
'attributes': attributes} 'attributes': attributes}
data = self._issue_api_request('CreateVolume', params) data = self._issue_api_request('CreateVolume', params)
if 'result' not in data:
msg = _("Error in SolidFire API response data was: %s" if 'result' not in data or 'volumeID' not in data['result']:
% data) raise exception.SolidFireAPIDataException(data=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)
volume_id = data['result']['volumeID'] volume_id = data['result']['volumeID']
volume_list = self._get_volumes_by_sfaccount(account_id) volume_list = self._get_volumes_by_sfaccount(account_id)
@@ -873,9 +865,7 @@ class SolidFireSanISCSIDriver(SanISCSIDriver):
params = {'accountID': sfaccount['accountID']} params = {'accountID': sfaccount['accountID']}
data = self._issue_api_request('ListVolumesForAccount', params) data = self._issue_api_request('ListVolumesForAccount', params)
if 'result' not in data: if 'result' not in data:
msg = _("Error in SolidFire API response, data was: %s" raise exception.SolidFireAPIDataException(data=data)
% data)
raise exception.ApiError(msg)
found_count = 0 found_count = 0
volid = -1 volid = -1
@@ -891,9 +881,7 @@ class SolidFireSanISCSIDriver(SanISCSIDriver):
params = {'volumeID': volid} params = {'volumeID': volid}
data = self._issue_api_request('DeleteVolume', params) data = self._issue_api_request('DeleteVolume', params)
if 'result' not in data: if 'result' not in data:
msg = _("Error in SolidFire API response, data was: %s" raise exception.SolidFireAPIDataException(data=data)
% data)
raise exception.ApiError(msg)
LOG.debug(_("Leaving SolidFire delete_volume")) LOG.debug(_("Leaving SolidFire delete_volume"))

View File

@@ -39,21 +39,17 @@ def create(context, name, extra_specs={}):
extra_specs=extra_specs)) extra_specs=extra_specs))
except exception.DBError, e: except exception.DBError, e:
LOG.exception(_('DB error: %s') % e) LOG.exception(_('DB error: %s') % e)
raise exception.ApiError(_("Cannot create volume_type with " raise exception.VolumeTypeCreateFailed(name=name,
"name %(name)s and specs %(extra_specs)s") extra_specs=extra_specs)
% locals())
def destroy(context, name): def destroy(context, name):
"""Marks volume types as deleted.""" """Marks volume types as deleted."""
if name is None: if name is None:
raise exception.InvalidVolumeType(volume_type=name) msg = _("name cannot be None")
raise exception.InvalidVolumeType(reason=msg)
else: else:
try: db.volume_type_destroy(context, name)
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)
def get_all_types(context, inactive=0, search_opts={}): 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): def get_volume_type(ctxt, id):
"""Retrieves single volume type by id.""" """Retrieves single volume type by id."""
if id is None: if id is None:
raise exception.InvalidVolumeType(volume_type=id) msg = _("id cannot be None")
raise exception.InvalidVolumeType(reason=msg)
if ctxt is None: if ctxt is None:
ctxt = context.get_admin_context() ctxt = context.get_admin_context()
try: return db.volume_type_get(ctxt, id)
return db.volume_type_get(ctxt, id)
except exception.DBError:
raise exception.ApiError(_("Unknown volume type: %s") % id)
def get_volume_type_by_name(context, name): def get_volume_type_by_name(context, name):
"""Retrieves single volume type by name.""" """Retrieves single volume type by name."""
if name is None: 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)
return db.volume_type_get_by_name(context, name)
except exception.DBError:
raise exception.ApiError(_("Unknown volume type: %s") % name)
def is_key_value_present(volume_type_id, key, value, volume_type=None): def is_key_value_present(volume_type_id, key, value, volume_type=None):

View File

@@ -23,8 +23,6 @@ For assistance and guidelines pls contact
Zadara Storage Inc & Openstack community Zadara Storage Inc & Openstack community
""" """
import sys
from nova import compute from nova import compute
from nova import exception from nova import exception
from nova import flags 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_type') is None or
vol_type['extra_specs'].get('drive_size') is None): vol_type['extra_specs'].get('drive_size') is None):
raise exception.ApiError(_("Invalid drive type %s") msg = _("invalid drive data")
% vol_type['name']) raise exception.InvalidVolumeType(reason=msg)
def _get_default_vsa_instance_type(self): def _get_default_vsa_instance_type(self):
return instance_types.get_instance_type_by_name( return instance_types.get_instance_type_by_name(
@@ -104,13 +102,14 @@ class API(base.Base):
num_disks = node.get('num_drives', 1) num_disks = node.get('num_drives', 1)
if name is None: if name is None:
raise exception.ApiError(_("No drive_name param found in %s") msg = _("drive_name not defined")
% node) raise exception.InvalidVolumeType(reason=msg)
try: try:
vol_type = volume_types.get_volume_type_by_name(context, name) vol_type = volume_types.get_volume_type_by_name(context, name)
except exception.NotFound: except exception.NotFound:
raise exception.ApiError(_("Invalid drive type name %s") msg = _("invalid drive type name %s")
% name) raise exception.InvalidVolumeType(reason=msg % name)
self._check_volume_type_correctness(vol_type) self._check_volume_type_correctness(vol_type)
@@ -177,13 +176,10 @@ class API(base.Base):
# check if image is ready before starting any work # check if image is ready before starting any work
if image_name is None: if image_name is None:
image_name = FLAGS.vc_image_name image_name = FLAGS.vc_image_name
try:
image_service = self.compute_api.image_service image_service = self.compute_api.image_service
vc_image = image_service.show_by_name(context, image_name) vc_image = image_service.show_by_name(context, image_name)
vc_image_href = vc_image['id'] vc_image_href = vc_image['id']
except exception.ImageNotFound:
raise exception.ApiError(_("Failed to find configured image %s")
% image_name)
options = { options = {
'display_name': display_name, 'display_name': display_name,
@@ -198,10 +194,8 @@ class API(base.Base):
LOG.info(_("Creating VSA: %s") % options) LOG.info(_("Creating VSA: %s") % options)
# create DB entry for VSA instance # create DB entry for VSA instance
try: vsa_ref = self.db.vsa_create(context, options)
vsa_ref = self.db.vsa_create(context, options)
except exception.Error:
raise exception.ApiError(_(sys.exc_info()[1]))
vsa_id = vsa_ref['id'] vsa_id = vsa_ref['id']
vsa_name = vsa_ref['name'] vsa_name = vsa_ref['name']
@@ -209,10 +203,9 @@ class API(base.Base):
try: try:
volume_params = self._check_storage_parameters(context, vsa_name, volume_params = self._check_storage_parameters(context, vsa_name,
storage, shared) storage, shared)
except exception.ApiError: except exception.InvalidVolumeType:
self.db.vsa_destroy(context, vsa_id) self.db.vsa_destroy(context, vsa_id)
raise exception.ApiError(_("Error in storage parameters: %s") raise
% storage)
# after creating DB entry, re-check and set some defaults # after creating DB entry, re-check and set some defaults
updates = {} updates = {}
@@ -358,7 +351,7 @@ class API(base.Base):
LOG.info(_("VSA ID %(vsa_id)s: Deleting %(direction)s " LOG.info(_("VSA ID %(vsa_id)s: Deleting %(direction)s "
"volume %(vol_name)s"), locals()) "volume %(vol_name)s"), locals())
self.volume_api.delete(context, volume) self.volume_api.delete(context, volume)
except exception.ApiError: except exception.InvalidVolume:
LOG.info(_("Unable to delete volume %s"), volume['name']) LOG.info(_("Unable to delete volume %s"), volume['name'])
if force_delete: if force_delete:
LOG.info(_("VSA ID %(vsa_id)s: Forced delete. " LOG.info(_("VSA ID %(vsa_id)s: Forced delete. "