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