]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
IBM Storwize with pool-aware-cinder-scheduler
authorXiaoqin Li <lixqin@cn.ibm.com>
Thu, 25 Feb 2016 08:36:11 +0000 (00:36 -0800)
committerJay S Bryant <jsbryant@us.ibm.com>
Mon, 29 Feb 2016 20:19:47 +0000 (14:19 -0600)
Storwize cinder driver only supports config one pool
within one backend right now. This change adds support
for multi-pools aware for scheduler.
storwize_svc_volpool_name accepts a list of pools
separated by comma in cinder.conf now.

User-Visible Change
-------------------
DocImpact
The configuration flag storwize_svc_volpool_name
should be updated to a ListOpt.

Implements: bp Storwize-pool-aware-support
Change-Id: If6f1decf4d6244b1e04b05b8662d891fb16c6790

cinder/tests/unit/test_storwize_svc.py
cinder/volume/drivers/ibm/storwize_svc/storwize_svc_common.py
cinder/volume/drivers/ibm/storwize_svc/storwize_svc_fc.py
cinder/volume/drivers/ibm/storwize_svc/storwize_svc_iscsi.py
releasenotes/notes/storwize-pool-aware-support-7a40c9934642b202.yaml [new file with mode: 0644]

index 013bdfa2513ef5fff9bc49ca68acd27e1dabc9f9..368ff0d24a62773a2edd522a76909cb2f3779c1f 100644 (file)
@@ -43,6 +43,7 @@ from cinder.volume.drivers.ibm.storwize_svc import storwize_svc_common
 from cinder.volume.drivers.ibm.storwize_svc import storwize_svc_fc
 from cinder.volume.drivers.ibm.storwize_svc import storwize_svc_iscsi
 from cinder.volume import qos_specs
+from cinder.volume import utils as volume_utils
 from cinder.volume import volume_types
 
 
@@ -377,25 +378,30 @@ class StorwizeSVCManagementSimulator(object):
 
     # Print mostly made-up stuff in the correct syntax, assume -bytes passed
     def _cmd_lsmdiskgrp(self, **kwargs):
-        rows = [None] * 4
-        rows[0] = ['id', 'name', 'status', 'mdisk_count',
-                   'vdisk_count', 'capacity', 'extent_size',
-                   'free_capacity', 'virtual_capacity', 'used_capacity',
-                   'real_capacity', 'overallocation', 'warning',
-                   'easy_tier', 'easy_tier_status']
-        rows[1] = ['1', self._flags['storwize_svc_volpool_name'], 'online',
-                   '1', six.text_type(len(self._volumes_list)),
-                   '3573412790272', '256', '3529926246400', '1693247906775',
-                   '277841182', '38203734097', '47', '80', 'auto',
-                   'inactive']
-        rows[2] = ['2', 'openstack2', 'online',
-                   '1', '0', '3573412790272', '256',
-                   '3529432325160', '1693247906775', '277841182',
-                   '38203734097', '47', '80', 'auto', 'inactive']
-        rows[3] = ['3', 'openstack3', 'online',
-                   '1', '0', '3573412790272', '128',
-                   '3529432325160', '1693247906775', '277841182',
-                   '38203734097', '47', '80', 'auto', 'inactive']
+        pool_num = len(self._flags['storwize_svc_volpool_name'])
+        rows = []
+        rows.append(['id', 'name', 'status', 'mdisk_count',
+                     'vdisk_count', 'capacity', 'extent_size',
+                     'free_capacity', 'virtual_capacity', 'used_capacity',
+                     'real_capacity', 'overallocation', 'warning',
+                     'easy_tier', 'easy_tier_status'])
+        for i in range(0, pool_num):
+            row_data = [str(i + 1),
+                        self._flags['storwize_svc_volpool_name'][i], 'online',
+                        '1', six.text_type(len(self._volumes_list)),
+                        '3573412790272', '256', '3529926246400',
+                        '1693247906775',
+                        '26843545600', '38203734097', '47', '80', 'auto',
+                        'inactive']
+            rows.append(row_data)
+        rows.append([str(pool_num + 1), 'openstack2', 'online',
+                     '1', '0', '3573412790272', '256',
+                     '3529432325160', '1693247906775', '26843545600',
+                     '38203734097', '47', '80', 'auto', 'inactive'])
+        rows.append([str(pool_num + 2), 'openstack3', 'online',
+                     '1', '0', '3573412790272', '128',
+                     '3529432325160', '1693247906775', '26843545600',
+                     '38203734097', '47', '80', 'auto', 'inactive'])
         if 'obj' not in kwargs:
             return self._print_info_cmd(rows=rows, **kwargs)
         else:
@@ -403,19 +409,20 @@ class StorwizeSVCManagementSimulator(object):
             if pool_name == kwargs['obj']:
                 raise exception.InvalidInput(
                     reason=_('obj missing quotes %s') % kwargs['obj'])
-            elif pool_name == self._flags['storwize_svc_volpool_name']:
-                row = rows[1]
+            elif pool_name in self._flags['storwize_svc_volpool_name']:
+                for each_row in rows:
+                    if pool_name in each_row:
+                        row = each_row
+                        break
             elif pool_name == 'openstack2':
-                row = rows[2]
+                row = rows[-2]
             elif pool_name == 'openstack3':
-                row = rows[3]
+                row = rows[-1]
             else:
                 return self._errors['CMMVC5754E']
-
             objrows = []
             for idx, val in enumerate(rows[0]):
                 objrows.append([val, row[idx]])
-
             if 'nohdr' in kwargs:
                 for index in range(len(objrows)):
                     objrows[index] = ' '.join(objrows[index][1:])
@@ -426,6 +433,19 @@ class StorwizeSVCManagementSimulator(object):
 
             return ('%s' % '\n'.join(objrows), '')
 
+    def _get_mdiskgrp_id(self, mdiskgrp):
+        grp_num = len(self._flags['storwize_svc_volpool_name'])
+        if mdiskgrp in self._flags['storwize_svc_volpool_name']:
+            for i in range(grp_num):
+                if mdiskgrp == self._flags['storwize_svc_volpool_name'][i]:
+                    return i + 1
+        elif mdiskgrp == 'openstack2':
+            return grp_num + 1
+        elif mdiskgrp == 'openstack3':
+            return grp_num + 2
+        else:
+            return None
+
     # Print mostly made-up stuff in the correct syntax
     def _cmd_lsnodecanister(self, **kwargs):
         rows = [None] * 3
@@ -620,6 +640,14 @@ port_speed!N/A
         volume_info['id'] = self._find_unused_id(self._volumes_list)
         volume_info['uid'] = ('ABCDEF' * 3) + ('0' * 14) + volume_info['id']
 
+        mdiskgrp = kwargs['mdiskgrp'].strip('\'\"')
+        if mdiskgrp == kwargs['mdiskgrp']:
+            raise exception.InvalidInput(
+                reason=_('mdiskgrp missing quotes %s') % kwargs['mdiskgrp'])
+        mdiskgrp_id = self._get_mdiskgrp_id(mdiskgrp)
+        volume_info['mdisk_grp_name'] = mdiskgrp
+        volume_info['mdisk_grp_id'] = str(mdiskgrp_id)
+
         if 'name' in kwargs:
             volume_info['name'] = kwargs['name'].strip('\'\"')
         else:
@@ -677,17 +705,12 @@ port_speed!N/A
                   'status': 'online',
                   'sync': 'yes',
                   'primary': 'yes',
-                  'mdisk_grp_id': '1',
-                  'mdisk_grp_name': self._flags['storwize_svc_volpool_name'],
+                  'mdisk_grp_id': str(mdiskgrp_id),
+                  'mdisk_grp_name': mdiskgrp,
                   'easy_tier': volume_info['easy_tier'],
                   'compressed_copy': volume_info['compressed_copy']}
         volume_info['copies'] = {'0': vol_cp}
 
-        mdiskgrp = kwargs['mdiskgrp'].strip('\'\"')
-        if mdiskgrp == kwargs['mdiskgrp']:
-            raise exception.InvalidInput(
-                reason=_('mdiskgrp missing quotes %s') % kwargs['mdiskgrp'])
-
         if volume_info['name'] in self._volumes_list:
             return self._errors['CMMVC6035E']
         else:
@@ -773,13 +796,12 @@ port_speed!N/A
                 rows.append([six.text_type(vol['id']), vol['name'],
                              vol['IO_group_id'],
                              vol['IO_group_name'], 'online', '0',
-                             self._flags['storwize_svc_volpool_name'],
+                             self._flags['storwize_svc_volpool_name'][0],
                              cap, 'striped',
                              fcmap_info['fc_id'], fcmap_info['fc_name'],
                              '', '', vol['uid'],
                              fcmap_info['fc_map_count'], '1', 'empty',
                              '1', 'no'])
-
         if 'obj' not in kwargs:
             return self._print_info_cmd(rows=rows, **kwargs)
         else:
@@ -1510,12 +1532,8 @@ port_speed!N/A
         copy_info['sync'] = 'no'
         copy_info['primary'] = 'no'
         copy_info['mdisk_grp_name'] = mdiskgrp
-        if mdiskgrp == self._flags['storwize_svc_volpool_name']:
-            copy_info['mdisk_grp_id'] = '1'
-        elif mdiskgrp == 'openstack2':
-            copy_info['mdisk_grp_id'] = '2'
-        elif mdiskgrp == 'openstack3':
-            copy_info['mdisk_grp_id'] = '3'
+        copy_info['mdisk_grp_id'] = str(self._get_mdiskgrp_id(mdiskgrp))
+
         if 'easytier' in kwargs:
             if kwargs['easytier'] == 'on':
                 copy_info['easy_tier'] = 'on'
@@ -1776,7 +1794,7 @@ class StorwizeSVCISCSIDriverTestCase(test.TestCase):
             self._def_flags = {'san_ip': 'hostname',
                                'san_login': 'user',
                                'san_password': 'pass',
-                               'storwize_svc_volpool_name': 'openstack',
+                               'storwize_svc_volpool_name': ['openstack'],
                                'storwize_svc_flashcopy_timeout': 20,
                                'storwize_svc_flashcopy_rate': 49,
                                'storwize_svc_multipath_enabled': False,
@@ -1790,7 +1808,7 @@ class StorwizeSVCISCSIDriverTestCase(test.TestCase):
                                'host': 'storwize-svc-test',
                                'wwpns': wwpns,
                                'initiator': initiator}
-            self.sim = StorwizeSVCManagementSimulator('openstack')
+            self.sim = StorwizeSVCManagementSimulator(['openstack'])
 
             self.iscsi_driver.set_fake_storage(self.sim)
             self.ctxt = context.get_admin_context()
@@ -1814,6 +1832,12 @@ class StorwizeSVCISCSIDriverTestCase(test.TestCase):
             self._set_flag(k, v)
 
     def _create_volume(self, **kwargs):
+        pool = self._def_flags['storwize_svc_volpool_name'][0]
+        prop = {'host': 'openstack@svc#%s' % pool,
+                'size': 1}
+        for p in prop.keys():
+            if p not in kwargs:
+                kwargs[p] = prop[p]
         vol = testutils.create_volume(self.ctxt, **kwargs)
         self.iscsi_driver.create_volume(vol)
         return vol
@@ -1823,6 +1847,7 @@ class StorwizeSVCISCSIDriverTestCase(test.TestCase):
         self.db.volume_destroy(self.ctxt, volume['id'])
 
     def _generate_vol_info(self, vol_name, vol_id):
+        pool = self._def_flags['storwize_svc_volpool_name'][0]
         rand_id = six.text_type(random.randint(10000, 99999))
         if vol_name:
             return {'name': 'snap_volume%s' % rand_id,
@@ -1830,13 +1855,14 @@ class StorwizeSVCISCSIDriverTestCase(test.TestCase):
                     'id': rand_id,
                     'volume_id': vol_id,
                     'volume_size': 10,
-                    'mdisk_grp_name': 'openstack'}
+                    'mdisk_grp_name': pool}
         else:
             return {'name': 'test_volume%s' % rand_id,
                     'size': 10,
                     'id': rand_id,
                     'volume_type_id': None,
-                    'mdisk_grp_name': 'openstack'}
+                    'mdisk_grp_name': pool,
+                    'host': 'openstack@svc#%s' % pool}
 
     def _assert_vol_exists(self, name, exists):
         is_vol_defined = self.iscsi_driver._helpers.is_vdisk_defined(name)
@@ -2104,7 +2130,8 @@ class StorwizeSVCFcDriverTestCase(test.TestCase):
             self._def_flags = {'san_ip': 'hostname',
                                'san_login': 'user',
                                'san_password': 'pass',
-                               'storwize_svc_volpool_name': 'openstack',
+                               'storwize_svc_volpool_name':
+                               ['openstack', 'openstack1'],
                                'storwize_svc_flashcopy_timeout': 20,
                                'storwize_svc_flashcopy_rate': 49,
                                'storwize_svc_multipath_enabled': False,
@@ -2118,7 +2145,8 @@ class StorwizeSVCFcDriverTestCase(test.TestCase):
                                'host': 'storwize-svc-test',
                                'wwpns': wwpns,
                                'initiator': initiator}
-            self.sim = StorwizeSVCManagementSimulator('openstack')
+            self.sim = StorwizeSVCManagementSimulator(['openstack',
+                                                      'openstack1'])
 
             self.fc_driver.set_fake_storage(self.sim)
             self.ctxt = context.get_admin_context()
@@ -2142,6 +2170,12 @@ class StorwizeSVCFcDriverTestCase(test.TestCase):
             self._set_flag(k, v)
 
     def _create_volume(self, **kwargs):
+        pool = self._def_flags['storwize_svc_volpool_name'][0]
+        prop = {'host': 'openstack@svc#%s' % pool,
+                'size': 1}
+        for p in prop.keys():
+            if p not in kwargs:
+                kwargs[p] = prop[p]
         vol = testutils.create_volume(self.ctxt, **kwargs)
         self.fc_driver.create_volume(vol)
         return vol
@@ -2151,6 +2185,7 @@ class StorwizeSVCFcDriverTestCase(test.TestCase):
         self.db.volume_destroy(self.ctxt, volume['id'])
 
     def _generate_vol_info(self, vol_name, vol_id):
+        pool = self._def_flags['storwize_svc_volpool_name'][0]
         rand_id = six.text_type(random.randint(10000, 99999))
         if vol_name:
             return {'name': 'snap_volume%s' % rand_id,
@@ -2158,13 +2193,14 @@ class StorwizeSVCFcDriverTestCase(test.TestCase):
                     'id': rand_id,
                     'volume_id': vol_id,
                     'volume_size': 10,
-                    'mdisk_grp_name': 'openstack'}
+                    'mdisk_grp_name': pool}
         else:
             return {'name': 'test_volume%s' % rand_id,
                     'size': 10,
                     'id': '%s' % rand_id,
                     'volume_type_id': None,
-                    'mdisk_grp_name': 'openstack'}
+                    'mdisk_grp_name': pool,
+                    'host': 'openstack@svc#%s' % pool}
 
     def _assert_vol_exists(self, name, exists):
         is_vol_defined = self.fc_driver._helpers.is_vdisk_defined(name)
@@ -2529,7 +2565,8 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
             self._def_flags = {'san_ip': 'hostname',
                                'san_login': 'user',
                                'san_password': 'pass',
-                               'storwize_svc_volpool_name': 'openstack',
+                               'storwize_svc_volpool_name':
+                               ['openstack', 'openstack1'],
                                'storwize_svc_flashcopy_timeout': 20,
                                'storwize_svc_flashcopy_rate': 49,
                                'storwize_svc_allow_tenant_qos': True}
@@ -2542,7 +2579,8 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
                                'host': 'storwize-svc-test',
                                'wwpns': wwpns,
                                'initiator': initiator}
-            self.sim = StorwizeSVCManagementSimulator('openstack')
+            self.sim = StorwizeSVCManagementSimulator(['openstack',
+                                                      'openstack1'])
 
             self.driver.set_fake_storage(self.sim)
             self.ctxt = context.get_admin_context()
@@ -2640,6 +2678,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
         self.driver.do_setup(None)
 
     def _generate_vol_info(self, vol_name, vol_id):
+        pool = self._def_flags['storwize_svc_volpool_name'][0]
         rand_id = six.text_type(random.randint(10000, 99999))
         if vol_name:
             return {'name': 'snap_volume%s' % rand_id,
@@ -2647,15 +2686,22 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
                     'id': rand_id,
                     'volume_id': vol_id,
                     'volume_size': 10,
-                    'mdisk_grp_name': 'openstack'}
+                    'mdisk_grp_name': pool}
         else:
             return {'name': 'test_volume%s' % rand_id,
                     'size': 10,
                     'id': '%s' % rand_id,
                     'volume_type_id': None,
-                    'mdisk_grp_name': 'openstack'}
+                    'mdisk_grp_name': pool,
+                    'host': 'openstack@svc#%s' % pool}
 
     def _create_volume(self, **kwargs):
+        pool = self._def_flags['storwize_svc_volpool_name'][0]
+        prop = {'host': 'openstack@svc#%s' % pool,
+                'size': 1}
+        for p in prop.keys():
+            if p not in kwargs:
+                kwargs[p] = prop[p]
         vol = testutils.create_volume(self.ctxt, **kwargs)
         self.driver.create_volume(vol)
         return vol
@@ -2962,7 +3008,8 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
         attributes = self.driver._helpers.get_vdisk_attributes(volume['name'])
         attr_size = float(attributes['capacity']) / units.Gi  # bytes to GB
         self.assertEqual(attr_size, float(volume['size']))
-        pool = self.driver.configuration.local_conf.storwize_svc_volpool_name
+        pool =\
+            self.driver.configuration.local_conf.storwize_svc_volpool_name[0]
         self.assertEqual(attributes['mdisk_grp_name'], pool)
 
         # Try to create the volume again (should fail)
@@ -3048,10 +3095,12 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
         self.driver.do_setup(None)
 
         rand_id = random.randint(10000, 99999)
+        pool = self._def_flags['storwize_svc_volpool_name'][0]
         volume1 = {'name': u'unicode1_volume%s' % rand_id,
                    'size': 2,
                    'id': 1,
-                   'volume_type_id': None}
+                   'volume_type_id': None,
+                   'host': 'openstack@svc#%s' % pool}
         self.driver.create_volume(volume1)
         self._assert_vol_exists(volume1['name'], True)
 
@@ -3167,15 +3216,39 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
     def test_storwize_svc_get_volume_stats(self):
         self._set_flag('reserved_percentage', 25)
         stats = self.driver.get_volume_stats()
-        self.assertLessEqual(stats['free_capacity_gb'],
-                             stats['total_capacity_gb'])
-        self.assertEqual(25, stats['reserved_percentage'])
-        pool = self.driver.configuration.local_conf.storwize_svc_volpool_name
+        for each_pool in stats['pools']:
+            self.assertIn(each_pool['pool_name'],
+                          self._def_flags['storwize_svc_volpool_name'])
+            self.assertLessEqual(each_pool['free_capacity_gb'],
+                                 each_pool['total_capacity_gb'])
+            self.assertLessEqual(each_pool['allocated_capacity_gb'],
+                                 each_pool['total_capacity_gb'])
+            self.assertEqual(25, each_pool['reserved_percentage'])
         if self.USESIM:
-            expected = 'storwize-svc-sim_' + pool
+            expected = 'storwize-svc-sim'
             self.assertEqual(expected, stats['volume_backend_name'])
-            self.assertAlmostEqual(3328.0, stats['total_capacity_gb'])
-            self.assertAlmostEqual(3287.5, stats['free_capacity_gb'])
+            for each_pool in stats['pools']:
+                self.assertIn(each_pool['pool_name'],
+                              self._def_flags['storwize_svc_volpool_name'])
+                self.assertAlmostEqual(3328.0, each_pool['total_capacity_gb'])
+                self.assertAlmostEqual(3287.5, each_pool['free_capacity_gb'])
+                self.assertAlmostEqual(25.0,
+                                       each_pool['allocated_capacity_gb'])
+
+    def test_get_pool(self):
+        ctxt = testutils.get_test_admin_context()
+        type_ref = volume_types.create(ctxt, 'testtype', None)
+        volume = self._generate_vol_info(None, None)
+        type_id = type_ref['id']
+        type_ref = volume_types.get_volume_type(ctxt, type_id)
+        volume['volume_type_id'] = type_id
+        volume['volume_type'] = type_ref
+        self.driver.create_volume(volume)
+        self.assertEqual(volume['mdisk_grp_name'],
+                         self.driver.get_pool(volume))
+
+        self.driver.delete_volume(volume)
+        volume_types.destroy(ctxt, type_ref['id'])
 
     def test_storwize_svc_extend_volume(self):
         volume = self._create_volume()
@@ -3268,7 +3341,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
         loc = ('StorwizeSVCDriver:' + self.driver._state['system_id'] +
                ':openstack2')
         cap = {'location_info': loc, 'extent_size': '256'}
-        host = {'host': 'foo', 'capabilities': cap}
+        host = {'host': 'openstack@svc#openstack2', 'capabilities': cap}
         ctxt = context.get_admin_context()
         volume = self._create_volume()
         volume['volume_type_id'] = None
@@ -3386,7 +3459,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
                ':openstack')
         cap = {'location_info': loc, 'extent_size': '128'}
         self.driver._stats = {'location_info': loc}
-        host = {'host': 'foo', 'capabilities': cap}
+        host = {'host': 'openstack@svc#openstack', 'capabilities': cap}
         ctxt = context.get_admin_context()
 
         key_specs_old = {'easytier': False, 'warning': 2, 'autoexpand': True}
@@ -3400,7 +3473,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
         volume = self._generate_vol_info(None, None)
         old_type = volume_types.get_volume_type(ctxt, old_type_ref['id'])
         volume['volume_type'] = old_type
-        volume['host'] = host
+        volume['host'] = 'openstack@svc#openstack'
         new_type = volume_types.get_volume_type(ctxt, new_type_ref['id'])
 
         self.driver.create_volume(volume)
@@ -3476,7 +3549,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
                ':openstack')
         cap = {'location_info': loc, 'extent_size': '128'}
         self.driver._stats = {'location_info': loc}
-        host = {'host': 'foo', 'capabilities': cap}
+        host = {'host': 'openstack@svc#openstack', 'capabilities': cap}
         ctxt = context.get_admin_context()
 
         key_specs_old = {'iogrp': 0}
@@ -3490,7 +3563,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
         volume = self._generate_vol_info(None, None)
         old_type = volume_types.get_volume_type(ctxt, old_type_ref['id'])
         volume['volume_type'] = old_type
-        volume['host'] = host
+        volume['host'] = 'openstack@svc#openstack'
         new_type = volume_types.get_volume_type(ctxt, new_type_ref['id'])
 
         self.driver.create_volume(volume)
@@ -3511,7 +3584,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
                ':openstack')
         cap = {'location_info': loc, 'extent_size': '128'}
         self.driver._stats = {'location_info': loc}
-        host = {'host': 'foo', 'capabilities': cap}
+        host = {'host': 'openstack@svc#openstack', 'capabilities': cap}
         ctxt = context.get_admin_context()
 
         key_specs_old = {'compression': True, 'iogrp': 0}
@@ -3525,7 +3598,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
         volume = self._generate_vol_info(None, None)
         old_type = volume_types.get_volume_type(ctxt, old_type_ref['id'])
         volume['volume_type'] = old_type
-        volume['host'] = host
+        volume['host'] = 'openstack@svc#openstack'
         new_type = volume_types.get_volume_type(ctxt, new_type_ref['id'])
 
         self.driver.create_volume(volume)
@@ -3630,7 +3703,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
         ctxt = testutils.get_test_admin_context()
         volume = self._create_volume()
         driver = self.driver
-        dest_pool = self.driver.configuration.storwize_svc_volpool_name
+        dest_pool = volume_utils.extract_host(volume['host'], 'pool')
         new_ops = driver._helpers.add_vdisk_copy(volume['name'], dest_pool,
                                                  None, self.driver._state,
                                                  self.driver.configuration)
@@ -3806,7 +3879,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
                ':openstack')
         cap = {'location_info': loc, 'extent_size': '128'}
         self.driver._stats = {'location_info': loc}
-        host = {'host': 'foo', 'capabilities': cap}
+        host = {'host': 'openstack@svc#openstack', 'capabilities': cap}
         ctxt = context.get_admin_context()
 
         disable_type = self._create_replication_volume_type(False)
@@ -3817,7 +3890,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
                                                       enable_type['id'])
 
         volume = self._generate_vol_info(None, None)
-        volume['host'] = host
+        volume['host'] = 'openstack@svc#openstack'
         volume['volume_type_id'] = disable_type['id']
         volume['volume_type'] = disable_type
         volume['replication_status'] = None
@@ -3842,7 +3915,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
                ':openstack')
         cap = {'location_info': loc, 'extent_size': '128'}
         self.driver._stats = {'location_info': loc}
-        host = {'host': 'foo', 'capabilities': cap}
+        host = {'host': 'openstack@svc#openstack', 'capabilities': cap}
         ctxt = context.get_admin_context()
 
         volume = self._generate_vol_info(None, None)
@@ -3850,6 +3923,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
         volume['volume_type'] = None
         volume['replication_status'] = "disabled"
         volume['replication_extended_status'] = None
+        volume['host'] = 'openstack@svc#openstack'
 
         # Create volume which is not volume replication
         model_update = self.driver.create_volume(volume)
@@ -3990,14 +4064,16 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
         cg_type = self._create_consistency_group_volume_type()
         self.ctxt.user_id = 'fake_user_id'
         self.ctxt.project_id = 'fake_project_id'
-
+        pool = self._def_flags['storwize_svc_volpool_name'][0]
         # Create cg in db
         cg = self._create_consistencygroup_in_db(volume_type_id=cg_type['id'])
         # Create volumes in db
         testutils.create_volume(self.ctxt, volume_type_id=cg_type['id'],
-                                consistencygroup_id=cg['id'])
+                                consistencygroup_id=cg['id'],
+                                host='openstack@svc#%s' % pool)
         testutils.create_volume(self.ctxt, volume_type_id=cg_type['id'],
-                                consistencygroup_id=cg['id'])
+                                consistencygroup_id=cg['id'],
+                                host='openstack@svc#%s' % pool)
         volumes = (
             self.db.volume_get_all_by_group(self.ctxt.elevated(), cg['id']))
 
@@ -4015,6 +4091,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
         cgsnapshot, snapshots = self._create_cgsnapshot(source_cg['id'])
 
         # Create cg from source cg
+
         model_update, volumes_model_update = (
             self.driver.create_consistencygroup_from_src(self.ctxt,
                                                          cg,
@@ -4278,7 +4355,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
 
         new_volume['volume_type_id'] = type_thick_ref['id']
         no_exist_pool = 'i-dont-exist-%s' % random.randint(10000, 99999)
-        self._set_flag('storwize_svc_volpool_name', no_exist_pool)
+        new_volume['host'] = 'openstack@svc#%s' % no_exist_pool
         self.assertRaises(exception.ManageExistingVolumeTypeMismatch,
                           self.driver.manage_existing, new_volume, ref)
 
@@ -4596,13 +4673,15 @@ class StorwizeSVCReplicationMirrorTestCase(test.TestCase):
             self.svc_driver.replication_factory(self.rep_type, fake_target))
         self.ctxt = context.get_admin_context()
         rand_id = six.text_type(uuid.uuid4())
+        pool = self.svc_driver.configuration.storwize_svc_volpool_name[0]
         self.volume = {'name': 'volume-%s' % rand_id,
                        'size': 10, 'id': '%s' % rand_id,
                        'volume_type_id': None,
                        'mdisk_grp_name': 'openstack',
                        'replication_status': 'disabled',
                        'replication_extended_status': None,
-                       'volume_metadata': None}
+                       'volume_metadata': None,
+                       'host': 'openstack@svc#%s' % pool}
         spec = {'replication_enabled': '<is> True',
                 'replication_type': extra_spec_rep_type}
         type_ref = volume_types.create(self.ctxt, "replication", spec)
@@ -4673,13 +4752,15 @@ class StorwizeSVCReplicationMirrorTestCase(test.TestCase):
         get_vdisk_params.return_value = {'replication': None,
                                          'qos': None}
         rand_id = six.text_type(random.randint(10000, 99999))
+        pool = self.svc_driver.configuration.storwize_svc_volpool_name[0]
         target_volume = {'name': 'test_volume%s' % rand_id,
                          'size': 10, 'id': '%s' % rand_id,
                          'volume_type_id': None,
                          'mdisk_grp_name': 'openstack',
                          'replication_status': 'disabled',
                          'replication_extended_status': None,
-                         'volume_metadata': None}
+                         'volume_metadata': None,
+                         'host': 'openstack@svc#%s' % pool}
         target_volume['volume_type_id'] = self.replication_type['id']
         target_volume['volume_type'] = self.replication_type
         model_update = self.svc_driver.create_cloned_volume(
index 98fc51e828bf1bd43889cf674a9d46edf2913269..68f51877585bac37ea359bc1cd37d14542936949 100644 (file)
@@ -49,9 +49,10 @@ DEFAULT_TIMEOUT = 15
 LOG = logging.getLogger(__name__)
 
 storwize_svc_opts = [
-    cfg.StrOpt('storwize_svc_volpool_name',
-               default='volpool',
-               help='Storage system storage pool for volumes'),
+    cfg.ListOpt('storwize_svc_volpool_name',
+                default=['volpool'],
+                help='Comma separated list of storage system storage '
+                     'pools for volumes.'),
     cfg.IntOpt('storwize_svc_vol_rsize',
                default=2,
                min=-1, max=100,
@@ -1286,11 +1287,12 @@ class StorwizeHelpers(object):
             for source, target in zip(sources, targets):
                 opts = self.get_vdisk_params(config, state,
                                              source['volume_type_id'])
+                pool = utils.extract_host(target['host'], 'pool')
                 self.create_flashcopy_to_consistgrp(source['name'],
                                                     target['name'],
                                                     fc_consistgrp,
                                                     config, opts,
-                                                    True)
+                                                    True, pool=pool)
             self.prepare_fc_consistgrp(fc_consistgrp, timeout)
             self.start_fc_consistgrp(fc_consistgrp)
             self.delete_fc_consistgrp(fc_consistgrp)
@@ -1360,7 +1362,7 @@ class StorwizeHelpers(object):
         src_size = src_attrs['capacity']
         # In case we need to use a specific pool
         if not pool:
-            pool = config.storwize_svc_volpool_name
+            pool = src_attrs['mdisk_grp_name']
         self.create_vdisk(target, src_size, 'b', pool, opts)
 
         self.ssh.mkfcmap(source, target, full_copy,
@@ -1547,7 +1549,7 @@ class StorwizeHelpers(object):
         src_size = src_attrs['capacity']
         # In case we need to use a specific pool
         if not pool:
-            pool = config.storwize_svc_volpool_name
+            pool = src_attrs['mdisk_grp_name']
         self.create_vdisk(tgt, src_size, 'b', pool, opts)
         timeout = config.storwize_svc_flashcopy_timeout
         try:
@@ -1891,12 +1893,7 @@ class StorwizeSVCCommonDriver(san.SanDriver,
         self.replication = storwize_rep.StorwizeSVCReplication.factory(self)
 
         # Validate that the pool exists
-        pool = self.configuration.storwize_svc_volpool_name
-        try:
-            self._helpers.get_pool_attrs(pool)
-        except exception.VolumeBackendAPIException:
-            msg = _('Failed getting details for pool %s.') % pool
-            raise exception.InvalidInput(reason=msg)
+        self._validate_pools_exist()
 
         # Check if compression is supported
         self._state['compression_enabled'] = (self._helpers.
@@ -1933,6 +1930,16 @@ class StorwizeSVCCommonDriver(san.SanDriver,
         # v2 replication setup
         self._do_replication_setup()
 
+    def _validate_pools_exist(self):
+        # Validate that the pool exists
+        pools = self.configuration.storwize_svc_volpool_name
+        for pool in pools:
+            try:
+                self._helpers.get_pool_attrs(pool)
+            except exception.VolumeBackendAPIException:
+                msg = _('Failed getting details for pool %s.') % pool
+                raise exception.InvalidInput(reason=msg)
+
     def check_for_setup_error(self):
         """Ensure that the flags are set properly."""
         LOG.debug('enter: check_for_setup_error')
@@ -1995,7 +2002,7 @@ class StorwizeSVCCommonDriver(san.SanDriver,
         opts = self._get_vdisk_params(volume['volume_type_id'],
                                       volume_metadata=
                                       volume.get('volume_metadata'))
-        pool = self.configuration.storwize_svc_volpool_name
+        pool = utils.extract_host(volume['host'], 'pool')
         self._helpers.create_vdisk(volume['name'], str(volume['size']),
                                    'gb', pool, opts)
         if opts['qos']:
@@ -2041,10 +2048,11 @@ class StorwizeSVCCommonDriver(san.SanDriver,
             msg = (_('create_snapshot: get source volume failed.'))
             LOG.error(msg)
             raise exception.VolumeDriverException(message=msg)
+        pool = utils.extract_host(source_vol['host'], 'pool')
         opts = self._get_vdisk_params(source_vol['volume_type_id'])
         self._helpers.create_copy(snapshot['volume_name'], snapshot['name'],
                                   snapshot['volume_id'], self.configuration,
-                                  opts, False)
+                                  opts, False, pool=pool)
 
     def delete_snapshot(self, snapshot):
         self._helpers.delete_vdisk(snapshot['name'], False)
@@ -2059,9 +2067,10 @@ class StorwizeSVCCommonDriver(san.SanDriver,
         opts = self._get_vdisk_params(volume['volume_type_id'],
                                       volume_metadata=
                                       volume.get('volume_metadata'))
+        pool = utils.extract_host(volume['host'], 'pool')
         self._helpers.create_copy(snapshot['name'], volume['name'],
                                   snapshot['id'], self.configuration,
-                                  opts, True)
+                                  opts, True, pool=pool)
         if opts['qos']:
             self._helpers.add_vdisk_qos(volume['name'], opts['qos'])
 
@@ -2089,9 +2098,10 @@ class StorwizeSVCCommonDriver(san.SanDriver,
         opts = self._get_vdisk_params(tgt_volume['volume_type_id'],
                                       volume_metadata=
                                       tgt_volume.get('volume_metadata'))
+        pool = utils.extract_host(tgt_volume['host'], 'pool')
         self._helpers.create_copy(src_volume['name'], tgt_volume['name'],
                                   src_volume['id'], self.configuration,
-                                  opts, True)
+                                  opts, True, pool=pool)
         if opts['qos']:
             self._helpers.add_vdisk_qos(tgt_volume['name'], opts['qos'])
 
@@ -2525,8 +2535,8 @@ class StorwizeSVCCommonDriver(san.SanDriver,
                 elif key in no_copy_keys:
                     vdisk_changes.append(key)
 
-        dest_location = host['capabilities'].get('location_info')
-        if self._stats['location_info'] != dest_location:
+        if (utils.extract_host(volume['host'], 'pool') !=
+                utils.extract_host(host['host'], 'pool')):
             need_copy = True
 
         if need_copy:
@@ -2671,9 +2681,8 @@ class StorwizeSVCCommonDriver(san.SanDriver,
                        {'vdisk_iogrp': vdisk['IO_group_name'],
                         'opt_iogrp': opts['iogrp']})
                 raise exception.ManageExistingVolumeTypeMismatch(reason=msg)
-
-        if (vdisk['mdisk_grp_name'] !=
-                self.configuration.storwize_svc_volpool_name):
+        pool = utils.extract_host(volume['host'], 'pool')
+        if vdisk['mdisk_grp_name'] != pool:
             msg = (_("Failed to manage existing volume due to the "
                      "pool of the volume to be managed does not "
                      "match the backend pool. Pool of the "
@@ -2843,6 +2852,17 @@ class StorwizeSVCCommonDriver(san.SanDriver,
 
         return model_update, snapshots_model
 
+    def get_pool(self, volume):
+        attr = self._helpers.get_vdisk_attributes(volume['name'])
+
+        if attr is None:
+            msg = (_('get_pool: Failed to get attributes for volume '
+                     '%s') % volume['name'])
+            LOG.error(msg)
+            raise exception.VolumeDriverException(message=msg)
+
+        return attr['mdisk_grp_name']
+
     def _update_volume_stats(self):
         """Retrieve stats info from volume group."""
 
@@ -2852,46 +2872,63 @@ class StorwizeSVCCommonDriver(san.SanDriver,
         data['vendor_name'] = 'IBM'
         data['driver_version'] = self.VERSION
         data['storage_protocol'] = self.protocol
+        data['pools'] = []
 
-        data['total_capacity_gb'] = 0  # To be overwritten
-        data['free_capacity_gb'] = 0   # To be overwritten
-        data['reserved_percentage'] = self.configuration.reserved_percentage
         data['multiattach'] = (self.configuration.
                                storwize_svc_multihostmap_enabled)
-        data['QoS_support'] = True
-        data['consistencygroup_support'] = True
 
-        pool = self.configuration.storwize_svc_volpool_name
         backend_name = self.configuration.safe_get('volume_backend_name')
-        if not backend_name:
-            backend_name = '%s_%s' % (self._state['system_name'], pool)
-        data['volume_backend_name'] = backend_name
-
-        attributes = self._helpers.get_pool_attrs(pool)
-        if not attributes:
-            LOG.error(_LE('Could not get pool data from the storage.'))
-            exception_message = (_('_update_volume_stats: '
-                                   'Could not get storage pool data.'))
-            raise exception.VolumeBackendAPIException(data=exception_message)
-
-        data['total_capacity_gb'] = (float(attributes['capacity']) /
-                                     units.Gi)
-        data['free_capacity_gb'] = (float(attributes['free_capacity']) /
-                                    units.Gi)
-        data['easytier_support'] = attributes['easy_tier'] in ['on', 'auto']
-        data['compression_support'] = self._state['compression_enabled']
-        data['location_info'] = ('StorwizeSVCDriver:%(sys_id)s:%(pool)s' %
+        data['volume_backend_name'] = (backend_name or
+                                       self._state['system_name'])
+
+        data['pools'] = [self._build_pool_stats(pool)
+                         for pool in
+                         self.configuration.storwize_svc_volpool_name]
+        self._stats = data
+
+    def _build_pool_stats(self, pool):
+        """Build pool status"""
+        QoS_support = True
+        pool_stats = {}
+        try:
+            pool_data = self._helpers.get_pool_attrs(pool)
+            if pool_data:
+                easy_tier = pool_data['easy_tier'] in ['on', 'auto']
+                total_capacity_gb = float(pool_data['capacity']) / units.Gi
+                free_capacity_gb = float(pool_data['free_capacity']) / units.Gi
+                allocated_capacity_gb = (float(pool_data['used_capacity']) /
+                                         units.Gi)
+                location_info = ('StorwizeSVCDriver:%(sys_id)s:%(pool)s' %
                                  {'sys_id': self._state['system_id'],
-                                  'pool': pool})
+                                  'pool': pool_data['name']})
+                pool_stats = {
+                    'pool_name': pool_data['name'],
+                    'total_capacity_gb': total_capacity_gb,
+                    'free_capacity_gb': free_capacity_gb,
+                    'allocated_capacity_gb': allocated_capacity_gb,
+                    'easytier_support': easy_tier,
+                    'compression_support': self._state['compression_enabled'],
+                    'reserved_percentage':
+                        self.configuration.reserved_percentage,
+                    'QoS_support': QoS_support,
+                    'consistencygroup_support': True,
+                    'location_info': location_info,
+                    'easytier_support': easy_tier
+                }
+            if self._replication_enabled:
+                pool_stats.update({
+                    'replication_enabled': self._replication_enabled,
+                    'replication_type': self._supported_replication_types,
+                    'replication_count': len(self._replication_targets)
+                })
+            elif self.replication:
+                pool_stats.update(self.replication.get_replication_info())
 
-        if self._replication_enabled:
-            data['replication_enabled'] = self._replication_enabled
-            data['replication_type'] = self._supported_replication_types
-            data['replication_count'] = len(self._replication_targets)
-        elif self.replication:
-            data.update(self.replication.get_replication_info())
+        except exception.VolumeBackendAPIException:
+            msg = _('Failed getting details for pool %s.') % pool
+            raise exception.VolumeBackendAPIException(data=msg)
 
-        self._stats = data
+        return pool_stats
 
     def _manage_input_check(self, ref):
         """Verify the input of manage function."""
index 762c98cc14bedaa9e96f08e85c476277ac446900..10f05446042054bd852e436af10cdba5438a6eac 100644 (file)
@@ -79,9 +79,10 @@ class StorwizeSVCFCDriver(storwize_common.StorwizeSVCCommonDriver):
     1.3.3 - Update driver to use ABC metaclasses
     2.0 - Code refactor, split init file and placed shared methods for
           FC and iSCSI within the StorwizeSVCCommonDriver class
+    2.0.1 - Added support for multiple pools with model update
     """
 
-    VERSION = "2.0"
+    VERSION = "2.0.1"
 
     def __init__(self, *args, **kwargs):
         super(StorwizeSVCFCDriver, self).__init__(*args, **kwargs)
index 56efbab742f3d146974004d33992752475564442..dbea147267d70d08f20665bd213687cbdfa088d3 100644 (file)
@@ -79,9 +79,10 @@ class StorwizeSVCISCSIDriver(storwize_common.StorwizeSVCCommonDriver):
     1.3.3 - Update driver to use ABC metaclasses
     2.0 - Code refactor, split init file and placed shared methods for
           FC and iSCSI within the StorwizeSVCCommonDriver class
+    2.0.1 - Added support for multiple pools with model update
     """
 
-    VERSION = "2.0"
+    VERSION = "2.0.1"
 
     def __init__(self, *args, **kwargs):
         super(StorwizeSVCISCSIDriver, self).__init__(*args, **kwargs)
diff --git a/releasenotes/notes/storwize-pool-aware-support-7a40c9934642b202.yaml b/releasenotes/notes/storwize-pool-aware-support-7a40c9934642b202.yaml
new file mode 100644 (file)
index 0000000..316dd8f
--- /dev/null
@@ -0,0 +1,3 @@
+---
+features:
+  - Add multiple pools support to Storwize SVC driver.