]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Nexenta iSCSI driver: fixed volume_migration
authorVictor Rodionov <vito.ordaz@gmail.com>
Mon, 23 Dec 2013 21:24:41 +0000 (13:24 -0800)
committerVictor Rodionov <vito.ordaz@gmail.com>
Tue, 4 Feb 2014 22:06:14 +0000 (14:06 -0800)
Fixed volume_migration updating volume provider_location.
Fixed temporal snapshot deleting after volume migrated.

Change-Id: Id23749cb3724e1510865425232b38b9fc32690f8
Closes-Bug: #1263258

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

index cfc0146091884b2fe31517947bdf60ee465f2176..824f898120cc18ca431cfc5af26e766481f3d159 100644 (file)
@@ -160,7 +160,9 @@ class TestNexentaISCSIDriver(test.TestCase):
             'capabilities': {
                 'vendor_name': 'Nexenta',
                 'location_info': 'NexentaISCSIDriver:1.1.1.1:cinder',
-                'free_capacity_gb': 1
+                'free_capacity_gb': 1,
+                'iscsi_target_portal_port': 3260,
+                'nms_url': 'http://admin:password@1.1.1.1:2000'
             }
         }
         snapshot = {
@@ -174,19 +176,26 @@ class TestNexentaISCSIDriver(test.TestCase):
         src = '%(volume)s/%(zvol)s@%(snapshot)s' % {
             'volume': 'cinder',
             'zvol': volume['name'],
-            'snapshot': snapshot['name']}
+            'snapshot': snapshot['name']
+        }
         dst = '1.1.1.1:cinder'
         cmd = ' '.join(['rrmgr -s zfs -c 1 -q -e -w 1024 -n 2', src, dst])
 
         self.nms_mock.appliance.execute(cmd)
 
-        self.nms_mock.snapshot.destroy('cinder/%(volume)s@%(snapshot)s' % {
-                                       'volume': volume['name'],
-                                       'snapshot': snapshot['name']}, '')
+        snapshot_name = 'cinder/%(volume)s@%(snapshot)s' % {
+            'volume': volume['name'],
+            'snapshot': snapshot['name']
+        }
+        self.nms_mock.snapshot.destroy(snapshot_name, '')
         volume_name = 'cinder/%s' % volume['name']
         self.nms_mock.zvol.get_child_props(volume_name,
                                            'origin').AndReturn(None)
         self.nms_mock.zvol.destroy(volume_name, '')
+        self.nms_mock.snapshot.destroy('cinder/%(volume)s@%(snapshot)s' % {
+            'volume': volume['name'],
+            'snapshot': snapshot['name']
+        }, '')
 
         self.mox.ReplayAll()
         self.drv.migrate_volume(None, volume, host)
index 81d1c84f6c390b9a8fe5a45c40472a825769abe1..5e4c9c817b4e3f2841189732ea6bb8de39c3b67a 100644 (file)
@@ -32,7 +32,7 @@ from cinder.volume.drivers.nexenta import jsonrpc
 from cinder.volume.drivers.nexenta import options
 from cinder.volume.drivers.nexenta import utils
 
-VERSION = '1.1.3'
+VERSION = '1.2.1'
 LOG = logging.getLogger(__name__)
 
 
@@ -48,6 +48,10 @@ class NexentaISCSIDriver(driver.ISCSIDriver):  # pylint: disable=R0921
         1.1.2 - Optimized create_cloned_volume, replaced zfs send recv with zfs
                 clone.
         1.1.3 - Extended volume stats provided by _update_volume_stats method.
+        1.2.0 - Added volume migration with storage assist method.
+        1.2.1 - Fixed bug #1263258: now migrate_volume update provider_location
+                of migrated volume; after migrating volume migrate_volume
+                destroy snapshot on migration destination.
     """
 
     VERSION = VERSION
@@ -73,6 +77,8 @@ class NexentaISCSIDriver(driver.ISCSIDriver):  # pylint: disable=R0921
         self.rrmgr_compression = self.configuration.nexenta_rrmgr_compression
         self.rrmgr_tcp_buf_size = self.configuration.nexenta_rrmgr_tcp_buf_size
         self.rrmgr_connections = self.configuration.nexenta_rrmgr_connections
+        self.iscsi_target_portal_port = \
+            self.configuration.nexenta_iscsi_target_portal_port
 
     @property
     def backend_name(self):
@@ -125,11 +131,6 @@ class NexentaISCSIDriver(driver.ISCSIDriver):  # pylint: disable=R0921
         name = snapshot.split('@')[-1]
         return name.startswith('cinder-clone-snapshot-')
 
-    @staticmethod
-    def _get_migrate_snapshot_name(volume):
-        """Return name for snapshot that will be used to migrate the volume."""
-        return 'cinder-migrate-snapshot-%(id)s' % volume
-
     def create_volume(self, volume):
         """Create a zvol on appliance.
 
@@ -215,6 +216,14 @@ class NexentaISCSIDriver(driver.ISCSIDriver):  # pylint: disable=R0921
                                    tcp_buf_size=self.rrmgr_tcp_buf_size,
                                    connections=self.rrmgr_connections)
 
+    @staticmethod
+    def get_nms_for_url(url):
+        """Returns initialized nms object for url."""
+        auto, scheme, user, password, host, port, path =\
+            utils.parse_nms_url(url)
+        return jsonrpc.NexentaJSONProxy(scheme, host, port, path, user,
+                                        password, auto=auto)
+
     def migrate_volume(self, ctxt, volume, host):
         """Migrate if volume and host are managed by Nexenta appliance.
 
@@ -230,14 +239,23 @@ class NexentaISCSIDriver(driver.ISCSIDriver):  # pylint: disable=R0921
         if volume['status'] != 'available':
             return false_ret
 
-        if 'location_info' not in host['capabilities']:
+        if 'capabilities' not in host:
             return false_ret
 
-        dst_parts = host['capabilities']['location_info'].split(':')
+        capabilities = host['capabilities']
 
-        if host['capabilities']['vendor_name'] != 'Nexenta' or \
-           dst_parts[0] != self.__class__.__name__ or \
-           host['capabilities']['free_capacity_gb'] < volume['size']:
+        if 'location_info' not in capabilities or \
+                'iscsi_target_portal_port' not in capabilities or \
+                'nms_url' not in capabilities:
+            return false_ret
+
+        iscsi_target_portal_port = capabilities['iscsi_target_portal_port']
+        nms_url = capabilities['nms_url']
+        dst_parts = capabilities['location_info'].split(':')
+
+        if capabilities.get('vendor_name') != 'Nexenta' or \
+                dst_parts[0] != self.__class__.__name__ or \
+                capabilities['free_capacity_gb'] < volume['size']:
             return false_ret
 
         dst_host, dst_volume = dst_parts[1:]
@@ -248,19 +266,22 @@ class NexentaISCSIDriver(driver.ISCSIDriver):  # pylint: disable=R0921
             if bind.index(dst_host) != -1:
                 ssh_bound = True
                 break
-        if not(ssh_bound):
+        if not ssh_bound:
             LOG.warning(_("Remote NexentaStor appliance at %s should be "
                           "SSH-bound."), dst_host)
 
         # Create temporary snapshot of volume on NexentaStor Appliance.
-        snapshot = {'volume_name': volume['name'],
-                    'name': self._get_migrate_snapshot_name(volume)}
+        snapshot = {
+            'volume_name': volume['name'],
+            'name': utils.get_migrate_snapshot_name(volume)
+        }
         self.create_snapshot(snapshot)
 
         src = '%(volume)s/%(zvol)s@%(snapshot)s' % {
             'volume': self.volume,
             'zvol': volume['name'],
-            'snapshot': snapshot['name']}
+            'snapshot': snapshot['name']
+        }
         dst = ':'.join([dst_host, dst_volume])
 
         try:
@@ -284,7 +305,23 @@ class NexentaISCSIDriver(driver.ISCSIDriver):  # pylint: disable=R0921
                           "NexentaStor Appliance: %(exc)s"),
                         {'volume': volume['name'], 'exc': exc})
 
-        return (True, None)
+        dst_nms = self.get_nms_for_url(nms_url)
+        dst_snapshot = '%s/%s@%s' % (dst_volume, volume['name'],
+                                     snapshot['name'])
+        try:
+            dst_nms.snapshot.destroy(dst_snapshot, '')
+        except nexenta.NexentaException as exc:
+            LOG.warning(_("Cannot delete temporary destination snapshot "
+                          "%(dst)s on NexentaStor Appliance: %(exc)s"),
+                        {'dst': dst_snapshot, 'exc': exc})
+
+        provider_location = '%(host)s:%(port)s,1 %(name)s 0' % {
+            'host': dst_host,
+            'port': iscsi_target_portal_port,
+            'name': self._get_target_name(volume['name'])
+        }
+
+        return True, {'provider_location': provider_location}
 
     def create_snapshot(self, snapshot):
         """Create snapshot of existing zvol on appliance.
@@ -560,5 +597,7 @@ class NexentaISCSIDriver(driver.ISCSIDriver):  # pylint: disable=R0921
             'reserved_percentage': 0,
             'QoS_support': False,
             'volume_backend_name': self.backend_name,
-            'location_info': location_info
+            'location_info': location_info,
+            'iscsi_target_portal_port': self.iscsi_target_portal_port,
+            'nms_url': self.nms.url
         }
index 4fa9f22fb4842984347c21b5a25ef5574c7d8e57..c724a530c032e84c6da32cb8dbc91fb7576e1d6c 100644 (file)
@@ -118,3 +118,8 @@ def parse_nms_url(url):
     else:
         host, port = host_and_port, '2000'
     return auto, scheme, user, password, host, port, '/rest/nms/'
+
+
+def get_migrate_snapshot_name(volume):
+    """Return name for snapshot that will be used to migrate the volume."""
+    return 'cinder-migrate-snapshot-%(id)s' % volume