TEST_VOLUME_REF = {
'name': TEST_VOLUME_NAME,
'size': 1,
+ 'id': '1'
}
TEST_VOLUME_REF2 = {
'name': TEST_VOLUME_NAME2,
'size': 1,
+ 'id': '2'
}
TEST_SNAPSHOT_REF = {
'name': TEST_SNAPSHOT_NAME,
nexenta_sparse=True,
)
self.nms_mock = self.mox.CreateMockAnything()
- for mod in ['volume', 'zvol', 'iscsitarget',
+ for mod in ['volume', 'zvol', 'iscsitarget', 'appliance',
'stmf', 'scsidisk', 'snapshot']:
setattr(self.nms_mock, mod, self.mox.CreateMockAnything())
self.stubs.Set(jsonrpc, 'NexentaJSONProxy',
self.mox.ReplayAll()
self.drv.delete_volume(self.TEST_VOLUME_REF)
+ def test_create_cloned_volume(self):
+ vol = self.TEST_VOLUME_REF2
+ src_vref = self.TEST_VOLUME_REF
+ snapshot = {
+ 'volume_name': src_vref['name'],
+ 'name': 'cinder-clone-snap-%s' % vol['id'],
+ }
+ self.nms_mock.zvol.create_snapshot('cinder/%s' % src_vref['name'],
+ snapshot['name'], '')
+ cmd = 'zfs send %(src_vol)s@%(src_snap)s | zfs recv %(volume)s' % {
+ 'src_vol': 'cinder/%s' % src_vref['name'],
+ 'src_snap': snapshot['name'],
+ 'volume': 'cinder/%s' % vol['name']
+ }
+ self.nms_mock.appliance.execute(cmd)
+ self.nms_mock.snapshot.destroy('cinder/%s@%s' % (src_vref['name'],
+ snapshot['name']), '')
+ self.nms_mock.snapshot.destroy('cinder/%s@%s' % (vol['name'],
+ snapshot['name']), '')
+ self.mox.ReplayAll()
+ self.drv.create_cloned_volume(vol, src_vref)
+
def test_create_snapshot(self):
self.nms_mock.zvol.create_snapshot('cinder/volume1', 'snapshot1', '')
self.mox.ReplayAll()
raise LookupError(_("Volume %s does not exist in Nexenta SA"),
CONF.nexenta_volume)
- @staticmethod
- def _get_zvol_name(volume_name):
+ def _get_zvol_name(self, volume_name):
"""Return zvol name that corresponds given volume name."""
return '%s/%s' % (CONF.nexenta_volume, volume_name)
- @staticmethod
- def _get_target_name(volume_name):
+ def _get_target_name(self, volume_name):
"""Return iSCSI target name to access volume."""
return '%s%s' % (CONF.nexenta_target_prefix, volume_name)
- @staticmethod
- def _get_target_group_name(volume_name):
+ def _get_target_group_name(self, volume_name):
"""Return Nexenta iSCSI target group name for volume."""
return '%s%s' % (CONF.nexenta_target_group_prefix, volume_name)
+ def _get_clone_snap_name(self, volume):
+ """Return name for snapshot that will be used to clone the volume."""
+ return 'cinder-clone-snap-%(id)s' % volume
+
def create_volume(self, volume):
"""Create a zvol on appliance.
raise exception.VolumeIsBusy(volume_name=volume['name'])
raise
+ def create_cloned_volume(self, volume, src_vref):
+ """Creates a clone of the specified volume.
+
+ :param volume: new volume reference
+ :param src_vref: source volume reference
+ """
+ snapshot = {'volume_name': src_vref['name'],
+ 'name': self._get_clone_snap_name(volume)}
+ LOG.debug(_('Creating temp snapshot of the original volume: '
+ '%(volume_name)s@%(name)s'), snapshot)
+ self.create_snapshot(snapshot)
+ try:
+ cmd = 'zfs send %(src_vol)s@%(src_snap)s | zfs recv %(volume)s' % {
+ 'src_vol': self._get_zvol_name(src_vref['name']),
+ 'src_snap': snapshot['name'],
+ 'volume': self._get_zvol_name(volume['name'])
+ }
+ LOG.debug(_('Executing zfs send/recv on the appliance'))
+ self.nms.appliance.execute(cmd)
+ LOG.debug(_('zfs send/recv done, new volume %s created'),
+ volume['name'])
+ finally:
+ try:
+ # deleting temp snapshot of the original volume
+ self.delete_snapshot(snapshot)
+ except (nexenta.NexentaException, exception.SnapshotIsBusy):
+ LOG.warning(_('Failed to delete temp snapshot '
+ '%(volume)s@%(snapshot)s'),
+ {'volume': src_vref['name'],
+ 'snapshot': snapshot['name']})
+ try:
+ # deleting snapshot resulting from zfs recv
+ self.delete_snapshot({'volume_name': volume['name'],
+ 'name': snapshot['name']})
+ except (nexenta.NexentaException, exception.SnapshotIsBusy):
+ LOG.warning(_('Failed to delete zfs recv snapshot '
+ '%(volume)s@%(snapshot)s'),
+ {'volume': volume['name'],
+ 'snapshot': snapshot['name']})
+
def create_snapshot(self, snapshot):
"""Create snapshot of existing zvol on appliance.
def delete_snapshot(self, snapshot):
"""Delete volume's snapshot on appliance.
- :param snapshot: shapshot reference
+ :param snapshot: snapshot reference
"""
try:
self.nms.snapshot.destroy(