Revision 0e79564a qa/qa_cluster.py
b/qa/qa_cluster.py | ||
---|---|---|
63 | 63 |
AssertEqual(qa_utils.GetCommandOutput(node.primary, cmd), content) |
64 | 64 |
|
65 | 65 |
|
66 |
# "gnt-cluster info" fields
|
|
67 |
_CIFIELD_RE = re.compile(r"^[-\s]*(?P<field>[^\s:]+):\s*(?P<value>\S.*)$")
|
|
66 |
def _GetClusterField(field_path):
|
|
67 |
"""Get the value of a cluster field.
|
|
68 | 68 |
|
69 |
|
|
70 |
def _GetBoolClusterField(field): |
|
71 |
"""Get the Boolean value of a cluster field. |
|
72 |
|
|
73 |
This function currently assumes that the field name is unique in the cluster |
|
74 |
configuration. An assertion checks this assumption. |
|
75 |
|
|
76 |
@type field: string |
|
77 |
@param field: Name of the field |
|
78 |
@rtype: bool |
|
79 |
@return: The effective value of the field |
|
69 |
@type field_path: list of strings |
|
70 |
@param field_path: Names of the groups/fields to navigate to get the desired |
|
71 |
value, e.g. C{["Default node parameters", "oob_program"]} |
|
72 |
@return: The effective value of the field (the actual type depends on the |
|
73 |
chosen field) |
|
80 | 74 |
|
81 | 75 |
""" |
82 |
master = qa_config.GetMasterNode() |
|
83 |
infocmd = "gnt-cluster info" |
|
84 |
info_out = qa_utils.GetCommandOutput(master.primary, infocmd) |
|
85 |
ret = None |
|
86 |
for l in info_out.splitlines(): |
|
87 |
m = _CIFIELD_RE.match(l) |
|
88 |
# FIXME: There should be a way to specify a field through a hierarchy |
|
89 |
if m and m.group("field") == field: |
|
90 |
# Make sure that ignoring the hierarchy doesn't cause a double match |
|
91 |
assert ret is None |
|
92 |
ret = (m.group("value").lower() == "true") |
|
93 |
if ret is not None: |
|
94 |
return ret |
|
95 |
raise qa_error.Error("Field not found in cluster configuration: %s" % field) |
|
76 |
assert isinstance(field_path, list) |
|
77 |
assert field_path |
|
78 |
ret = qa_utils.GetObjectInfo(["gnt-cluster", "info"]) |
|
79 |
for key in field_path: |
|
80 |
ret = ret[key] |
|
81 |
return ret |
|
96 | 82 |
|
97 | 83 |
|
98 | 84 |
# Cluster-verify errors (date, "ERROR", then error code) |
... | ... | |
467 | 453 |
AssertCommand(["gnt-cluster", "modify", "-B", bep]) |
468 | 454 |
|
469 | 455 |
|
470 |
_START_IPOLICY_RE = re.compile(r"^(\s*)Instance policy") |
|
471 |
_START_ISPEC_RE = re.compile(r"^\s+-\s+(std|min|max)") |
|
472 |
_VALUE_RE = r"([^\s:][^:]*):\s+(\S.*)$" |
|
473 |
_IPOLICY_PARAM_RE = re.compile(r"^\s+-\s+" + _VALUE_RE) |
|
474 |
_ISPEC_VALUE_RE = re.compile(r"^\s+" + _VALUE_RE) |
|
475 |
|
|
476 |
|
|
477 | 456 |
def _GetClusterIPolicy(): |
478 | 457 |
"""Return the run-time values of the cluster-level instance policy. |
479 | 458 |
|
... | ... | |
484 | 463 |
"min", "max", or "std" |
485 | 464 |
|
486 | 465 |
""" |
487 |
mnode = qa_config.GetMasterNode() |
|
488 |
info = GetCommandOutput(mnode.primary, "gnt-cluster info") |
|
489 |
inside_policy = False |
|
490 |
end_ispec_re = None |
|
491 |
curr_spec = "" |
|
492 |
specs = {} |
|
493 |
policy = {} |
|
494 |
for line in info.splitlines(): |
|
495 |
if inside_policy: |
|
496 |
# The order of the matching is important, as some REs overlap |
|
497 |
m = _START_ISPEC_RE.match(line) |
|
498 |
if m: |
|
499 |
curr_spec = m.group(1) |
|
500 |
continue |
|
501 |
m = _IPOLICY_PARAM_RE.match(line) |
|
502 |
if m: |
|
503 |
policy[m.group(1)] = m.group(2).strip() |
|
504 |
continue |
|
505 |
m = _ISPEC_VALUE_RE.match(line) |
|
506 |
if m: |
|
507 |
assert curr_spec |
|
508 |
par = m.group(1) |
|
466 |
info = qa_utils.GetObjectInfo(["gnt-cluster", "info"]) |
|
467 |
policy = info["Instance policy - limits for instances"] |
|
468 |
ret_specs = {} |
|
469 |
ret_policy = {} |
|
470 |
for (key, val) in policy.items(): |
|
471 |
if key in constants.IPOLICY_ISPECS: |
|
472 |
for (par, pval) in val.items(): |
|
509 | 473 |
if par == "memory-size": |
510 | 474 |
par = "mem-size" |
511 |
d = specs.setdefault(par, {}) |
|
512 |
d[curr_spec] = m.group(2).strip() |
|
513 |
continue |
|
514 |
assert end_ispec_re is not None |
|
515 |
if end_ispec_re.match(line): |
|
516 |
inside_policy = False |
|
475 |
d = ret_specs.setdefault(par, {}) |
|
476 |
d[key] = pval |
|
517 | 477 |
else: |
518 |
m = _START_IPOLICY_RE.match(line) |
|
519 |
if m: |
|
520 |
inside_policy = True |
|
521 |
# We stop parsing when we find the same indentation level |
|
522 |
re_str = r"^\s{%s}\S" % len(m.group(1)) |
|
523 |
end_ispec_re = re.compile(re_str) |
|
478 |
ret_policy[key] = val |
|
479 |
|
|
524 | 480 |
# Sanity checks |
525 |
assert len(specs) > 0 |
|
526 |
good = ("min" in d and "std" in d and "max" in d for d in specs) |
|
527 |
assert good, "Missing item in specs: %s" % specs |
|
528 |
assert len(policy) > 0 |
|
529 |
return (policy, specs)
|
|
481 |
assert len(ret_specs) > 0
|
|
482 |
good = ("min" in d and "std" in d and "max" in d for d in ret_specs)
|
|
483 |
assert good, "Missing item in specs: %s" % ret_specs
|
|
484 |
assert len(ret_policy) > 0
|
|
485 |
return (ret_policy, ret_specs)
|
|
530 | 486 |
|
531 | 487 |
|
532 | 488 |
def TestClusterModifyIPolicy(): |
... | ... | |
912 | 868 |
@return: The old value of exclusive_storage |
913 | 869 |
|
914 | 870 |
""" |
915 |
oldvalue = _GetBoolClusterField("exclusive_storage") |
|
871 |
es_path = ["Default node parameters", "exclusive_storage"] |
|
872 |
oldvalue = _GetClusterField(es_path) |
|
916 | 873 |
AssertCommand(["gnt-cluster", "modify", "--node-parameters", |
917 | 874 |
"exclusive_storage=%s" % newvalue]) |
918 |
effvalue = _GetBoolClusterField("exclusive_storage")
|
|
875 |
effvalue = _GetClusterField(es_path)
|
|
919 | 876 |
if effvalue != newvalue: |
920 | 877 |
raise qa_error.Error("exclusive_storage has the wrong value: %s instead" |
921 | 878 |
" of %s" % (effvalue, newvalue)) |
Also available in: Unified diff