From 190c49e1381cc39160ced743cb11e140c9be4825 Mon Sep 17 00:00:00 2001 From: Avishay Traeger Date: Tue, 11 Sep 2012 13:31:01 +0300 Subject: [PATCH] Fixes bug 1049446. Removed the "vtype" option which did not work in the driver, and added the "easytier" option. Added another check to _check_flags and made sure -warning flag is passed properly. Added unit tests to check all option variations. Change-Id: I4e66436f8f62d851a079ec80209fe9d6b27fb5b4 --- cinder/tests/test_storwize_svc.py | 252 +++++++++++++++++++++++------- cinder/volume/storwize_svc.py | 61 +++++--- 2 files changed, 233 insertions(+), 80 deletions(-) diff --git a/cinder/tests/test_storwize_svc.py b/cinder/tests/test_storwize_svc.py index 22a01a9c8..3aff1cb7c 100644 --- a/cinder/tests/test_storwize_svc.py +++ b/cinder/tests/test_storwize_svc.py @@ -46,6 +46,7 @@ class StorwizeSVCManagementSimulator: self._next_cmd_error = { "lsportip": "", "lsnodecanister": "", + "mkvdisk": "", "lsvdisk": "", "lsfcmap": "", "prestartfcmap": "", @@ -92,6 +93,9 @@ class StorwizeSVCManagementSimulator: "virtual disks (VDisks) are different sizes."), "CMMVC6303E": ("", "CMMVC6303E The create failed because the " + "source and target VDisks are the same."), + "CMMVC7050E": ("", "CMMVC7050E The command failed because at " + + "least one node in the I/O group does not " + + "support compressed VDisks."), } # Find an unused ID @@ -142,7 +146,8 @@ class StorwizeSVCManagementSimulator: "source", "target", "unit", - "vtype", + "easytier", + "warning", ] # Handle the special case of lsnode which is a two-word command @@ -182,16 +187,20 @@ class StorwizeSVCManagementSimulator: # Print mostly made-up stuff in the correct syntax def _cmd_lsmdiskgrp(self, **kwargs): - rows = [None] * 2 + rows = [None] * 3 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] = ["0", self._flags["storwize_svc_volpool_name"], "online", + rows[1] = ["1", self._flags["storwize_svc_volpool_name"], "online", "1", str(len(self._volumes_list)), "3.25TB", "256", "3.21TB", "1.54TB", "264.97MB", "35.58GB", "47", "80", "auto", "inactive"] + rows[2] = ["2", "volpool2", "online", + "1", "0", "3.25TB", "256", + "3.21TB", "1.54TB", "264.97MB", "35.58GB", "47", "80", + "auto", "inactive"] return self._print_info_cmd(rows=rows, **kwargs) # Print mostly made-up stuff in the correct syntax @@ -302,17 +311,64 @@ class StorwizeSVCManagementSimulator: unit = kwargs["unit"] if unit == "b": - volume_info["capacity"] = capacity + cap_bytes = capacity elif unit == "kb": - volume_info["capacity"] = capacity * pow(1024, 1) + cap_bytes = capacity * pow(1024, 1) elif unit == "mb": - volume_info["capacity"] = capacity * pow(1024, 2) + cap_bytes = capacity * pow(1024, 2) elif unit == "gb": - volume_info["capacity"] = capacity * pow(1024, 3) + cap_bytes = capacity * pow(1024, 3) elif unit == "tb": - volume_info["capacity"] = capacity * pow(1024, 4) + cap_bytes = capacity * pow(1024, 4) elif unit == "pb": - volume_info["capacity"] = capacity * pow(1024, 5) + cap_bytes = capacity * pow(1024, 5) + volume_info["cap_bytes"] = str(cap_bytes) + volume_info["capacity"] = str(capacity) + unit.upper() + + if "easytier" in kwargs: + if kwargs["easytier"] == "on": + volume_info["easy_tier"] = "on" + else: + volume_info["easy_tier"] = "off" + + if "rsize" in kwargs: + # Fake numbers + volume_info["used_capacity"] = "0.75MB" + volume_info["real_capacity"] = "36.98MB" + volume_info["free_capacity"] = "36.23MB" + volume_info["used_capacity_bytes"] = "786432" + volume_info["real_capacity_bytes"] = "38776340" + volume_info["free_capacity_bytes"] = "37989908" + if "warning" in kwargs: + volume_info["warning"] = kwargs["warning"].rstrip('%') + else: + volume_info["warning"] = "80" + if "autoexpand" in kwargs: + volume_info["autoexpand"] = "on" + else: + volume_info["autoexpand"] = "off" + if "grainsize" in kwargs: + volume_info["grainsize"] = kwargs["grainsize"] + else: + volume_info["grainsize"] = "32" + if "compressed" in kwargs: + if self._next_cmd_error["mkvdisk"] == "no_compression": + self._next_cmd_error["mkvdisk"] = "" + return self._errors["CMMVC7050E"] + volume_info["compressed_copy"] = "yes" + else: + volume_info["compressed_copy"] = "no" + else: + volume_info["used_capacity"] = volume_info["capacity"] + volume_info["real_capacity"] = volume_info["capacity"] + volume_info["free_capacity"] = "0.00MB" + volume_info["used_capacity_bytes"] = volume_info["cap_bytes"] + volume_info["real_capacity_bytes"] = volume_info["cap_bytes"] + volume_info["free_capacity_bytes"] = "0" + volume_info["warning"] = "" + volume_info["autoexpand"] = "" + volume_info["grainsize"] = "" + volume_info["compressed_copy"] = "no" if volume_info["name"] in self._volumes_list: return self._errors["CMMVC6035E"] @@ -375,10 +431,14 @@ class StorwizeSVCManagementSimulator: (kwargs["filtervalue"] == "name=" + vol["name"])): fcmap_info = self._get_fcmap_info(vol["name"]) + if "bytes" in kwargs: + cap = vol["cap_bytes"] + else: + cap = vol["capacity"] rows.append([str(vol["id"]), vol["name"], "0", "io_grp0", "online", "0", self._flags["storwize_svc_volpool_name"], - str(vol["capacity"]), "striped", + cap, "striped", fcmap_info["fc_id"], fcmap_info["fc_name"], "", "", vol["uid"], fcmap_info["fc_map_count"], "1", "empty", @@ -391,7 +451,18 @@ class StorwizeSVCManagementSimulator: return self._errors["CMMVC5754E"] vol = self._volumes_list[kwargs["obj"]] fcmap_info = self._get_fcmap_info(vol["name"]) + if "bytes" in kwargs: + cap = vol["cap_bytes"] + cap_u = vol["used_capacity_bytes"] + cap_r = vol["real_capacity_bytes"] + cap_f = vol["free_capacity_bytes"] + else: + cap = vol["capacity"] + cap_u = vol["used_capacity"] + cap_r = vol["real_capacity"] + cap_f = vol["free_capacity"] rows = [] + rows.append(["id", str(vol["id"])]) rows.append(["name", vol["name"]]) rows.append(["IO_group_id", "0"]) @@ -400,7 +471,7 @@ class StorwizeSVCManagementSimulator: rows.append(["mdisk_grp_id", "0"]) rows.append(["mdisk_grp_name", self._flags["storwize_svc_volpool_name"]]) - rows.append(["capacity", str(vol["capacity"])]) + rows.append(["capacity", cap]) rows.append(["type", "striped"]) rows.append(["formatted", "no"]) rows.append(["mdisk_id", ""]) @@ -428,6 +499,14 @@ class StorwizeSVCManagementSimulator: rows.append(["se_copy_count", "0"]) rows.append(["mirror_write_priority", "latency"]) rows.append(["RC_change", "no"]) + rows.append(["used_capacity", cap_u]) + rows.append(["real_capacity", cap_r]) + rows.append(["free_capacity", cap_f]) + rows.append(["autoexpand", vol["autoexpand"]]) + rows.append(["warning", vol["warning"]]) + rows.append(["grainsize", vol["grainsize"]]) + rows.append(["easy_tier", vol["easy_tier"]]) + rows.append(["compressed_copy", vol["compressed_copy"]]) if "nohdr" in kwargs: for index in range(len(rows)): @@ -625,8 +704,8 @@ class StorwizeSVCManagementSimulator: if source == target: return self._errors["CMMVC6303E"] - if (self._volumes_list[source]["capacity"] != - self._volumes_list[target]["capacity"]): + if (self._volumes_list[source]["cap_bytes"] != + self._volumes_list[target]["cap_bytes"]): return self._errors["CMMVC5924E"] fcmap_info = {} @@ -841,7 +920,6 @@ class StorwizeSVCDriverTestCase(test.TestCase): storwize_svc.FLAGS.san_ip = "hostname" storwize_svc.FLAGS.san_login = "user" storwize_svc.FLAGS.san_password = "pass" - storwize_svc.FLAGS.storwize_svc_volpool_name = "volpool" storwize_svc.FLAGS.storwize_svc_flashcopy_timeout = "20" else: driver = storwize_svc.StorwizeSVCDriver() @@ -854,6 +932,10 @@ class StorwizeSVCDriverTestCase(test.TestCase): self.driver.do_setup(None) self.driver.check_for_setup_error() + def _revert_flags(self): + for flag in storwize_svc.storwize_svc_opts: + setattr(storwize_svc.FLAGS, flag.name, flag.default) + def test_storwize_svc_volume_tests(self): storwize_svc.FLAGS.storwize_svc_vol_rsize = "-1" volume = {} @@ -867,28 +949,22 @@ class StorwizeSVCDriverTestCase(test.TestCase): self.driver.delete_volume(volume) if self.USESIM == 1: - saved_rsize = storwize_svc.FLAGS.storwize_svc_vol_rsize - saved_comp = storwize_svc.FLAGS.storwize_svc_vol_compression storwize_svc.FLAGS.storwize_svc_vol_rsize = "2%" storwize_svc.FLAGS.storwize_svc_vol_compression = True self.driver.create_volume(volume) is_volume_defined = self.driver._is_volume_defined(volume["name"]) self.assertEqual(is_volume_defined, True) self.driver.delete_volume(volume) - storwize_svc.FLAGS.storwize_svc_vol_rsize = saved_rsize - storwize_svc.FLAGS.storwize_svc_vol_compression = saved_comp + self._revert_flags() def test_storwize_svc_ip_connectivity(self): # Check for missing san_ip - saved = storwize_svc.FLAGS.san_ip storwize_svc.FLAGS.san_ip = None self.assertRaises(exception.InvalidInput, self.driver._check_flags) - storwize_svc.FLAGS.san_ip = saved + self._revert_flags() if self.USESIM != 1: - saved = storwize_svc.FLAGS.san_ip - # Check for invalid ip storwize_svc.FLAGS.san_ip = "-1.-1.-1.-1" self.assertRaises(socket.gaierror, @@ -899,7 +975,7 @@ class StorwizeSVCDriverTestCase(test.TestCase): self.assertRaises(socket.error, self.driver.check_for_setup_error) - storwize_svc.FLAGS.san_ip = saved + self._revert_flags() def test_storwize_svc_connectivity(self): # Make sure we detect if the pool doesn't exist @@ -930,57 +1006,49 @@ class StorwizeSVCDriverTestCase(test.TestCase): self.driver.check_for_setup_error) # Check with bad parameters - saved_pass = storwize_svc.FLAGS.san_password - saved_key = storwize_svc.FLAGS.san_private_key storwize_svc.FLAGS.san_password = None storwize_svc.FLAGS.san_private_key = None self.assertRaises(exception.InvalidInput, self.driver._check_flags) - storwize_svc.FLAGS.san_password = saved_pass - storwize_svc.FLAGS.san_private_key = saved_key - - saved = storwize_svc.FLAGS.storwize_svc_vol_vtype - storwize_svc.FLAGS.storwize_svc_vol_vtype = "invalid" - self.assertRaises(exception.InvalidInput, - self.driver._check_flags) - storwize_svc.FLAGS.storwize_svc_vol_vtype = saved + self._revert_flags() - saved = storwize_svc.FLAGS.storwize_svc_vol_rsize storwize_svc.FLAGS.storwize_svc_vol_rsize = "invalid" self.assertRaises(exception.InvalidInput, self.driver._check_flags) - storwize_svc.FLAGS.storwize_svc_vol_rsize = saved + self._revert_flags() - saved = storwize_svc.FLAGS.storwize_svc_vol_warning storwize_svc.FLAGS.storwize_svc_vol_warning = "invalid" self.assertRaises(exception.InvalidInput, self.driver._check_flags) - storwize_svc.FLAGS.storwize_svc_vol_warning = saved + self._revert_flags() - saved = storwize_svc.FLAGS.storwize_svc_vol_autoexpand storwize_svc.FLAGS.storwize_svc_vol_autoexpand = "invalid" self.assertRaises(exception.InvalidInput, self.driver._check_flags) - storwize_svc.FLAGS.storwize_svc_vol_autoexpand = saved + self._revert_flags() - saved = storwize_svc.FLAGS.storwize_svc_vol_grainsize storwize_svc.FLAGS.storwize_svc_vol_grainsize = str(42) self.assertRaises(exception.InvalidInput, self.driver._check_flags) - storwize_svc.FLAGS.storwize_svc_vol_grainsize = saved + self._revert_flags() - saved = storwize_svc.FLAGS.storwize_svc_flashcopy_timeout storwize_svc.FLAGS.storwize_svc_flashcopy_timeout = str(601) self.assertRaises(exception.InvalidInput, self.driver._check_flags) - storwize_svc.FLAGS.storwize_svc_flashcopy_timeout = saved + self._revert_flags() + + storwize_svc.FLAGS.storwize_svc_vol_compression = True + storwize_svc.FLAGS.storwize_svc_vol_rsize = "-1" + self.assertRaises(exception.InvalidInput, + self.driver._check_flags) + self._revert_flags() # Finally, check with good parameters self.driver.check_for_setup_error() def test_storwize_svc_flashcopy(self): volume1 = {} - volume1["name"] = "test_volume%s" % random.randint(10000, 99999) + volume1["name"] = "test1_volume%s" % random.randint(10000, 99999) volume1["size"] = 10 volume1["id"] = 10 self.driver.create_volume(volume1) @@ -990,13 +1058,12 @@ class StorwizeSVCDriverTestCase(test.TestCase): snapshot["volume_name"] = volume1["name"] # Test timeout and volume cleanup - saved = storwize_svc.FLAGS.storwize_svc_flashcopy_timeout storwize_svc.FLAGS.storwize_svc_flashcopy_timeout = str(1) self.assertRaises(exception.InvalidSnapshot, self.driver.create_snapshot, snapshot) is_volume_defined = self.driver._is_volume_defined(snapshot["name"]) self.assertEqual(is_volume_defined, False) - storwize_svc.FLAGS.storwize_svc_flashcopy_timeout = saved + self._revert_flags() # Test bogus statuses if self.USESIM == 1: @@ -1069,7 +1136,7 @@ class StorwizeSVCDriverTestCase(test.TestCase): # Check with target with different size volume3 = {} - volume3["name"] = "test_volume%s" % random.randint(10000, 99999) + volume3["name"] = "test3_volume%s" % random.randint(10000, 99999) volume3["size"] = 11 volume3["id"] = 11 self.driver.create_volume(volume3) @@ -1109,8 +1176,6 @@ class StorwizeSVCDriverTestCase(test.TestCase): self.assertEqual(attr_size, float(volume["size"])) pool = getattr(storwize_svc.FLAGS, "storwize_svc_volpool_name") self.assertEqual(attributes["mdisk_grp_name"], pool) - vtype = getattr(storwize_svc.FLAGS, "storwize_svc_vol_vtype") - self.assertEqual(attributes["type"], vtype) # Try to create the volume again (should fail) self.assertRaises(exception.ProcessExecutionError, @@ -1125,14 +1190,91 @@ class StorwizeSVCDriverTestCase(test.TestCase): # Delete the volume self.driver.delete_volume(volume) - # Check auto-expand option - saved = storwize_svc.FLAGS.storwize_svc_vol_autoexpand - storwize_svc.FLAGS.storwize_svc_vol_autoexpand = False + def _create_test_vol(self): + volume = {} + volume["name"] = "testparam_volume%s" % random.randint(10000, 99999) + volume["size"] = 1 + volume["id"] = 1 self.driver.create_volume(volume) - is_volume_defined = self.driver._is_volume_defined(volume["name"]) - self.assertEqual(is_volume_defined, True) + + attrs = self.driver._get_volume_attributes(volume["name"]) self.driver.delete_volume(volume) - storwize_svc.FLAGS.storwize_svc_vol_autoexpand = saved + return attrs + + def test_storwize_svc_volume_params(self): + # Option test matrix + # Option Value Covered by test # + # rsize -1 1 + # rsize 2% 2,3 + # warning 0 2 + # warning 80% 3 + # autoexpand True 2 + # autoexpand False 3 + # grainsize 32 2 + # grainsize 256 3 + # compression True 4 + # compression False 2,3 + # easytier True 1,3 + # easytier False 2 + + # Test 1 + storwize_svc.FLAGS.storwize_svc_vol_rsize = "-1" + storwize_svc.FLAGS.storwize_svc_vol_easytier = True + attrs = self._create_test_vol() + self.assertEquals(attrs["free_capacity"], "0") + self.assertEquals(attrs["easy_tier"], "on") + self._revert_flags() + + # Test 2 + storwize_svc.FLAGS.storwize_svc_vol_rsize = "2%" + storwize_svc.FLAGS.storwize_svc_vol_compression = False + storwize_svc.FLAGS.storwize_svc_vol_warning = "0" + storwize_svc.FLAGS.storwize_svc_vol_autoexpand = True + storwize_svc.FLAGS.storwize_svc_vol_grainsize = "32" + storwize_svc.FLAGS.storwize_svc_vol_easytier = False + attrs = self._create_test_vol() + self.assertNotEqual(attrs["capacity"], attrs["real_capacity"]) + self.assertEquals(attrs["compressed_copy"], "no") + self.assertEquals(attrs["warning"], "0") + self.assertEquals(attrs["autoexpand"], "on") + self.assertEquals(attrs["grainsize"], "32") + self.assertEquals(attrs["easy_tier"], "off") + self._revert_flags() + + # Test 3 + storwize_svc.FLAGS.storwize_svc_vol_rsize = "2%" + storwize_svc.FLAGS.storwize_svc_vol_compression = False + storwize_svc.FLAGS.storwize_svc_vol_warning = "80%" + storwize_svc.FLAGS.storwize_svc_vol_autoexpand = False + storwize_svc.FLAGS.storwize_svc_vol_grainsize = "256" + storwize_svc.FLAGS.storwize_svc_vol_easytier = True + attrs = self._create_test_vol() + self.assertNotEqual(attrs["capacity"], attrs["real_capacity"]) + self.assertEquals(attrs["compressed_copy"], "no") + self.assertEquals(attrs["warning"], "80") + self.assertEquals(attrs["autoexpand"], "off") + self.assertEquals(attrs["grainsize"], "256") + self.assertEquals(attrs["easy_tier"], "on") + self._revert_flags() + + # Test 4 + storwize_svc.FLAGS.storwize_svc_vol_rsize = "2%" + storwize_svc.FLAGS.storwize_svc_vol_compression = True + try: + attrs = self._create_test_vol() + self.assertNotEqual(attrs["capacity"], attrs["real_capacity"]) + self.assertEquals(attrs["compressed_copy"], "yes") + except exception.ProcessExecutionError as e: + if "CMMVC7050E" not in e.stderr: + raise exception.ProcessExecutionError(exit_code=e.exit_code, + stdout=e.stdout, + stderr=e.stderr, + cmd=e.cmd) + if self.USESIM == 1: + self.sim.error_injection("mkvdisk", "no_compression") + self.assertRaises(exception.ProcessExecutionError, + self._create_test_vol) + self._revert_flags() def test_storwize_svc_unicode_host_and_volume_names(self): volume1 = {} diff --git a/cinder/volume/storwize_svc.py b/cinder/volume/storwize_svc.py index ba8f4213d..9e0d0e7ae 100644 --- a/cinder/volume/storwize_svc.py +++ b/cinder/volume/storwize_svc.py @@ -28,9 +28,9 @@ Notes: key file only. 2. When using a key file for authentication, it is up to the user or system administrator to store the private key in a safe manner. -3. The defaults for creating volumes are "-vtype striped -rsize 2% -autoexpand - -grainsize 256 -warning 0". These can be changed in the configuration file - (recommended only for advanced users). +3. The defaults for creating volumes are "-rsize 2% -autoexpand + -grainsize 256 -warning 0". These can be changed in the configuration + file or by using volume types(recommended only for advanced users). Limitations: 1. The driver was not tested with SVC or clustered configurations of Storwize @@ -57,9 +57,6 @@ storwize_svc_opts = [ cfg.StrOpt('storwize_svc_volpool_name', default='volpool', help='Storage system storage pool for volumes'), - cfg.StrOpt('storwize_svc_vol_vtype', - default='striped', - help='Storage system volume type for volumes'), cfg.StrOpt('storwize_svc_vol_rsize', default='2%', help='Storage system space-efficiency parameter for volumes'), @@ -77,6 +74,9 @@ storwize_svc_opts = [ cfg.BoolOpt('storwize_svc_vol_compression', default=False, help='Storage system compression option for volumes'), + cfg.BoolOpt('storwize_svc_vol_easytier', + default=True, + help='Enable Easy Tier for volumes'), cfg.StrOpt('storwize_svc_flashcopy_timeout', default='120', help='Maximum number of seconds to wait for FlashCopy to be' @@ -333,16 +333,9 @@ class StorwizeSVCDriver(san.SanISCSIDriver): 'authentication: set either san_password or ' 'san_private_key option')) - # vtype should either be 'striped' or 'seq' - vtype = getattr(FLAGS, 'storwize_svc_vol_vtype') - if vtype not in ['striped', 'seq']: - raise exception.InvalidInput( - reason=_('Illegal value specified for storwize_svc_vol_vtype: ' - 'set to either \'striped\' or \'seq\'')) - # Check that rsize is a number or percentage rsize = getattr(FLAGS, 'storwize_svc_vol_rsize') - if not self._check_num_perc(rsize) and (rsize not in ['auto', '-1']): + if not self._check_num_perc(rsize) and (rsize != '-1'): raise exception.InvalidInput( reason=_('Illegal value specified for storwize_svc_vol_rsize: ' 'set to either a number or a percentage')) @@ -381,13 +374,26 @@ class StorwizeSVCDriver(san.SanISCSIDriver): 'valid values are between 0 and 600') % flashcopy_timeout) - # Check that compression is a boolean + # Check that compression is a boolean and that rsize is set volume_compression = getattr(FLAGS, 'storwize_svc_vol_compression') if type(volume_compression) != type(True): raise exception.InvalidInput( reason=_('Illegal value specified for ' 'storwize_svc_vol_compression: set to either ' 'True or False')) + if ((volume_compression == True) and + (getattr(FLAGS, 'storwize_svc_vol_rsize') == '-1')): + raise exception.InvalidInput( + reason=_('If compression is set to True, rsize must ' + 'also be set (not equal to -1)')) + + # Check that easytier is a boolean + volume_easytier = getattr(FLAGS, 'storwize_svc_vol_easytier') + if type(volume_easytier) != type(True): + raise exception.InvalidInput( + reason=_('Illegal value specified for ' + 'storwize_svc_vol_easytier: set to either ' + 'True or False')) def do_setup(self, context): """Validate the flags.""" @@ -410,30 +416,35 @@ class StorwizeSVCDriver(san.SanISCSIDriver): size = int(volume['size']) if getattr(FLAGS, 'storwize_svc_vol_autoexpand') == True: - autoexpand = '-autoexpand' + autoex = '-autoexpand' + else: + autoex = '' + + if getattr(FLAGS, 'storwize_svc_vol_easytier') == True: + easytier = '-easytier on' else: - autoexpand = '' + easytier = '-easytier off' # Set space-efficient options if getattr(FLAGS, 'storwize_svc_vol_rsize').strip() == '-1': ssh_cmd_se_opt = '' else: - ssh_cmd_se_opt = ('-rsize %(rsize)s %(autoexpand)s ' % + ssh_cmd_se_opt = ('-rsize %(rsize)s %(autoex)s -warning %(warn)s' % {'rsize': getattr(FLAGS, 'storwize_svc_vol_rsize'), - 'autoexpand': autoexpand}) + 'autoex': autoex, + 'warn': getattr(FLAGS, 'storwize_svc_vol_warning')}) if getattr(FLAGS, 'storwize_svc_vol_compression'): - ssh_cmd_se_opt = ssh_cmd_se_opt + '-compressed' + ssh_cmd_se_opt = ssh_cmd_se_opt + ' -compressed' else: - ssh_cmd_se_opt = ssh_cmd_se_opt + ('-grainsize %(grain)s' % + ssh_cmd_se_opt = ssh_cmd_se_opt + (' -grainsize %(grain)s' % {'grain': getattr(FLAGS, 'storwize_svc_vol_grainsize')}) ssh_cmd = ('mkvdisk -name %(name)s -mdiskgrp %(mdiskgrp)s ' - '-iogrp 0 -vtype %(vtype)s -size %(size)s -unit ' - '%(unit)s %(ssh_cmd_se_opt)s' + '-iogrp 0 -size %(size)s -unit ' + '%(unit)s %(easytier)s %(ssh_cmd_se_opt)s' % {'name': name, 'mdiskgrp': getattr(FLAGS, 'storwize_svc_volpool_name'), - 'vtype': getattr(FLAGS, 'storwize_svc_vol_vtype'), - 'size': size, 'unit': units, + 'size': size, 'unit': units, 'easytier': easytier, 'ssh_cmd_se_opt': ssh_cmd_se_opt}) out, err = self._run_ssh(ssh_cmd) self._driver_assert(len(out.strip()) > 0, -- 2.45.2