diff --git a/qa/ganeti-qa.py b/qa/ganeti-qa.py index d7b6a237dd379177e698850380a4b537c94a4ade..7af9ff80cfe4b7b43a7a1bc63be06073960167f7 100755 --- a/qa/ganeti-qa.py +++ b/qa/ganeti-qa.py @@ -267,6 +267,8 @@ def RunCommonInstanceTests(instance): RunTestIf(["instance-console", qa_rapi.Enabled], qa_rapi.TestRapiInstanceConsole, instance) + RunTestIf("instance-device-names", qa_instance.TestInstanceDeviceNames, + instance) DOWN_TESTS = qa_config.Either([ "instance-reinstall", "instance-rename", diff --git a/qa/qa-sample.json b/qa/qa-sample.json index 3899a47cc71be9e81833d07b0245fc9e3abf4b88..851a3b123e9f1f74960768748505e47c46617b09 100644 --- a/qa/qa-sample.json +++ b/qa/qa-sample.json @@ -68,9 +68,19 @@ "#ispec_nic_count_min": null, "#ispec_nic_count_std": null, - "# Lists of disk sizes": null, - "disk": ["1G", "512M"], - "disk-growth": ["2G", "768M"], + "# Lists of disks": null, + "disks": [ + { + "size": "1G", + "name": "disk0", + "growth": "2G" + }, + { + "size": "512M", + "name": "disk1", + "growth": "768M" + } + ], "# Script to check instance status": null, "instance-check": null, @@ -197,6 +207,7 @@ "instance-reinstall": true, "instance-rename": true, "instance-shutdown": true, + "instance-device-names": true, "job-list": true, diff --git a/qa/qa_cluster.py b/qa/qa_cluster.py index 210f8bf4751768eccdac9d8d949923ec160bbe1f..c4de57abdc584c796b78ad3cb2abbe8e970edd1d 100644 --- a/qa/qa_cluster.py +++ b/qa/qa_cluster.py @@ -800,13 +800,14 @@ def TestClusterBurnin(): script = qa_utils.UploadFile(master.primary, "../tools/burnin") try: + disks = qa_config.GetDiskOptions() # Run burnin cmd = [script, "--os=%s" % qa_config.get("os"), "--minmem-size=%s" % qa_config.get(constants.BE_MINMEM), "--maxmem-size=%s" % qa_config.get(constants.BE_MAXMEM), - "--disk-size=%s" % ",".join(qa_config.get("disk")), - "--disk-growth=%s" % ",".join(qa_config.get("disk-growth")), + "--disk-size=%s" % ",".join([d.get("size") for d in disks]), + "--disk-growth=%s" % ",".join([d.get("growth") for d in disks]), "--disk-template=%s" % disk_template] if parallel: cmd.append("--parallel") diff --git a/qa/qa_config.py b/qa/qa_config.py index 1c6a5430c5805aa119ac66f1c2dc090ddc965082..4e0d5f5530b6230f4c2bd6d6d7234f464ccc26d4 100644 --- a/qa/qa_config.py +++ b/qa/qa_config.py @@ -280,12 +280,14 @@ class _QaConfig(object): if not self.get("instances"): raise qa_error.Error("Need at least one instance") - if (self.get("disk") is None or - self.get("disk-growth") is None or - len(self.get("disk")) != len(self.get("disk-growth"))): - raise qa_error.Error("Config options 'disk' and 'disk-growth' must exist" - " and have the same number of items") - + disks = self.GetDiskOptions() + if disks is None: + raise qa_error.Error("Config option 'disks' must exist") + else: + for d in disks: + if d.get("size") is None or d.get("growth") is None: + raise qa_error.Error("Config options `size` and `growth` must exist" + " for all `disks` items") check = self.GetInstanceCheckScript() if check: try: @@ -425,6 +427,32 @@ class _QaConfig(object): return (master, basedir) + def GetDiskOptions(self): + """Return options for the disks of the instances. + + Get 'disks' parameter from the configuration data. If 'disks' is missing, + try to create it from the legacy 'disk' and 'disk-growth' parameters. + + """ + try: + return self._data["disks"] + except KeyError: + pass + + # Legacy interface + sizes = self._data.get("disk") + growths = self._data.get("disk-growth") + if sizes or growths: + if (sizes is None or growths is None or len(sizes) != len(growths)): + raise qa_error.Error("Config options 'disk' and 'disk-growth' must" + " exist and have the same number of items") + disks = [] + for (size, growth) in zip(sizes, growths): + disks.append({"size": size, "growth": growth}) + return disks + else: + return None + def Load(path): """Loads the passed configuration file. @@ -718,3 +746,10 @@ def NoVirtualCluster(): """ return not UseVirtualCluster() + + +def GetDiskOptions(): + """Wrapper for L{_QaConfig.GetDiskOptions}. + + """ + return GetConfig().GetDiskOptions() diff --git a/qa/qa_instance.py b/qa/qa_instance.py index 33376b46f966a311071772c4d4262de5e995096e..b348fc8452e3df7f32e4386a8a3c4916cfab9032 100644 --- a/qa/qa_instance.py +++ b/qa/qa_instance.py @@ -52,8 +52,10 @@ def _GetGenericAddParameters(inst, disk_template, force_mac=None): qa_config.get(constants.BE_MAXMEM))) if disk_template != constants.DT_DISKLESS: - for idx, size in enumerate(qa_config.get("disk")): - params.extend(["--disk", "%s:size=%s" % (idx, size)]) + for idx, disk in enumerate(qa_config.GetDiskOptions()): + size = disk.get("size") + name = disk.get("name") + params.extend(["--disk", "%s:size=%s,name=%s" % (idx, size, name)]) # Set static MAC address if configured if force_mac: @@ -780,8 +782,9 @@ def TestInstanceGrowDisk(instance): return name = instance.name - all_size = qa_config.get("disk") - all_grow = qa_config.get("disk-growth") + disks = qa_config.GetDiskOptions() + all_size = [d.get("size") for d in disks] + all_grow = [d.get("growth") for d in disks] if not all_grow: # missing disk sizes but instance grow disk has been enabled, @@ -801,6 +804,55 @@ def TestInstanceGrowDisk(instance): str(int_size + 2 * int_grow)]) +@InstanceCheck(INST_UP, INST_UP, FIRST_ARG) +def TestInstanceDeviceNames(instance): + if instance.disk_template == constants.DT_DISKLESS: + print qa_utils.FormatInfo("Test not supported for diskless instances") + return + + name = instance.name + for dev_type in ["disk", "net"]: + if dev_type == "disk": + options = ",size=512M" + else: + options = "" + # succeed in adding a device named 'test_device' + AssertCommand(["gnt-instance", "modify", + "--%s=-1:add,name=test_device%s" % (dev_type, options), + name]) + # succeed in removing the 'test_device' + AssertCommand(["gnt-instance", "modify", + "--%s=test_device:remove" % dev_type, + name]) + # fail to add two devices with the same name + AssertCommand(["gnt-instance", "modify", + "--%s=-1:add,name=test_device%s" % (dev_type, options), + "--%s=-1:add,name=test_device%s" % (dev_type, options), + name], fail=True) + # fail to add a device with invalid name + AssertCommand(["gnt-instance", "modify", + "--%s=-1:add,name=2%s" % (dev_type, options), + name], fail=True) + # Rename disks + disks = qa_config.GetDiskOptions() + disk_names = [d.get("name") for d in disks] + for idx, disk_name in enumerate(disk_names): + # Refer to disk by idx + AssertCommand(["gnt-instance", "modify", + "--disk=%s:modify,name=renamed" % idx, + name]) + # Refer to by name and rename to original name + AssertCommand(["gnt-instance", "modify", + "--disk=renamed:modify,name=%s" % disk_name, + name]) + if len(disks) >= 2: + # fail in renaming to disks to the same name + AssertCommand(["gnt-instance", "modify", + "--disk=0:modify,name=same_name", + "--disk=1:modify,name=same_name", + name], fail=True) + + def TestInstanceList(): """gnt-instance list""" qa_utils.GenericQueryTest("gnt-instance", query.INSTANCE_FIELDS.keys()) diff --git a/qa/qa_rapi.py b/qa/qa_rapi.py index b2ff4f0b20f0b89feb5c2b6a65e0c086334fd334..0ebe6356c7e23705a8fde280d4a4ac37d5df3b49 100644 --- a/qa/qa_rapi.py +++ b/qa/qa_rapi.py @@ -565,8 +565,9 @@ def TestRapiInstanceAdd(node, use_client): instance = qa_config.AcquireInstance() instance.SetDiskTemplate(constants.DT_PLAIN) try: - disk_sizes = [utils.ParseUnit(size) for size in qa_config.get("disk")] - disks = [{"size": size} for size in disk_sizes] + disks = [{"size": utils.ParseUnit(d.get("size")), + "name": str(d.get("name"))} + for d in qa_config.GetDiskOptions()] nic0_mac = instance.GetNicMacAddr(0, constants.VALUE_GENERATE) nics = [{ constants.INIC_MAC: nic0_mac, diff --git a/test/data/qa-minimal-nodes-instances-only.json b/test/data/qa-minimal-nodes-instances-only.json index 6a5578eceada652230cf9159e010774809c53837..9a85241f28909c4e1c0c89562506c9ebcc65468d 100644 --- a/test/data/qa-minimal-nodes-instances-only.json +++ b/test/data/qa-minimal-nodes-instances-only.json @@ -1,8 +1,17 @@ { "name": "xen-test-qa-minimal-nodes-instances-only", - "disk": ["1G", "512M"], - "disk-growth": ["2G", "768M"], + "# Lists of disks": null, + "disks": [ + { + "size": "1G", + "growth": "2G" + }, + { + "size": "512M", + "growth": "768M" + } + ], "enabled-disk-templates": [ "plain", diff --git a/test/py/qa.qa_config_unittest.py b/test/py/qa.qa_config_unittest.py index bb27dde30689f4d6bc9fb4d23593e6f21a8bfc51..4715153e3bd807f5f066dacbacc9806e8f0949fc 100755 --- a/test/py/qa.qa_config_unittest.py +++ b/test/py/qa.qa_config_unittest.py @@ -205,10 +205,9 @@ class TestQaConfigLoad(unittest.TestCase): ] # Missing "disk" and "disk-growth" - check_fn("Config options 'disk' and 'disk-growth' ") + check_fn("Config option 'disks'") - testconfig["disk"] = [] - testconfig["disk-growth"] = testconfig["disk"] + testconfig["disks"] = [] # Minimal accepted configuration self._WriteConfig(filename, testconfig)