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:
@@ -1607,7 +1607,7 @@ class VsaDriveTypeCommands(object):
|
||||
"""Marks volume types as deleted"""
|
||||
try:
|
||||
volume_types.destroy(self.context, name)
|
||||
except exception.ApiError:
|
||||
except exception.InvalidVolumeType:
|
||||
print "Valid volume type name is required"
|
||||
sys.exit(1)
|
||||
except exception.DBError, e:
|
||||
@@ -1786,7 +1786,7 @@ class InstanceTypeCommands(object):
|
||||
"""Marks instance types / flavors as deleted"""
|
||||
try:
|
||||
instance_types.destroy(name)
|
||||
except exception.ApiError:
|
||||
except exception.InstanceTypeNotFound:
|
||||
print "Valid instance type name is required"
|
||||
sys.exit(1)
|
||||
except exception.DBError, e:
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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'])
|
||||
|
||||
@@ -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']}
|
||||
|
||||
|
||||
@@ -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}
|
||||
|
||||
|
||||
@@ -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']}}
|
||||
|
||||
|
||||
@@ -204,14 +204,14 @@ class FloatingIPActionController(wsgi.Controller):
|
||||
msg = _("Address not specified")
|
||||
raise webob.exc.HTTPBadRequest(explanation=msg)
|
||||
|
||||
try:
|
||||
instance = self.compute_api.get(context, id)
|
||||
|
||||
try:
|
||||
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)
|
||||
|
||||
@@ -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)
|
||||
instance = self._get_instance(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)
|
||||
|
||||
@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)
|
||||
instance = self._get_instance(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)
|
||||
|
||||
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -496,13 +496,9 @@ class Controller(wsgi.Controller):
|
||||
"InstanceLimitExceeded": error.message,
|
||||
}
|
||||
|
||||
expl = code_mappings.get(error.code)
|
||||
if expl:
|
||||
expl = code_mappings.get(error.kwargs['code'], error.message)
|
||||
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})
|
||||
|
||||
def _validate_server_name(self, value):
|
||||
if not isinstance(value, basestring):
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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:
|
||||
if not nw_info:
|
||||
raise exception.FixedIpNotFoundForInstance(
|
||||
instance_id=instance_uuid)
|
||||
|
||||
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)
|
||||
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:
|
||||
LOG.warning(_('multiple fixedips exist, using the first: %s'),
|
||||
ips[0]['address'])
|
||||
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'])
|
||||
return
|
||||
raise exception.ApiError(fail_bag)
|
||||
floating_address=address, fixed_address=ips[0]['address'])
|
||||
|
||||
@wrap_check_policy
|
||||
def get_instance_metadata(self, context, instance):
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
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)
|
||||
|
||||
|
||||
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)
|
||||
|
||||
|
||||
# TODO(termie): flavor-specific code should probably be in the API that uses
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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'}}
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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."""
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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"))
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
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)
|
||||
|
||||
|
||||
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)
|
||||
|
||||
|
||||
def is_key_value_present(volume_type_id, key, value, volume_type=None):
|
||||
|
||||
@@ -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)
|
||||
|
||||
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_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. "
|
||||
|
||||
Reference in New Issue
Block a user