volume_ref['attach_status'] = 'detached'
volume_ref['instance_uuid'] = None
volume_ref['attached_host'] = None
+ volume_ref['attach_time'] = None
volume_ref.save(session=session)
from cinder import exception
from cinder.openstack.common import log as logging
+from cinder.openstack.common import timeutils
from cinder import test
from cinder.volume import configuration as conf
from cinder.volume.drivers.solidfire import SolidFireDriver
'name': 'testvol',
'size': 1,
'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
- 'volume_type_id': 'fast'}
+ 'volume_type_id': 'fast',
+ 'created_at': timeutils.utcnow()}
sfv = SolidFireDriver(configuration=self.configuration)
model_update = sfv.create_volume(testvol)
'name': 'testvol',
'size': 1,
'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
- 'volume_type_id': None}
+ 'volume_type_id': None,
+ 'created_at': timeutils.utcnow()}
+
sfv = SolidFireDriver(configuration=self.configuration)
model_update = sfv.create_volume(testvol)
self.assertNotEqual(model_update, None)
'name': 'testvol',
'size': 1,
'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
- 'volume_type_id': None}
+ 'volume_type_id': None,
+ 'created_at': timeutils.utcnow()}
+
self.configuration.sf_emulate_512 = False
sfv = SolidFireDriver(configuration=self.configuration)
model_update = sfv.create_volume(testvol)
'74-4cb7-bd55-14aed659a0cc.4060 0',
'provider_auth': 'CHAP stack-1-a60e2611875f40199931f2'
'c76370d66b 2FE0CQ8J196R',
- 'provider_geometry': '4096 4096'
+ 'provider_geometry': '4096 4096',
+ 'created_at': timeutils.utcnow(),
}
sfv = SolidFireDriver(configuration=self.configuration)
'size': 1,
'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
'metadata': [preset_qos],
- 'volume_type_id': None}
+ 'volume_type_id': None,
+ 'created_at': timeutils.utcnow()}
sfv = SolidFireDriver(configuration=self.configuration)
model_update = sfv.create_volume(testvol)
testvol = {'project_id': 'testprjid',
'name': 'testvol',
'size': 1,
- 'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66'}
+ 'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
+ 'created_at': timeutils.utcnow()}
sfv = SolidFireDriver(configuration=self.configuration)
try:
sfv.create_volume(testvol)
testvol = {'project_id': 'testprjid',
'name': 'test_volume',
'size': 1,
- 'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66'}
+ 'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
+ 'created_at': timeutils.utcnow()}
+
sfv = SolidFireDriver(configuration=self.configuration)
sfv.delete_volume(testvol)
testvol = {'project_id': 'testprjid',
'name': 'no-name',
'size': 1,
- 'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66'}
+ 'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
+ 'created_at': timeutils.utcnow()}
+
sfv = SolidFireDriver(configuration=self.configuration)
try:
sfv.delete_volume(testvol)
testvol = {'project_id': 'testprjid',
'name': 'no-name',
'size': 1,
- 'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66'}
+ 'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
+ 'created_at': timeutils.utcnow()}
+
sfv = SolidFireDriver(configuration=self.configuration)
self.assertRaises(exception.SfAccountNotFound,
sfv.delete_volume,
testvol = {'project_id': 'testprjid',
'name': 'test_volume',
'size': 1,
- 'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66'}
+ 'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
+ 'created_at': timeutils.utcnow()}
+
sfv = SolidFireDriver(configuration=self.configuration)
sfv.extend_volume(testvol, 2)
testvol = {'project_id': 'testprjid',
'name': 'no-name',
'size': 1,
- 'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66'}
+ 'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
+ 'created_at': timeutils.utcnow()}
+
sfv = SolidFireDriver(configuration=self.configuration)
self.assertRaises(exception.SfAccountNotFound,
sfv.extend_volume,
"""Disallow connection from connector"""
raise NotImplementedError()
- def attach_volume(self, context, volume_id, instance_uuid, host_name,
+ def attach_volume(self, context, volume, instance_uuid, host_name,
mountpoint):
"""Callback for volume attached to instance or host."""
pass
- def detach_volume(self, context, volume_id):
+ def detach_volume(self, context, volume):
"""Callback for volume detached."""
pass
"""Disallow connection from connector."""
pass
- def detach_volume(self, context, volume_id):
+ def detach_volume(self, context, volume):
"""Callback for volume detached."""
pass
from cinder import context
from cinder import exception
from cinder.openstack.common import log as logging
+from cinder.openstack.common import timeutils
from cinder.volume.drivers.san.san import SanISCSIDriver
from cinder.volume import volume_types
# to set any that were provided
params = {'volumeID': sf_volume_id}
+ create_time = timeutils.strtime(v_ref['created_at'])
attributes = {'uuid': v_ref['id'],
'is_clone': 'True',
- 'src_uuid': src_uuid}
+ 'src_uuid': src_uuid,
+ 'created_at': create_time}
if qos:
params['qos'] = qos
for k, v in qos.items():
if type_id is not None:
qos = self._set_qos_by_volume_type(ctxt, type_id)
+ create_time = timeutils.strtime(volume['created_at'])
attributes = {'uuid': volume['id'],
- 'is_clone': 'False'}
+ 'is_clone': 'False',
+ 'created_at': create_time}
if qos:
for k, v in qos.items():
attributes[k] = str(v)
data['thin_provision_percent'] =\
results['thinProvisioningPercent']
self.cluster_stats = data
+
+ def attach_volume(self, context, volume,
+ instance_uuid, host_name,
+ mountpoint):
+
+ LOG.debug(_("Entering SolidFire attach_volume..."))
+ sfaccount = self._get_sfaccount(volume['project_id'])
+ params = {'accountID': sfaccount['accountID']}
+
+ sf_vol = self._get_sf_volume(volume['id'], params)
+ if sf_vol is None:
+ LOG.error(_("Volume ID %s was not found on "
+ "the SolidFire Cluster!"), volume['id'])
+ raise exception.VolumeNotFound(volume_id=volume['id'])
+
+ attributes = sf_vol['attributes']
+ attributes['attach_time'] = volume.get('attach_time', None)
+ attributes['attached_to'] = instance_uuid
+ params = {
+ 'volumeID': sf_vol['volumeID'],
+ 'attributes': attributes
+ }
+
+ data = self._issue_api_request('ModifyVolume', params)
+
+ if 'result' not in data:
+ raise exception.SolidFireAPIDataException(data=data)
+
+ def detach_volume(self, context, volume):
+
+ LOG.debug(_("Entering SolidFire attach_volume..."))
+ sfaccount = self._get_sfaccount(volume['project_id'])
+ params = {'accountID': sfaccount['accountID']}
+
+ sf_vol = self._get_sf_volume(volume['id'], params)
+ if sf_vol is None:
+ LOG.error(_("Volume ID %s was not found on "
+ "the SolidFire Cluster!"), volume['id'])
+ raise exception.VolumeNotFound(volume_id=volume['id'])
+
+ attributes = sf_vol['attributes']
+ attributes['attach_time'] = None
+ attributes['attached_to'] = None
+ params = {
+ 'volumeID': sf_vol['volumeID'],
+ 'attributes': attributes
+ }
+
+ data = self._issue_api_request('ModifyVolume', params)
+
+ if 'result' not in data:
+ raise exception.SolidFireAPIDataException(data=data)
self.db.volume_update(context,
volume_ref['id'],
{'status': volume_ref['status'],
- 'launched_at': now})
+ 'launched_at': now})
LOG.info(_("volume %s: created successfully"), volume_ref['name'])
self._reset_stats()
elif volume['status'] != "available":
msg = _("status must be available")
raise exception.InvalidVolume(reason=msg)
+
+ # TODO(jdg): attach_time column is currently varchar
+ # we should update this to a date-time object
+ # also consider adding detach_time?
+ now = timeutils.strtime()
self.db.volume_update(context, volume_id,
{"instance_uuid": instance_uuid,
"attached_host": host_name,
- "status": "attaching"})
+ "status": "attaching",
+ "attach_time": now})
if instance_uuid and not uuidutils.is_uuid_like(instance_uuid):
self.db.volume_update(context,
host_name_sanitized = utils.sanitize_hostname(
host_name) if host_name else None
+ volume = self.db.volume_get(context, volume_id)
try:
self.driver.attach_volume(context,
- volume_id,
+ volume,
instance_uuid,
host_name_sanitized,
mountpoint)
"""Updates db to show volume is detached"""
# TODO(vish): refactor this into a more general "unreserve"
# TODO(sleepsonthefloor): Is this 'elevated' appropriate?
+
+ volume = self.db.volume_get(context, volume_id)
try:
- self.driver.detach_volume(context, volume_id)
+ self.driver.detach_volume(context, volume)
except Exception:
with excutils.save_and_reraise_exception():
self.db.volume_update(context,
self.db.volume_detached(context.elevated(), volume_id)
# Check for https://bugs.launchpad.net/cinder/+bug/1065702
- volume_ref = self.db.volume_get(context, volume_id)
- if (volume_ref['provider_location'] and
- volume_ref['name'] not in volume_ref['provider_location']):
- self.driver.ensure_export(context, volume_ref)
+ volume = self.db.volume_get(context, volume_id)
+ if (volume['provider_location'] and
+ volume['name'] not in volume['provider_location']):
+ self.driver.ensure_export(context, volume)
def _copy_image_to_volume(self, context, volume, image_service, image_id):
"""Downloads Glance image to the specified volume."""