'), cfg.StrOpt('cinder_endpoint_template',
help='Override service catalog lookup with template for cinder '
'endpoint e.g. http://localhost:8776/v1/%(project_id)s'),
cfg.StrOpt('os_region_name',
help='Region name of this node'),
cfg.StrOpt('cinder_ca_certificates_file',
help='Location of ca certificates file to use for cinder '
'client requests.'),
cfg.IntOpt('cinder_http_retries',
default=3,
help='Number of cinderclient retries on failed http calls'),
cfg.BoolOpt('cinder_api_insecure',
default=False,
help='Allow to perform insecure SSL requests to cinder'),
cfg.BoolOpt('cinder_cross_az_attach',
default=True,
help='Allow attach between instance and volume in different '
'availability zones.'),
]
CONF = cfg.CONF
CONF.register_opts(cinder_opts)
LOG = logging.getLogger(__name__)
**** CubicPower OpenStack Study ****
def cinderclient(context):
# FIXME: the cinderclient ServiceCatalog object is mis-named.
# It actually contains the entire access blob.
# Only needed parts of the service catalog are passed in, see
# nova/context.py.
compat_catalog = {
'access': {'serviceCatalog': context.service_catalog or []}
}
sc = service_catalog.ServiceCatalog(compat_catalog)
if CONF.cinder_endpoint_template:
url = CONF.cinder_endpoint_template % context.to_dict()
else:
info = CONF.cinder_catalog_info
service_type, service_name, endpoint_type = info.split(':')
# extract the region if set in configuration
if CONF.os_region_name:
attr = 'region'
filter_value = CONF.os_region_name
else:
attr = None
filter_value = None
url = sc.url_for(attr=attr,
filter_value=filter_value,
service_type=service_type,
service_name=service_name,
endpoint_type=endpoint_type)
LOG.debug(_('Cinderclient connection created using URL: %s') % url)
c = cinder_client.Client(context.user_id,
context.auth_token,
project_id=context.project_id,
auth_url=url,
insecure=CONF.cinder_api_insecure,
retries=CONF.cinder_http_retries,
cacert=CONF.cinder_ca_certificates_file)
# noauth extracts user_id:project_id from auth_token
c.client.auth_token = context.auth_token or '%s:%s' % (context.user_id,
context.project_id)
c.client.management_url = url
return c
**** CubicPower OpenStack Study ****
def _untranslate_volume_summary_view(context, vol):
"""Maps keys for volumes summary view."""
d = {}
d['id'] = vol.id
d['status'] = vol.status
d['size'] = vol.size
d['availability_zone'] = vol.availability_zone
d['created_at'] = vol.created_at
# TODO(jdg): The calling code expects attach_time and
# mountpoint to be set. When the calling
# code is more defensive this can be
# removed.
d['attach_time'] = ""
d['mountpoint'] = ""
if vol.attachments:
att = vol.attachments[0]
d['attach_status'] = 'attached'
d['instance_uuid'] = att['server_id']
d['mountpoint'] = att['device']
else:
d['attach_status'] = 'detached'
d['display_name'] = vol.display_name
d['display_description'] = vol.display_description
# TODO(jdg): Information may be lost in this translation
d['volume_type_id'] = vol.volume_type
d['snapshot_id'] = vol.snapshot_id
d['volume_metadata'] = {}
for key, value in vol.metadata.items():
d['volume_metadata'][key] = value
if hasattr(vol, 'volume_image_metadata'):
d['volume_image_metadata'] = copy.deepcopy(vol.volume_image_metadata)
return d
**** CubicPower OpenStack Study ****
def _untranslate_snapshot_summary_view(context, snapshot):
"""Maps keys for snapshots summary view."""
d = {}
d['id'] = snapshot.id
d['status'] = snapshot.status
d['progress'] = snapshot.progress
d['size'] = snapshot.size
d['created_at'] = snapshot.created_at
d['display_name'] = snapshot.display_name
d['display_description'] = snapshot.display_description
d['volume_id'] = snapshot.volume_id
d['project_id'] = snapshot.project_id
d['volume_size'] = snapshot.size
return d
**** CubicPower OpenStack Study ****
def translate_volume_exception(method):
"""Transforms the exception for the volume but keeps its traceback intact.
"""
def wrapper(self, ctx, volume_id, *args, **kwargs):
try:
res = method(self, ctx, volume_id, *args, **kwargs)
except cinder_exception.ClientException:
exc_type, exc_value, exc_trace = sys.exc_info()
if isinstance(exc_value, cinder_exception.NotFound):
exc_value = exception.VolumeNotFound(volume_id=volume_id)
elif isinstance(exc_value, cinder_exception.BadRequest):
exc_value = exception.InvalidInput(reason=exc_value.message)
raise exc_value, None, exc_trace
return res
return wrapper
**** CubicPower OpenStack Study ****
def wrapper(self, ctx, volume_id, *args, **kwargs):
try:
res = method(self, ctx, volume_id, *args, **kwargs)
except cinder_exception.ClientException:
exc_type, exc_value, exc_trace = sys.exc_info()
if isinstance(exc_value, cinder_exception.NotFound):
exc_value = exception.VolumeNotFound(volume_id=volume_id)
elif isinstance(exc_value, cinder_exception.BadRequest):
exc_value = exception.InvalidInput(reason=exc_value.message)
raise exc_value, None, exc_trace
return res
return wrapper
**** CubicPower OpenStack Study ****
def translate_snapshot_exception(method):
"""Transforms the exception for the snapshot but keeps its traceback
intact.
"""
def wrapper(self, ctx, snapshot_id, *args, **kwargs):
try:
res = method(self, ctx, snapshot_id, *args, **kwargs)
except cinder_exception.ClientException:
exc_type, exc_value, exc_trace = sys.exc_info()
if isinstance(exc_value, cinder_exception.NotFound):
exc_value = exception.SnapshotNotFound(snapshot_id=snapshot_id)
raise exc_value, None, exc_trace
return res
return wrapper
**** CubicPower OpenStack Study ****
def wrapper(self, ctx, snapshot_id, *args, **kwargs):
try:
res = method(self, ctx, snapshot_id, *args, **kwargs)
except cinder_exception.ClientException:
exc_type, exc_value, exc_trace = sys.exc_info()
if isinstance(exc_value, cinder_exception.NotFound):
exc_value = exception.SnapshotNotFound(snapshot_id=snapshot_id)
raise exc_value, None, exc_trace
return res
return wrapper
**** CubicPower OpenStack Study ****
class API(object):
"""API for interacting with the volume manager."""
@translate_volume_exception
**** CubicPower OpenStack Study ****
def get(self, context, volume_id):
item = cinderclient(context).volumes.get(volume_id)
return _untranslate_volume_summary_view(context, item)
**** CubicPower OpenStack Study ****
def get_all(self, context, search_opts={}):
items = cinderclient(context).volumes.list(detailed=True)
rval = []
for item in items:
rval.append(_untranslate_volume_summary_view(context, item))
return rval
**** CubicPower OpenStack Study ****
def check_attached(self, context, volume):
"""Raise exception if volume in use."""
if volume['status'] != "in-use":
msg = _("status must be 'in-use'")
raise exception.InvalidVolume(reason=msg)
**** CubicPower OpenStack Study ****
def check_attach(self, context, volume, instance=None):
# TODO(vish): abstract status checking?
if volume['status'] != "available":
msg = _("status must be 'available'")
raise exception.InvalidVolume(reason=msg)
if volume['attach_status'] == "attached":
msg = _("already attached")
raise exception.InvalidVolume(reason=msg)
if instance and not CONF.cinder_cross_az_attach:
if instance['availability_zone'] != volume['availability_zone']:
msg = _("Instance and volume not in same availability_zone")
raise exception.InvalidVolume(reason=msg)
**** CubicPower OpenStack Study ****
def check_detach(self, context, volume):
# TODO(vish): abstract status checking?
if volume['status'] == "available":
msg = _("already detached")
raise exception.InvalidVolume(reason=msg)
@translate_volume_exception
**** CubicPower OpenStack Study ****
def reserve_volume(self, context, volume_id):
cinderclient(context).volumes.reserve(volume_id)
@translate_volume_exception
**** CubicPower OpenStack Study ****
def unreserve_volume(self, context, volume_id):
cinderclient(context).volumes.unreserve(volume_id)
@translate_volume_exception
**** CubicPower OpenStack Study ****
def begin_detaching(self, context, volume_id):
cinderclient(context).volumes.begin_detaching(volume_id)
@translate_volume_exception
**** CubicPower OpenStack Study ****
def roll_detaching(self, context, volume_id):
cinderclient(context).volumes.roll_detaching(volume_id)
@translate_volume_exception
**** CubicPower OpenStack Study ****
def attach(self, context, volume_id, instance_uuid, mountpoint):
cinderclient(context).volumes.attach(volume_id, instance_uuid,
mountpoint)
@translate_volume_exception
**** CubicPower OpenStack Study ****
def detach(self, context, volume_id):
cinderclient(context).volumes.detach(volume_id)
@translate_volume_exception
**** CubicPower OpenStack Study ****
def initialize_connection(self, context, volume_id, connector):
return cinderclient(context).volumes.initialize_connection(volume_id,
connector)
@translate_volume_exception
**** CubicPower OpenStack Study ****
def terminate_connection(self, context, volume_id, connector):
return cinderclient(context).volumes.terminate_connection(volume_id,
connector)
**** CubicPower OpenStack Study ****
def migrate_volume_completion(self, context, old_volume_id, new_volume_id,
error=False):
return cinderclient(context).volumes.migrate_volume_completion(
old_volume_id, new_volume_id, error)
**** CubicPower OpenStack Study ****
def create(self, context, size, name, description, snapshot=None,
image_id=None, volume_type=None, metadata=None,
availability_zone=None):
if snapshot is not None:
snapshot_id = snapshot['id']
else:
snapshot_id = None
kwargs = dict(snapshot_id=snapshot_id,
display_name=name,
display_description=description,
volume_type=volume_type,
user_id=context.user_id,
project_id=context.project_id,
availability_zone=availability_zone,
metadata=metadata,
imageRef=image_id)
try:
item = cinderclient(context).volumes.create(size, **kwargs)
return _untranslate_volume_summary_view(context, item)
except cinder_exception.BadRequest as e:
raise exception.InvalidInput(reason=unicode(e))
@translate_volume_exception
**** CubicPower OpenStack Study ****
def delete(self, context, volume_id):
cinderclient(context).volumes.delete(volume_id)
@translate_volume_exception
**** CubicPower OpenStack Study ****
def update(self, context, volume_id, fields):
raise NotImplementedError()
@translate_snapshot_exception
**** CubicPower OpenStack Study ****
def get_snapshot(self, context, snapshot_id):
item = cinderclient(context).volume_snapshots.get(snapshot_id)
return _untranslate_snapshot_summary_view(context, item)
**** CubicPower OpenStack Study ****
def get_all_snapshots(self, context):
items = cinderclient(context).volume_snapshots.list(detailed=True)
rvals = []
for item in items:
rvals.append(_untranslate_snapshot_summary_view(context, item))
return rvals
@translate_volume_exception
**** CubicPower OpenStack Study ****
def create_snapshot(self, context, volume_id, name, description):
item = cinderclient(context).volume_snapshots.create(volume_id,
False,
name,
description)
return _untranslate_snapshot_summary_view(context, item)
@translate_volume_exception
**** CubicPower OpenStack Study ****
def create_snapshot_force(self, context, volume_id, name, description):
item = cinderclient(context).volume_snapshots.create(volume_id,
True,
name,
description)
return _untranslate_snapshot_summary_view(context, item)
@translate_snapshot_exception
**** CubicPower OpenStack Study ****
def delete_snapshot(self, context, snapshot_id):
cinderclient(context).volume_snapshots.delete(snapshot_id)
**** CubicPower OpenStack Study ****
def get_volume_encryption_metadata(self, context, volume_id):
return cinderclient(context).volumes.get_encryption_metadata(volume_id)
@translate_volume_exception
**** CubicPower OpenStack Study ****
def get_volume_metadata(self, context, volume_id):
raise NotImplementedError()
@translate_volume_exception
**** CubicPower OpenStack Study ****
def delete_volume_metadata(self, context, volume_id, key):
raise NotImplementedError()
@translate_volume_exception
**** CubicPower OpenStack Study ****
def update_volume_metadata(self, context, volume_id,
metadata, delete=False):
raise NotImplementedError()
@translate_volume_exception
**** CubicPower OpenStack Study ****
def get_volume_metadata_value(self, volume_id, key):
raise NotImplementedError()
@translate_snapshot_exception
**** CubicPower OpenStack Study ****
def update_snapshot_status(self, context, snapshot_id, status):
vs = cinderclient(context).volume_snapshots
# '90%' here is used to tell Cinder that Nova is done
# with its portion of the 'creating' state. This can
# be removed when we are able to split the Cinder states
# into 'creating' and a separate state of
# 'creating_in_nova'. (Same for 'deleting' state.)
vs.update_snapshot_status(
snapshot_id,
{'status': status,
'progress': '90%'}
)