]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Refactor huawei Dorado array iSCSI driver
authorzhangchao010 <zhangchao010@huawei.com>
Sat, 31 Aug 2013 02:23:35 +0000 (10:23 +0800)
committerGerrit Code Review <review@openstack.org>
Tue, 3 Sep 2013 02:53:50 +0000 (02:53 +0000)
This is the second patch, changes as follows:
1.Add ISCSIDriver for Dorado arrays. The ISCSIDriver inherit from T.
1.Add a common class DoradoCommon for both FC and iSCSI drivers. The common class
inherit from T common for they have many common functions.
2.Add unit test for Dorado drivers.

Change-Id: I7ff2cc1e0d058b7a3d9e55644769ec74075f962f

cinder/tests/test_huawei_t_dorado.py
cinder/volume/drivers/huawei/__init__.py
cinder/volume/drivers/huawei/huawei_dorado.py [new file with mode: 0644]
cinder/volume/drivers/huawei/ssh_common.py

index fdd35289d9b521010d63d125e89dccb045e4430a..6903b615ba2c0571ec24c03a9c0c5e5b5fffa8f7 100644 (file)
@@ -161,6 +161,10 @@ class FakeChannel():
     def __init__(self):
         if Curr_test[0] == 'T':
             self.simu = HuaweiTCLIResSimulator()
+        elif Curr_test[0] == 'Dorado5100':
+            self.simu = HuaweiDorado5100CLIResSimulator()
+        else:
+            self.simu = HuaweiDorado2100G2CLIResSimulator()
 
     def resize_pty(self, width=80, height=24):
         pass
@@ -830,6 +834,196 @@ Multipath Type
         return out
 
 
+class HuaweiDorado5100CLIResSimulator(HuaweiTCLIResSimulator):
+    def cli_showsys(self, params):
+        out = """/>showsys
+=============================================================
+                                System Information
+-------------------------------------------------------------
+  System Name           | SN_Dorado5100
+  Device Type           | Oceanstor Dorado5100
+  Current System Mode   | Double Controllers Normal
+  Mirroring Link Status | Link Up
+  Location              |
+  Time                  | 2013-01-01 01:01:01
+  Product Version       | V100R001C00
+=============================================================
+"""
+        return out
+
+    def cli_showlun(self, params):
+        if '-lun' not in params:
+            if LUN_INFO['ID'] is None:
+                out = 'command operates successfully, but no information.'
+            elif CLONED_LUN_INFO['ID'] is None:
+                out = """/>showlun
+===========================================================================
+                           LUN Information
+---------------------------------------------------------------------------
+  ID   RAIDgroup ID  Status   Controller  Visible Capacity(MB)   LUN Name..\
+  Strip Unit Size(KB)   Lun Type
+---------------------------------------------------------------------------
+  %s      %s       Normal       %s      %s       %s       64       THICK
+===========================================================================
+""" % (LUN_INFO['ID'], LUN_INFO['RAID Group ID'],
+       LUN_INFO['Owner Controller'], str(int(LUN_INFO['Size']) * 1024),
+       LUN_INFO['Name'])
+            else:
+                out = """/>showlun
+===========================================================================
+                           LUN Information
+---------------------------------------------------------------------------
+  ID   RAIDgroup ID   Status   Controller   Visible Capacity(MB)   LUN Name \
+  Strip Unit Size(KB)   Lun Type
+---------------------------------------------------------------------------
+  %s      %s       Normal      %s      %s       %s        64       THICK
+  %s      %s       Norma       %s      %s       %s        64       THICK
+===========================================================================
+""" % (LUN_INFO['ID'], LUN_INFO['RAID Group ID'], LUN_INFO['Owner Controller'],
+       str(int(LUN_INFO['Size']) * 1024), LUN_INFO['Name'],
+       CLONED_LUN_INFO['ID'], CLONED_LUN_INFO['RAID Group ID'],
+       CLONED_LUN_INFO['Owner Controller'],
+       str(int(CLONED_LUN_INFO['Size']) * 1024),
+       CLONED_LUN_INFO['Name'])
+        elif params[params.index('-lun') + 1] in VOLUME_SNAP_ID.values():
+            out = """/>showlun
+================================================
+                 LUN Information
+------------------------------------------------
+  ID                     |  %s
+  Name                   |  %s
+  LUN WWN                |  --
+  Visible Capacity       |  %s
+  RAID GROUP ID          |  %s
+  Owning Controller      |  %s
+  Workong Controller     |  %s
+  Lun Type               |  %s
+  SnapShot ID            |  %s
+  LunCopy ID             |  %s
+================================================
+""" % ((LUN_INFO['ID'], LUN_INFO['Name'], LUN_INFO['Visible Capacity'],
+        LUN_INFO['RAID Group ID'], LUN_INFO['Owner Controller'],
+        LUN_INFO['Worker Controller'], LUN_INFO['Lun Type'],
+        LUN_INFO['SnapShot ID'], LUN_INFO['LunCopy ID'])
+       if params[params.index('-lun')] == VOLUME_SNAP_ID['vol'] else
+       (CLONED_LUN_INFO['ID'], CLONED_LUN_INFO['Name'],
+        CLONED_LUN_INFO['Visible Capacity'], CLONED_LUN_INFO['RAID Group ID'],
+        CLONED_LUN_INFO['Owner Controller'],
+        CLONED_LUN_INFO['Worker Controller'],
+        CLONED_LUN_INFO['Lun Type'], CLONED_LUN_INFO['SnapShot ID'],
+        CLONED_LUN_INFO['LunCopy ID']))
+        else:
+            out = 'ERROR: The object does not exist.'
+        return out
+
+
+class HuaweiDorado2100G2CLIResSimulator(HuaweiTCLIResSimulator):
+    def cli_showsys(self, params):
+        out = """/>showsys
+==========================================================================
+                                System Information
+--------------------------------------------------------------------------
+  System Name           | SN_Dorado2100_G2
+  Device Type           | Oceanstor Dorado2100 G2
+  Current System Mode   | Double Controllers Normal
+  Mirroring Link Status | Link Up
+  Location              |
+  Time                  | 2013-01-01 01:01:01
+  Product Version       | V100R001C00
+===========================================================================
+"""
+        return out
+
+    def cli_createlun(self, params):
+        lun_type = ('THIN' if params[params.index('-type') + 1] == '2' else
+                    'THICK')
+        if LUN_INFO['ID'] is None:
+            LUN_INFO['Name'] = self._name_translate(FAKE_VOLUME['name'])
+            LUN_INFO['ID'] = VOLUME_SNAP_ID['vol']
+            LUN_INFO['Size'] = FAKE_VOLUME['size']
+            LUN_INFO['Lun Type'] = lun_type
+            LUN_INFO['Owner Controller'] = 'A'
+            LUN_INFO['Worker Controller'] = 'A'
+            LUN_INFO['RAID Group ID'] = POOL_SETTING['ID']
+            FAKE_VOLUME['provider_location'] = LUN_INFO['ID']
+        else:
+            CLONED_LUN_INFO['Name'] = \
+                self._name_translate(FAKE_CLONED_VOLUME['name'])
+            CLONED_LUN_INFO['ID'] = VOLUME_SNAP_ID['vol_copy']
+            CLONED_LUN_INFO['Size'] = FAKE_CLONED_VOLUME['size']
+            CLONED_LUN_INFO['Lun Type'] = lun_type
+            CLONED_LUN_INFO['Owner Controller'] = 'A'
+            CLONED_LUN_INFO['Worker Controller'] = 'A'
+            CLONED_LUN_INFO['RAID Group ID'] = POOL_SETTING['ID']
+            CLONED_LUN_INFO['provider_location'] = CLONED_LUN_INFO['ID']
+            FAKE_CLONED_VOLUME['provider_location'] = CLONED_LUN_INFO['ID']
+        out = 'command operates successfully'
+        return out
+
+    def cli_showlun(self, params):
+        if '-lun' not in params:
+            if LUN_INFO['ID'] is None:
+                out = 'command operates successfully, but no information.'
+            elif CLONED_LUN_INFO['ID'] is None:
+                out = """/>showlun
+===========================================================================
+                           LUN Information
+---------------------------------------------------------------------------
+  ID   Status   Controller  Visible Capacity(MB)   LUN Name  Lun Type
+---------------------------------------------------------------------------
+  %s   Normal   %s          %s                     %s        THICK
+===========================================================================
+""" % (LUN_INFO['ID'], LUN_INFO['Owner Controller'],
+       str(int(LUN_INFO['Size']) * 1024), LUN_INFO['Name'])
+            else:
+                out = """/>showlun
+===========================================================================
+                           LUN Information
+---------------------------------------------------------------------------
+  ID   Status   Controller  Visible Capacity(MB)   LUN Name  Lun Type
+---------------------------------------------------------------------------
+  %s   Normal   %s          %s                     %s         THICK
+  %s   Normal   %s          %s                     %s         THICK
+===========================================================================
+""" % (LUN_INFO['ID'], LUN_INFO['Owner Controller'],
+       str(int(LUN_INFO['Size']) * 1024), LUN_INFO['Name'],
+       CLONED_LUN_INFO['ID'], CLONED_LUN_INFO['Owner Controller'],
+       str(int(CLONED_LUN_INFO['Size']) * 1024), CLONED_LUN_INFO['Name'])
+
+        elif params[params.index('-lun') + 1] in VOLUME_SNAP_ID.values():
+            out = """/>showlun
+================================================
+                 LUN Information
+------------------------------------------------
+  ID                     |  %s
+  Name                   |  %s
+  LUN WWN                |  --
+  Visible Capacity       |  %s
+  RAID GROUP ID          |  %s
+  Owning Controller      |  %s
+  Workong Controller     |  %s
+  Lun Type               |  %s
+  SnapShot ID            |  %s
+  LunCopy ID             |  %s
+================================================
+""" % ((LUN_INFO['ID'], LUN_INFO['Name'], LUN_INFO['Visible Capacity'],
+        LUN_INFO['RAID Group ID'], LUN_INFO['Owner Controller'],
+        LUN_INFO['Worker Controller'], LUN_INFO['Lun Type'],
+        LUN_INFO['SnapShot ID'], LUN_INFO['LunCopy ID'])
+       if params[params.index('-lun')] == VOLUME_SNAP_ID['vol'] else
+       (CLONED_LUN_INFO['ID'], CLONED_LUN_INFO['Name'],
+        CLONED_LUN_INFO['Visible Capacity'], CLONED_LUN_INFO['RAID Group ID'],
+        CLONED_LUN_INFO['Owner Controller'],
+        CLONED_LUN_INFO['Worker Controller'],
+        CLONED_LUN_INFO['Lun Type'], CLONED_LUN_INFO['SnapShot ID'],
+        CLONED_LUN_INFO['LunCopy ID']))
+
+        else:
+            out = 'ERROR: The object does not exist.'
+
+        return out
+
+
 class HuaweiTISCSIDriverTestCase(test.TestCase):
     def __init__(self, *args, **kwargs):
         super(HuaweiTISCSIDriverTestCase, self).__init__(*args, **kwargs)
@@ -1199,6 +1393,81 @@ class HuaweiTISCSIDriverTestCase(test.TestCase):
         self.assertEqual(stats['storage_protocol'], 'iSCSI')
 
 
+class HuaweiDorado5100ISCSIDriverTestCase(HuaweiTISCSIDriverTestCase):
+    def __init__(self, *args, **kwargs):
+        super(HuaweiDorado5100ISCSIDriverTestCase, self).__init__(*args,
+                                                                  **kwargs)
+
+    def setUp(self):
+        super(HuaweiDorado5100ISCSIDriverTestCase, self).setUp()
+
+    def _init_driver(self):
+        Curr_test[0] = 'Dorado5100'
+        modify_conf(self.fake_conf_file, 'Storage/Product', 'Dorado')
+        self.driver = HuaweiVolumeDriver(configuration=self.configuration)
+        self.driver.do_setup(None)
+
+    def test_create_delete_cloned_volume(self):
+        self.assertRaises(exception.VolumeBackendAPIException,
+                          self.driver.create_cloned_volume,
+                          FAKE_CLONED_VOLUME, FAKE_VOLUME)
+
+    def test_create_delete_snapshot_volume(self):
+        self.assertRaises(exception.VolumeBackendAPIException,
+                          self.driver.create_volume_from_snapshot,
+                          FAKE_CLONED_VOLUME, FAKE_SNAPSHOT)
+
+    def test_volume_type(self):
+        pass
+
+
+class HuaweiDorado2100G2ISCSIDriverTestCase(HuaweiTISCSIDriverTestCase):
+    def __init__(self, *args, **kwargs):
+        super(HuaweiDorado2100G2ISCSIDriverTestCase, self).__init__(*args,
+                                                                    **kwargs)
+
+    def setUp(self):
+        super(HuaweiDorado2100G2ISCSIDriverTestCase, self).setUp()
+
+    def _init_driver(self):
+        Curr_test[0] = 'Dorado2100G2'
+        modify_conf(self.fake_conf_file, 'Storage/Product', 'Dorado')
+        self.driver = HuaweiVolumeDriver(configuration=self.configuration)
+        self.driver.do_setup(None)
+
+    def test_conf_invalid(self):
+        pass
+
+    def test_create_delete_cloned_volume(self):
+        self.assertRaises(exception.VolumeBackendAPIException,
+                          self.driver.create_cloned_volume,
+                          FAKE_CLONED_VOLUME, FAKE_VOLUME)
+
+    def test_create_delete_snapshot(self):
+        self.assertRaises(exception.VolumeBackendAPIException,
+                          self.driver.create_snapshot, FAKE_SNAPSHOT)
+
+    def test_create_delete_snapshot_volume(self):
+        self.assertRaises(exception.VolumeBackendAPIException,
+                          self.driver.create_volume_from_snapshot,
+                          FAKE_CLONED_VOLUME, FAKE_SNAPSHOT)
+
+    def test_initialize_connection(self):
+        self.driver.create_volume(FAKE_VOLUME)
+        ret = self.driver.initialize_connection(FAKE_VOLUME, FAKE_CONNECTOR)
+        iscsi_propers = ret['data']
+        self.assertEquals(iscsi_propers['target_iqn'],
+                          INITIATOR_SETTING['TargetIQN-form'])
+        self.assertEquals(iscsi_propers['target_portal'],
+                          INITIATOR_SETTING['Initiator TargetIP'] + ':3260')
+        self.assertEqual(MAP_INFO["DEV LUN ID"], LUN_INFO['ID'])
+        self.assertEqual(MAP_INFO["INI Port Info"],
+                         FAKE_CONNECTOR['initiator'])
+        self.driver.terminate_connection(FAKE_VOLUME, FAKE_CONNECTOR)
+        self.driver.delete_volume(FAKE_VOLUME)
+        self.assertEqual(LUN_INFO['ID'], None)
+
+
 class SSHMethodTestCase(test.TestCase):
     def __init__(self, *args, **kwargs):
         super(SSHMethodTestCase, self).__init__(*args, **kwargs)
index d1673f7372022c77f0bb0e547e624628bd3470fa..732db1d753d6842b1385eccbd2973edd9efc36c0 100644 (file)
@@ -27,6 +27,7 @@ from cinder import exception
 from cinder.openstack.common import log as logging
 from cinder.volume.configuration import Configuration
 from cinder.volume import driver
+from cinder.volume.drivers.huawei import huawei_dorado
 from cinder.volume.drivers.huawei import huawei_t
 from cinder.volume.drivers.huawei import ssh_common
 
@@ -46,7 +47,7 @@ class HuaweiVolumeDriver(object):
 
     def __init__(self, *args, **kwargs):
         super(HuaweiVolumeDriver, self).__init__()
-        self._product = {'T': huawei_t}
+        self._product = {'T': huawei_t, 'Dorado': huawei_dorado}
         self._protocol = {'iSCSI': 'ISCSIDriver'}
 
         self.driver = self._instantiate_driver(*args, **kwargs)
@@ -83,7 +84,7 @@ class HuaweiVolumeDriver(object):
             return (product, protocol)
         else:
             msg = (_('"Product" or "Protocol" is illegal. "Product" should '
-                     'be set to T. "Protocol" should be set '
+                     'be set to either T or Dorado. "Protocol" should be set '
                      'to iSCSI. Product: %(product)s '
                      'Protocol: %(protocol)s')
                    % {'product': str(product),
diff --git a/cinder/volume/drivers/huawei/huawei_dorado.py b/cinder/volume/drivers/huawei/huawei_dorado.py
new file mode 100644 (file)
index 0000000..2b1393e
--- /dev/null
@@ -0,0 +1,38 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright (c) 2013 Huawei Technologies Co., Ltd.
+# Copyright (c) 2012 OpenStack LLC.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+"""
+Volume Drivers for Huawei OceanStor Dorado series storage arrays.
+"""
+
+from cinder.volume.drivers.huawei import huawei_t
+from cinder.volume.drivers.huawei import ssh_common
+
+
+class HuaweiDoradoISCSIDriver(huawei_t.HuaweiTISCSIDriver):
+    """ISCSI driver class for Huawei OceanStor Dorado storage arrays."""
+
+    def __init__(self, *args, **kwargs):
+        super(HuaweiDoradoISCSIDriver, self).__init__(*args, **kwargs)
+
+    def do_setup(self, context):
+        """Instantiate common class."""
+        self.common = ssh_common.DoradoCommon(configuration=self.configuration)
+
+        self.common.do_setup(context)
+        self._assert_cli_out = self.common._assert_cli_out
+        self._assert_cli_operate_out = self.common._assert_cli_operate_out
index ef507d70e39a94ded768cefa83c9f7ea749db1d0..3de97b2ee5e733eb72158370f65f898a982bfdaf 100644 (file)
@@ -1127,3 +1127,235 @@ class TseriesCommon():
 
         pool = out.split('\r\n')[6:-2]
         return [line.split() for line in pool]
+
+
+class DoradoCommon(TseriesCommon):
+    """Common class for Huawei Dorado2100 G2 and Dorado5100 storage arrays.
+
+    Dorados share a lot of common codes with T series storage systems,
+    so this class inherited from class TseriesCommon and just rewrite some
+    methods.
+
+    """
+
+    def __init__(self, configuration=None):
+        TseriesCommon.__init__(self, configuration)
+        self.device_type = None
+
+    def do_setup(self, context):
+        """Check config file."""
+        LOG.debug(_('do_setup.'))
+
+        self._check_conf_file()
+        self.lun_distribution = self._get_lun_ctr_info()
+
+    def _check_conf_file(self):
+        """Check the config file, make sure the key elements are set."""
+        root = parse_xml_file(self.xml_conf)
+        # Check login infomation
+        IP1 = root.findtext('Storage/ControllerIP0')
+        IP2 = root.findtext('Storage/ControllerIP1')
+        username = root.findtext('Storage/UserName')
+        pwd = root.findtext('Storage/UserPassword')
+        if (not IP1 and not IP2) or (not username) or (not pwd):
+            err_msg = (_('Config file invalid. Controler IP, UserName, '
+                         'UserPassword must be specified.'))
+            LOG.error(err_msg)
+            raise exception.InvalidInput(reason=err_msg)
+
+        # Check storage pool
+        # No need for Dorado2100 G2
+        self.login_info = self._get_login_info()
+        self.device_type = self._get_device_type()
+        if self.device_type == 'Dorado5100':
+            pool_node = root.findall('LUN/StoragePool')
+            if not pool_node:
+                err_msg = (_('_check_conf_file: Config file invalid. '
+                             'StoragePool must be specified.'))
+                LOG.error(err_msg)
+                raise exception.InvalidInput(reason=err_msg)
+
+    def _get_device_type(self):
+        """Run CLI command to get system type."""
+        cli_cmd = 'showsys'
+        out = self._execute_cli(cli_cmd)
+
+        self._assert_cli_out(re.search('System Information', out),
+                             '_get_device_type',
+                             'Failed to get system information',
+                             cli_cmd, out)
+
+        for line in out.split('\r\n')[4:-2]:
+            if re.search('Device Type', line):
+                if re.search('Dorado2100 G2$', line):
+                    return 'Dorado2100 G2'
+                elif re.search('Dorado5100$', line):
+                    return 'Dorado5100'
+                else:
+                    LOG.error(_('_get_device_type: The drivers only support'
+                                'Dorado5100 and Dorado 2100 G2 now.'))
+                    raise exception.InvalidResults()
+
+    def _get_lun_ctr_info(self):
+        luns = self._get_all_luns_info()
+        ctr_info = [0, 0]
+        (c, n) = ((2, 4) if self.device_type == 'Dorado2100 G2' else (3, 5))
+        for lun in luns:
+            if lun[n].startswith('OpenStack'):
+                if lun[c] == 'A':
+                    ctr_info[0] += 1
+                else:
+                    ctr_info[1] += 1
+        return ctr_info
+
+    def _create_volume(self, name, size, params):
+        """Create a new volume with the given name and size."""
+        cli_cmd = ('createlun -n %(name)s -lunsize %(size)s '
+                   '-wrtype %(wrtype)s '
+                   % {'name': name,
+                      'size': size,
+                      'wrtype': params['WriteType']})
+
+        # If write type is "write through", no need to set mirror switch.
+        if params['WriteType'] != '2':
+            cli_cmd = cli_cmd + ('-mirrorsw %(mirrorsw)s '
+                                 % {'mirrorsw': params['MirrorSwitch']})
+
+        ctr = self._calculate_lun_ctr()
+        # Dorado5100 does not support thin LUN.
+        if self.device_type == 'Dorado5100':
+            cli_cmd = cli_cmd + ('-rg %(raidgroup)s -susize %(susize)s '
+                                 '-c %(ctr)s'
+                                 % {'raidgroup': params['StoragePool'],
+                                    'susize': params['StripUnitSize'],
+                                    'ctr': ctr})
+        else:
+            if params['LUNType'] == 'Thin':
+                # Not allowed to specify ctr for thin LUN.
+                ctr_str = ''
+                luntype_str = '-type 2'
+            else:
+                ctr_str = ' -c %s' % ctr
+                luntype_str = '-type 3'
+
+            cli_cmd = cli_cmd + luntype_str + ctr_str
+
+        out = self._execute_cli(cli_cmd)
+
+        self._assert_cli_operate_out('_create_volume',
+                                     'Failed to create volume %s' % name,
+                                     cli_cmd, out)
+
+        self._update_lun_distribution(ctr)
+
+        return self._get_lun_id(name)
+
+    def _get_lun_id(self, name):
+        luns = self._get_all_luns_info()
+        if luns:
+            n_index = (4 if 'Dorado2100 G2' == self.device_type else 5)
+            for lun in luns:
+                if lun[n_index] == name:
+                    return lun[0]
+        return None
+
+    def create_volume_from_snapshot(self, volume, snapshot):
+        err_msg = (_('create_volume_from_snapshot: %(device)s does '
+                     'not support create volume from snapshot.')
+                   % {'device': self.device_type})
+        LOG.error(err_msg)
+        raise exception.VolumeBackendAPIException(data=err_msg)
+
+    def create_cloned_volume(self, volume, src_vref):
+        err_msg = (_('create_cloned_volume: %(device)s does '
+                     'not support clone volume.')
+                   % {'device': self.device_type})
+        LOG.error(err_msg)
+        raise exception.VolumeBackendAPIException(data=err_msg)
+
+    def create_snapshot(self, snapshot):
+        if self.device_type == 'Dorado2100 G2':
+            err_msg = (_('create_snapshot: %(device)s does not support '
+                         'snapshot.') % {'device': self.device_type})
+            LOG.error(err_msg)
+            raise exception.VolumeBackendAPIException(data=err_msg)
+        else:
+            return TseriesCommon.create_snapshot(self, snapshot)
+
+    def delete_snapshot(self, snapshot):
+        if self.device_type == 'Dorado2100 G2':
+            return
+        else:
+            TseriesCommon.delete_snapshot(self, snapshot)
+
+    def _get_lun_params(self):
+        params_conf = self._parse_conf_lun_params()
+        # Select a pool with maximum capacity.
+        if self.device_type == 'Dorado5100':
+            pools_dev = self._get_dev_pool_info('Thick')
+            params_conf['StoragePool'] = \
+                self._get_maximum_capacity_pool_id(params_conf['StoragePool'],
+                                                   pools_dev, 'Thick')
+        return params_conf
+
+    def _parse_conf_lun_params(self):
+        """Get parameters from config file for creating LUN."""
+        # Default LUN parameters.
+        conf_params = {'LUNType': 'Thin',
+                       'StripUnitSize': '64',
+                       'WriteType': '1',
+                       'MirrorSwitch': '1'}
+
+        root = parse_xml_file(self.xml_conf)
+
+        luntype = root.findtext('LUN/LUNType')
+        if luntype:
+            if luntype.strip() in ['Thick', 'Thin']:
+                conf_params['LUNType'] = luntype.strip()
+            else:
+                err_msg = (_('LUNType must be "Thin" or "Thick". '
+                             'LUNType:%(type)s') % {'type': luntype})
+                raise exception.InvalidInput(reason=err_msg)
+
+        # Here we do not judge whether the parameters are set correct.
+        # CLI will return error responses if the parameters are invalid.
+        stripunitsize = root.findtext('LUN/StripUnitSize')
+        if stripunitsize:
+            conf_params['StripUnitSize'] = stripunitsize.strip()
+        writetype = root.findtext('LUN/WriteType')
+        if writetype:
+            conf_params['WriteType'] = writetype.strip()
+        mirrorswitch = root.findtext('LUN/MirrorSwitch')
+        if mirrorswitch:
+            conf_params['MirrorSwitch'] = mirrorswitch.strip()
+
+        # No need to set StoragePool for Dorado2100 G2.
+        if self.device_type == 'Dorado2100 G2':
+            return conf_params
+
+        pools_conf = root.findall('LUN/StoragePool')
+        conf_params['StoragePool'] = []
+        for pool in pools_conf:
+            conf_params['StoragePool'].append(pool.attrib['Name'].strip())
+
+        return conf_params
+
+    def _get_free_capacity(self):
+        """Get total free capacity of pools."""
+        self._update_login_info()
+        lun_type = ('Thin' if self.device_type == 'Dorado2100 G2' else 'Thick')
+        pools_dev = self._get_dev_pool_info(lun_type)
+        total_free_capacity = 0.0
+        for pool_dev in pools_dev:
+            if self.device_type == 'Dorado2100 G2':
+                total_free_capacity += float(pool_dev[2])
+                continue
+            else:
+                params_conf = self._parse_conf_lun_params()
+                pools_conf = params_conf['StoragePool']
+                for pool_conf in pools_conf:
+                    if pool_dev[5] == pool_conf:
+                        total_free_capacity += float(pool_dev[3])
+                        break
+
+        return total_free_capacity / 1024