From 96795787aeb92a644138daba235e954d3c0fd83b Mon Sep 17 00:00:00 2001 From: liucheng Date: Tue, 17 May 2016 12:47:27 +0800 Subject: [PATCH] Huawei: Add share sectorsize config in Huawei driver Data in the file system consists of fixed-length disk blocks. The size of the blocks (also known as file system sector size) affects disk space usage and performance. The value of blocks can be 4 KB, 8 KB, 16 KB, 32 KB, or 64 KB. Change-Id: I95a9aa7e071c470c21dc0fa009ba96a7c7439ce6 Implements: blueprint huawei-driver-block-size-config --- doc/source/devref/huawei_nas_driver.rst | 14 +++ manila/share/drivers/huawei/constants.py | 5 + manila/share/drivers/huawei/v3/connection.py | 3 + manila/share/drivers/huawei/v3/smartx.py | 21 ++++ .../share/drivers/huawei/test_huawei_nas.py | 111 +++++++++++++++++- ...er-sectorsize-config-da776132ba6da2a7.yaml | 5 + 6 files changed, 157 insertions(+), 2 deletions(-) create mode 100644 releasenotes/notes/huawei-driver-sectorsize-config-da776132ba6da2a7.yaml diff --git a/doc/source/devref/huawei_nas_driver.rst b/doc/source/devref/huawei_nas_driver.rst index 5d56e4a659..e6500ce30c 100644 --- a/doc/source/devref/huawei_nas_driver.rst +++ b/doc/source/devref/huawei_nas_driver.rst @@ -84,6 +84,7 @@ storage systems, the driver configuration file is as follows: xxxxxxxxx xxxxxxxx + 64 3 60 @@ -109,6 +110,11 @@ storage systems, the driver configuration file is as follows: - `UserPassword` is a password of an administrator. - `StoragePool` is a name of a storage pool to be used. - `AllocType` is the file system space allocation type, optional value is "Thick" or "Thin". +- `SectorSize` is the size of the disk blocks, optional value can be "4", "8", "16", "32" or "64", + and the units is KB. If "sectorsize" is configured in both share_type and xml file, the value + of sectorsize in the share_type will be used. If "sectorsize" is configured in neither + share_type nor xml file, huawei storage backends will provide a default value(64) when creating + a new share. - `WaitInterval` is the interval time of querying the file system status. - `Timeout` is the timeout period for waiting command execution of a device to complete. @@ -179,6 +185,8 @@ commit makes the Huawei driver report the following boolean capabilities: * qos:latency * qos:iotype +- capabilities:huawei_sectorsize + The scheduler will choose a host that supports the needed capability when the CapabilityFilter is used and a share type uses one or more of the following extra-specs: @@ -203,6 +211,10 @@ type uses one or more of the following extra-specs: * qos:latency=10 * qos:iotype=0 +- capabilities:huawei_sectorsize=' True' or ' False' + + * huawei_sectorsize:sectorsize=4 + `thin_provisioning` will be reported as [True, False] for Huawei backends. `dedupe` will be reported as [True, False] for Huawei backends. @@ -221,6 +233,8 @@ ensuring the quality of critical services. `qos` will be reported as True for backends that use QoS (Quality of Service) specification. +`huawei_sectorsize` will be reported as [True, False] for Huawei backends. + Restrictions ------------ diff --git a/manila/share/drivers/huawei/constants.py b/manila/share/drivers/huawei/constants.py index c1abd2d19a..18acdac307 100644 --- a/manila/share/drivers/huawei/constants.py +++ b/manila/share/drivers/huawei/constants.py @@ -80,11 +80,13 @@ OPTS_CAPABILITIES = { 'huawei_smartpartition': False, 'thin_provisioning': None, 'qos': False, + 'huawei_sectorsize': None, } OPTS_VALUE = { 'cachename': None, 'partitionname': None, + 'sectorsize': None, } OPTS_VALUE.update(OPTS_QOS_VALUE) @@ -92,5 +94,8 @@ OPTS_VALUE.update(OPTS_QOS_VALUE) OPTS_ASSOCIATE = { 'huawei_smartcache': 'cachename', 'huawei_smartpartition': 'partitionname', + 'huawei_sectorsize': 'sectorsize', 'qos': OPTS_QOS_VALUE, } + +VALID_SECTOR_SIZES = ('4', '8', '16', '32', '64') \ No newline at end of file diff --git a/manila/share/drivers/huawei/v3/connection.py b/manila/share/drivers/huawei/v3/connection.py index dac3f0ce75..bf246dcdfe 100644 --- a/manila/share/drivers/huawei/v3/connection.py +++ b/manila/share/drivers/huawei/v3/connection.py @@ -298,6 +298,7 @@ class V3StorageConnection(driver.HuaweiBase): compression=[True, False], huawei_smartcache=[True, False], huawei_smartpartition=[True, False], + huawei_sectorsize=[True, False], ) stats_dict["pools"].append(pool) @@ -630,6 +631,8 @@ class V3StorageConnection(driver.HuaweiBase): ' so dedupe or compression cannot be set.') LOG.error(err_msg) raise exception.InvalidInput(reason=err_msg) + if extra_specs['sectorsize']: + fileparam['SECTORSIZE'] = extra_specs['sectorsize'] * units.Ki return fileparam diff --git a/manila/share/drivers/huawei/v3/smartx.py b/manila/share/drivers/huawei/v3/smartx.py index 8309ee5616..691a7b12f8 100644 --- a/manila/share/drivers/huawei/v3/smartx.py +++ b/manila/share/drivers/huawei/v3/smartx.py @@ -110,6 +110,7 @@ class SmartX(object): opts = self.get_smartprovisioning_opts(opts) opts = self.get_smartcache_opts(opts) opts = self.get_smartpartition_opts(opts) + opts = self.get_sectorsize_opts(opts) qos = self.get_qos_opts(opts) return opts, qos @@ -170,6 +171,26 @@ class SmartX(object): return opts + def get_sectorsize_opts(self, opts): + value = None + if strutils.bool_from_string(opts.get('huawei_sectorsize')): + value = opts.get('sectorsize') + if not value: + root = self.helper._read_xml() + sectorsize = root.findtext('Filesystem/SectorSize') + if sectorsize: + sectorsize = sectorsize.strip() + value = sectorsize + + if value: + if value not in constants.VALID_SECTOR_SIZES: + raise exception.InvalidInput( + reason=(_('Illegal value(%s) specified for sectorsize: ' + 'set to either 4, 8, 16, 32 or 64.') % value)) + else: + opts['sectorsize'] = int(value) + return opts + def get_qos_opts(self, opts): qos = {} if not strutils.bool_from_string(opts.get('qos')): diff --git a/manila/tests/share/drivers/huawei/test_huawei_nas.py b/manila/tests/share/drivers/huawei/test_huawei_nas.py index f24fae0b6c..b022f9e77c 100644 --- a/manila/tests/share/drivers/huawei/test_huawei_nas.py +++ b/manila/tests/share/drivers/huawei/test_huawei_nas.py @@ -1160,6 +1160,11 @@ class HuaweiShareDriverTestCase(test.TestCase): share = None return share + def mock_share_type(self, share_type): + self.mock_object(db, + 'share_type_get', + mock.Mock(return_value=share_type)) + def test_conf_product_fail(self): self.recreate_fake_conf_file(product_flag=False) self.driver.plugin.configuration.manila_huawei_conf_file = ( @@ -1374,6 +1379,99 @@ class HuaweiShareDriverTestCase(test.TestCase): self.assertEqual(constants.ALLOC_TYPE_THICK_FLAG, self.driver.plugin.helper.alloc_type) + @ddt.data(*constants.VALID_SECTOR_SIZES) + def test_create_share_with_sectorsize_in_type(self, sectorsize): + share_type = { + 'extra_specs': { + 'capabilities:huawei_sectorsize': " true", + 'huawei_sectorsize:sectorsize': sectorsize, + }, + } + self.mock_share_type(share_type) + + self.driver.plugin.helper.login() + location = self.driver.create_share(self._context, self.share_nfs, + self.share_server) + + self.assertEqual("100.115.10.68:/share_fake_uuid", location) + self.assertTrue(db.share_type_get.called) + + @ddt.data('128', 'xx', 'None', ' ') + def test_create_share_with_illegal_sectorsize_in_type(self, sectorsize): + share_type = { + 'extra_specs': { + 'capabilities:huawei_sectorsize': " true", + 'huawei_sectorsize:sectorsize': sectorsize, + }, + } + self.mock_share_type(share_type) + + self.driver.plugin.helper.login() + self.assertRaises(exception.InvalidShare, + self.driver.create_share, + self._context, + self.share_nfs, + self.share_server) + + @ddt.data({'extra_specs': {'capabilities:huawei_sectorsize': " false", + 'huawei_sectorsize:sectorsize': '0'}, 'xmlvalue': '4'}, + {'extra_specs': {'capabilities:huawei_sectorsize': " False", + 'huawei_sectorsize:sectorsize': '128'}, 'xmlvalue': '8'}, + {'extra_specs': {'capabilities:huawei_sectorsize': "false", + 'huawei_sectorsize:sectorsize': 'a'}, 'xmlvalue': '16'}, + {'extra_specs': {'capabilities:huawei_sectorsize': "False", + 'huawei_sectorsize:sectorsize': 'xx'}, 'xmlvalue': '32'}, + {'extra_specs': {'capabilities:huawei_sectorsize': "true", + 'huawei_sectorsize:sectorsize': 'None'}, 'xmlvalue': '64'}, + {'extra_specs': {'capabilities:huawei_sectorsize': "True", + 'huawei_sectorsize:sectorsize': ' '}, 'xmlvalue': ' '}, + {'extra_specs': {'capabilities:huawei_sectorsize': "True", + 'huawei_sectorsize:sectorsize': ''}, 'xmlvalue': ''}) + @ddt.unpack + def test_create_share_with_invalid_type_valid_xml(self, extra_specs, + xmlvalue): + fake_share_type = {} + fake_share_type['extra_specs'] = extra_specs + self.mock_share_type(fake_share_type) + + self.recreate_fake_conf_file(sectorsize_value=xmlvalue) + self.driver.plugin.configuration.manila_huawei_conf_file = ( + self.fake_conf_file) + self.driver.plugin.helper.login() + location = self.driver.create_share(self._context, self.share_nfs, + self.share_server) + + self.assertEqual("100.115.10.68:/share_fake_uuid", location) + self.assertTrue(db.share_type_get.called) + + @ddt.data({'extra_specs': {'capabilities:huawei_sectorsize': " false", + 'huawei_sectorsize:sectorsize': '4'}, 'xmlvalue': '0'}, + {'extra_specs': {'capabilities:huawei_sectorsize': " False", + 'huawei_sectorsize:sectorsize': '8'}, 'xmlvalue': '128'}, + {'extra_specs': {'capabilities:huawei_sectorsize': "false", + 'huawei_sectorsize:sectorsize': '16'}, 'xmlvalue': 'a'}, + {'extra_specs': {'capabilities:huawei_sectorsize': "False", + 'huawei_sectorsize:sectorsize': '32'}, 'xmlvalue': 'xx'}, + {'extra_specs': {'capabilities:huawei_sectorsize': "true", + 'huawei_sectorsize:sectorsize': '64'}, 'xmlvalue': 'None'}) + @ddt.unpack + def test_create_share_with_invalid_type_illegal_xml(self, extra_specs, + xmlvalue): + fake_share_type = {} + fake_share_type['extra_specs'] = extra_specs + self.mock_share_type(fake_share_type) + + self.recreate_fake_conf_file(sectorsize_value=xmlvalue) + self.driver.plugin.configuration.manila_huawei_conf_file = ( + self.fake_conf_file) + self.driver.plugin.helper.login() + + self.assertRaises(exception.InvalidShare, + self.driver.create_share, + self._context, + self.share_nfs, + self.share_server) + def test_shrink_share_success(self): self.driver.plugin.helper.shrink_share_flag = False self.driver.plugin.helper.login() @@ -2158,6 +2256,7 @@ class HuaweiShareDriverTestCase(test.TestCase): thin_provisioning=[True, False], huawei_smartcache=[True, False], huawei_smartpartition=[True, False], + huawei_sectorsize=[True, False], ) expected["pools"].append(pool) self.assertEqual(expected, self.driver._stats) @@ -3475,6 +3574,7 @@ class HuaweiShareDriverTestCase(test.TestCase): pool_node_flag=True, timeout_flag=True, wait_interval_flag=True, alloctype_value='Thick', + sectorsize_value='4', multi_url=False, logical_port='100.115.10.68'): doc = xml.dom.minidom.Document() @@ -3584,6 +3684,12 @@ class HuaweiShareDriverTestCase(test.TestCase): alloctype.appendChild(alloctype_text) lun.appendChild(alloctype) + if sectorsize_value: + sectorsize = doc.createElement('SectorSize') + sectorsize_text = doc.createTextNode(sectorsize_value) + sectorsize.appendChild(sectorsize_text) + lun.appendChild(sectorsize) + prefetch = doc.createElement('Prefetch') prefetch.setAttribute('Type', '0') prefetch.setAttribute('Value', '0') @@ -3597,6 +3703,7 @@ class HuaweiShareDriverTestCase(test.TestCase): pool_node_flag=True, timeout_flag=True, wait_interval_flag=True, alloctype_value='Thick', + sectorsize_value='4', multi_url=False, logical_port='100.115.10.68'): self.tmp_dir = tempfile.mkdtemp() @@ -3605,6 +3712,6 @@ class HuaweiShareDriverTestCase(test.TestCase): self.create_fake_conf_file(self.fake_conf_file, product_flag, username_flag, pool_node_flag, timeout_flag, wait_interval_flag, - alloctype_value, multi_url, - logical_port) + alloctype_value, sectorsize_value, + multi_url, logical_port) self.addCleanup(os.remove, self.fake_conf_file) diff --git a/releasenotes/notes/huawei-driver-sectorsize-config-da776132ba6da2a7.yaml b/releasenotes/notes/huawei-driver-sectorsize-config-da776132ba6da2a7.yaml new file mode 100644 index 0000000000..ed834811b7 --- /dev/null +++ b/releasenotes/notes/huawei-driver-sectorsize-config-da776132ba6da2a7.yaml @@ -0,0 +1,5 @@ +--- +features: + - Huawei driver supports setting the backend 'sectorsize' while creating shares + and administrators can use this capability via the share types extra-spec + 'huawei_sectorsize:sectorsize' or via the XML configuration file.