]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Add support for volume cloning to Nexenta driver
authorVictor Rodionov <vito.ordaz@gmail.com>
Thu, 1 Aug 2013 14:43:37 +0000 (18:43 +0400)
committerVictor Rodionov <vito.ordaz@gmail.com>
Sat, 10 Aug 2013 05:51:27 +0000 (09:51 +0400)
This patch implements missing functionality for Havana.

Change-Id: I39d838e955f25b8438a24f6aff5ec97fb3c14e4b

cinder/tests/test_nexenta.py
cinder/volume/drivers/nexenta/volume.py

index 08f9e1d0a87b61f2f8c318243634a0b2158c7787..6275b11b3c192edfd6e4374b8768b1ac93b85a0e 100644 (file)
@@ -40,10 +40,12 @@ class TestNexentaDriver(test.TestCase):
     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,
@@ -64,7 +66,7 @@ class TestNexentaDriver(test.TestCase):
             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',
@@ -95,6 +97,28 @@ class TestNexentaDriver(test.TestCase):
         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()
index fb1e94db0d448c9300fad245f0d5f737b181bed1..f423781683c50dfbd38a5b6e2f1cf084e7548fb6 100644 (file)
@@ -103,21 +103,22 @@ class NexentaDriver(driver.ISCSIDriver):  # pylint: disable=R0921
             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.
 
@@ -144,6 +145,46 @@ class NexentaDriver(driver.ISCSIDriver):  # pylint: disable=R0921
                 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.
 
@@ -167,7 +208,7 @@ class NexentaDriver(driver.ISCSIDriver):  # pylint: disable=R0921
     def delete_snapshot(self, snapshot):
         """Delete volume's snapshot on appliance.
 
-        :param snapshot: shapshot reference
+        :param snapshot: snapshot reference
         """
         try:
             self.nms.snapshot.destroy(