import qa_config
import qa_utils
import qa_error
+import qa_instance
from qa_utils import AssertEqual, AssertCommand, GetCommandOutput
AssertEqual(qa_utils.GetCommandOutput(node.primary, cmd), content)
-# "gnt-cluster info" fields
-_CIFIELD_RE = re.compile(r"^[-\s]*(?P<field>[^\s:]+):\s*(?P<value>\S.*)$")
+def _GetClusterField(field_path):
+ """Get the value of a cluster field.
-
-def _GetBoolClusterField(field):
- """Get the Boolean value of a cluster field.
-
- This function currently assumes that the field name is unique in the cluster
- configuration. An assertion checks this assumption.
-
- @type field: string
- @param field: Name of the field
- @rtype: bool
- @return: The effective value of the field
+ @type field_path: list of strings
+ @param field_path: Names of the groups/fields to navigate to get the desired
+ value, e.g. C{["Default node parameters", "oob_program"]}
+ @return: The effective value of the field (the actual type depends on the
+ chosen field)
"""
- master = qa_config.GetMasterNode()
- infocmd = "gnt-cluster info"
- info_out = qa_utils.GetCommandOutput(master.primary, infocmd)
- ret = None
- for l in info_out.splitlines():
- m = _CIFIELD_RE.match(l)
- # FIXME: There should be a way to specify a field through a hierarchy
- if m and m.group("field") == field:
- # Make sure that ignoring the hierarchy doesn't cause a double match
- assert ret is None
- ret = (m.group("value").lower() == "true")
- if ret is not None:
- return ret
- raise qa_error.Error("Field not found in cluster configuration: %s" % field)
+ assert isinstance(field_path, list)
+ assert field_path
+ ret = qa_utils.GetObjectInfo(["gnt-cluster", "info"])
+ for key in field_path:
+ ret = ret[key]
+ return ret
# Cluster-verify errors (date, "ERROR", then error code)
"gnt-cluster", "init",
"--primary-ip-version=%d" % qa_config.get("primary_ip_version", 4),
"--enabled-hypervisors=%s" % ",".join(qa_config.GetEnabledHypervisors()),
- "--enabled-storage-types=%s" %
- ",".join(qa_config.GetEnabledStorageTypes())
+ "--enabled-disk-templates=%s" %
+ ",".join(qa_config.GetEnabledDiskTemplates())
]
for spec_type in ("mem-size", "disk-size", "disk-count", "cpu-count",
AssertCommand(["gnt-cluster", "modify", "-D", param], fail=True)
-def TestClusterModifyStorageTypes():
- """gnt-cluster modify --enabled-storage-types=..."""
- default_storage_type = qa_config.GetDefaultStorageType()
+def TestClusterModifyDiskTemplates():
+ """gnt-cluster modify --enabled-disk-templates=..."""
+ enabled_disk_templates = qa_config.GetEnabledDiskTemplates()
+ default_disk_template = qa_config.GetDefaultDiskTemplate()
+
+ _TestClusterModifyDiskTemplatesArguments(default_disk_template,
+ enabled_disk_templates)
+
+ _RestoreEnabledDiskTemplates()
+ nodes = qa_config.AcquireManyNodes(2)
+
+ instance_template = enabled_disk_templates[0]
+ instance = qa_instance.CreateInstanceByDiskTemplate(nodes, instance_template)
+
+ _TestClusterModifyUnusedDiskTemplate(instance_template)
+ _TestClusterModifyUsedDiskTemplate(instance_template,
+ enabled_disk_templates)
+
+ qa_instance.TestInstanceRemove(instance)
+ _RestoreEnabledDiskTemplates()
+
+
+def _RestoreEnabledDiskTemplates():
+ """Sets the list of enabled disk templates back to the list of enabled disk
+ templates from the QA configuration. This can be used to make sure that
+ the tests that modify the list of disk templates do not interfere with
+ other tests.
+
+ """
AssertCommand(
["gnt-cluster", "modify",
- "--enabled-storage-types=%s" % default_storage_type],
+ "--enabled-disk-template=%s" %
+ ",".join(qa_config.GetEnabledDiskTemplates())],
fail=False)
- AssertCommand(["gnt-cluster", "info"])
+
+
+def _TestClusterModifyDiskTemplatesArguments(default_disk_template,
+ enabled_disk_templates):
+ """Tests argument handling of 'gnt-cluster modify' with respect to
+ the parameter '--enabled-disk-templates'. This test is independent
+ of instances.
+
+ """
AssertCommand(
["gnt-cluster", "modify",
- "--enabled-storage-types=%s" %
- ",".join(qa_config.GetEnabledStorageTypes())],
+ "--enabled-disk-template=%s" %
+ ",".join(enabled_disk_templates)],
fail=False)
- AssertCommand(["gnt-cluster", "info"])
- # bogus types
+
+ # bogus templates
AssertCommand(["gnt-cluster", "modify",
- "--enabled-storage-types=pinkbunny"],
+ "--enabled-disk-templates=pinkbunny"],
fail=True)
+
# duplicate entries do no harm
AssertCommand(
["gnt-cluster", "modify",
- "--enabled-storage-types=%s,%s" %
- (default_storage_type, default_storage_type)],
+ "--enabled-disk-templates=%s,%s" %
+ (default_disk_template, default_disk_template)],
+ fail=False)
+
+
+def _TestClusterModifyUsedDiskTemplate(instance_template,
+ enabled_disk_templates):
+ """Tests that disk templates that are currently in use by instances cannot
+ be disabled on the cluster.
+
+ """
+ # If the list of enabled disk templates contains only one template
+ # we need to add some other templates, because the list of enabled disk
+ # templates can only be set to a non-empty list.
+ new_disk_templates = list(set(enabled_disk_templates)
+ - set([instance_template]))
+ if not new_disk_templates:
+ new_disk_templates = list(set(constants.DISK_TEMPLATES)
+ - set([instance_template]))
+ AssertCommand(
+ ["gnt-cluster", "modify",
+ "--enabled-disk-templates=%s" %
+ ",".join(new_disk_templates)],
+ fail=True)
+
+
+def _TestClusterModifyUnusedDiskTemplate(instance_template):
+ """Tests that unused disk templates can be disabled safely."""
+ all_disk_templates = constants.DISK_TEMPLATES
+ AssertCommand(
+ ["gnt-cluster", "modify",
+ "--enabled-disk-templates=%s" %
+ ",".join(all_disk_templates)],
+ fail=False)
+ new_disk_templates = [instance_template]
+ AssertCommand(
+ ["gnt-cluster", "modify",
+ "--enabled-disk-templates=%s" %
+ ",".join(new_disk_templates)],
fail=False)
- AssertCommand(["gnt-cluster", "info"])
def TestClusterModifyBe():
AssertCommand(["gnt-cluster", "modify", "-B", bep])
-_START_IPOLICY_RE = re.compile(r"^(\s*)Instance policy")
-_START_ISPEC_RE = re.compile(r"^\s+-\s+(std|min|max)")
-_VALUE_RE = r"([^\s:][^:]*):\s+(\S.*)$"
-_IPOLICY_PARAM_RE = re.compile(r"^\s+-\s+" + _VALUE_RE)
-_ISPEC_VALUE_RE = re.compile(r"^\s+" + _VALUE_RE)
-
-
def _GetClusterIPolicy():
"""Return the run-time values of the cluster-level instance policy.
"min", "max", or "std"
"""
- mnode = qa_config.GetMasterNode()
- info = GetCommandOutput(mnode.primary, "gnt-cluster info")
- inside_policy = False
- end_ispec_re = None
- curr_spec = ""
- specs = {}
- policy = {}
- for line in info.splitlines():
- if inside_policy:
- # The order of the matching is important, as some REs overlap
- m = _START_ISPEC_RE.match(line)
- if m:
- curr_spec = m.group(1)
- continue
- m = _IPOLICY_PARAM_RE.match(line)
- if m:
- policy[m.group(1)] = m.group(2).strip()
- continue
- m = _ISPEC_VALUE_RE.match(line)
- if m:
- assert curr_spec
- par = m.group(1)
- if par == "memory-size":
- par = "mem-size"
- d = specs.setdefault(par, {})
- d[curr_spec] = m.group(2).strip()
- continue
- assert end_ispec_re is not None
- if end_ispec_re.match(line):
- inside_policy = False
- else:
- m = _START_IPOLICY_RE.match(line)
- if m:
- inside_policy = True
- # We stop parsing when we find the same indentation level
- re_str = r"^\s{%s}\S" % len(m.group(1))
- end_ispec_re = re.compile(re_str)
+ info = qa_utils.GetObjectInfo(["gnt-cluster", "info"])
+ policy = info["Instance policy - limits for instances"]
+ (ret_policy, ret_specs) = qa_utils.ParseIPolicy(policy)
+
# Sanity checks
- assert len(specs) > 0
- good = ("min" in d and "std" in d and "max" in d for d in specs)
- assert good, "Missing item in specs: %s" % specs
- assert len(policy) > 0
- return (policy, specs)
+ assert len(ret_specs) > 0
+ good = all("min" in d and "std" in d and "max" in d
+ for d in ret_specs.values())
+ assert good, "Missing item in specs: %s" % ret_specs
+ assert len(ret_policy) > 0
+ return (ret_policy, ret_specs)
def TestClusterModifyIPolicy():
@return: same as L{_GetClusterIPolicy}
"""
- if old_values:
- (old_policy, old_specs) = old_values
- else:
- (old_policy, old_specs) = _GetClusterIPolicy()
- if new_specs:
- cmd = ["gnt-cluster", "modify"]
- for (par, keyvals) in new_specs.items():
- if par == "spindle-use":
- # ignore spindle-use, which is not settable
- continue
- cmd += [
- "--specs-%s" % par,
- ",".join(["%s=%s" % (k, v) for (k, v) in keyvals.items()]),
- ]
- AssertCommand(cmd, fail=fail)
- # Check the new state
- (eff_policy, eff_specs) = _GetClusterIPolicy()
- AssertEqual(eff_policy, old_policy)
- if fail:
- AssertEqual(eff_specs, old_specs)
- else:
- for par in eff_specs:
- for key in eff_specs[par]:
- if par in new_specs and key in new_specs[par]:
- AssertEqual(int(eff_specs[par][key]), int(new_specs[par][key]))
- else:
- AssertEqual(int(eff_specs[par][key]), int(old_specs[par][key]))
- return (eff_policy, eff_specs)
+ build_cmd = lambda opts: ["gnt-cluster", "modify"] + opts
+ return qa_utils.TestSetISpecs(new_specs, get_policy_fn=_GetClusterIPolicy,
+ build_cmd_fn=build_cmd, fail=fail,
+ old_values=old_values)
def TestClusterModifyISpecs():
"""gnt-cluster modify --specs-*"""
- params = ["mem-size", "disk-size", "disk-count", "cpu-count", "nic-count"]
+ params = ["memory-size", "disk-size", "disk-count", "cpu-count", "nic-count"]
(cur_policy, cur_specs) = _GetClusterIPolicy()
for par in params:
test_values = [
(cur_policy, cur_specs) = TestClusterSetISpecs(new_vals, fail=not good,
old_values=cur_state)
+ # Get the ipolicy command
+ mnode = qa_config.GetMasterNode()
+ initcmd = GetCommandOutput(mnode.primary, "gnt-cluster show-ispecs-cmd")
+ modcmd = ["gnt-cluster", "modify"]
+ opts = initcmd.split()
+ assert opts[0:2] == ["gnt-cluster", "init"]
+ for k in range(2, len(opts) - 1):
+ if opts[k].startswith("--ipolicy-"):
+ assert k + 2 <= len(opts)
+ modcmd.extend(opts[k:k + 2])
+ # Re-apply the ipolicy (this should be a no-op)
+ AssertCommand(modcmd)
+ new_initcmd = GetCommandOutput(mnode.primary, "gnt-cluster show-ispecs-cmd")
+ AssertEqual(initcmd, new_initcmd)
+
def TestClusterInfo():
"""gnt-cluster info"""
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")
@return: The old value of exclusive_storage
"""
- oldvalue = _GetBoolClusterField("exclusive_storage")
+ es_path = ["Default node parameters", "exclusive_storage"]
+ oldvalue = _GetClusterField(es_path)
AssertCommand(["gnt-cluster", "modify", "--node-parameters",
"exclusive_storage=%s" % newvalue])
- effvalue = _GetBoolClusterField("exclusive_storage")
+ effvalue = _GetClusterField(es_path)
if effvalue != newvalue:
raise qa_error.Error("exclusive_storage has the wrong value: %s instead"
" of %s" % (effvalue, newvalue))