Revision dbdb0594 qa/qa_config.py

b/qa/qa_config.py
113 113
      return default
114 114

  
115 115

  
116
class _QaNode(object):
117
  __slots__ = [
118
    "primary",
119
    "secondary",
120
    "_added",
121
    "use_count",
122
    ]
123

  
124
  def __init__(self, primary, secondary):
125
    """Initializes instances of this class.
126

  
127
    """
128
    self.primary = primary
129
    self.secondary = secondary
130
    self.use_count = 0
131
    self._added = False
132

  
133
  @classmethod
134
  def FromDict(cls, data):
135
    """Creates node object from JSON dictionary.
136

  
137
    """
138
    return cls(primary=data["primary"], secondary=data.get("secondary"))
139

  
140
  def __getitem__(self, key):
141
    """Legacy dict-like interface.
142

  
143
    """
144
    if key == "primary":
145
      return self.primary
146
    elif key == "secondary":
147
      return self.secondary
148
    else:
149
      raise KeyError(key)
150

  
151
  def get(self, key, default):
152
    """Legacy dict-like interface.
153

  
154
    """
155
    try:
156
      return self[key]
157
    except KeyError:
158
      return default
159

  
160
  def Use(self):
161
    """Marks a node as being in use.
162

  
163
    """
164
    assert self.use_count >= 0
165

  
166
    self.use_count += 1
167

  
168
    return self
169

  
170
  def MarkAdded(self):
171
    """Marks node as having been added to a cluster.
172

  
173
    """
174
    assert not self._added
175
    self._added = True
176

  
177
  def MarkRemoved(self):
178
    """Marks node as having been removed from a cluster.
179

  
180
    """
181
    assert self._added
182
    self._added = False
183

  
184
  @property
185
  def added(self):
186
    """Returns whether a node is part of a cluster.
187

  
188
    """
189
    return self._added
190

  
191

  
116 192
_RESOURCE_CONVERTER = {
117 193
  "instances": _QaInstance.FromDict,
194
  "nodes": _QaNode.FromDict,
118 195
  }
119 196

  
120 197

  
......
470 547
  return GetConfig().IsTemplateSupported(templ)
471 548

  
472 549

  
473
def AcquireNode(exclude=None):
550
def AcquireNode(exclude=None, _cfg=None):
474 551
  """Returns the least used node.
475 552

  
476 553
  """
477
  master = GetMasterNode()
478
  cfg = GetConfig()
554
  if _cfg is None:
555
    cfg = GetConfig()
556
  else:
557
    cfg = _cfg
558

  
559
  master = cfg.GetMasterNode()
479 560

  
480 561
  # Filter out unwanted nodes
481 562
  # TODO: Maybe combine filters
......
486 567
  else:
487 568
    nodes = filter(lambda node: node != exclude, cfg["nodes"])
488 569

  
489
  tmp_flt = lambda node: node.get("_added", False) or node == master
490
  nodes = filter(tmp_flt, nodes)
491
  del tmp_flt
570
  nodes = filter(lambda node: node.added or node == master, nodes)
492 571

  
493
  if len(nodes) == 0:
572
  if not nodes:
494 573
    raise qa_error.OutOfNodesError("No nodes left")
495 574

  
496 575
  # Get node with least number of uses
576
  # TODO: Switch to computing sort key instead of comparing directly
497 577
  def compare(a, b):
498
    result = cmp(a.get("_count", 0), b.get("_count", 0))
578
    result = cmp(a.use_count, b.use_count)
499 579
    if result == 0:
500
      result = cmp(a["primary"], b["primary"])
580
      result = cmp(a.primary, b.primary)
501 581
    return result
502 582

  
503 583
  nodes.sort(cmp=compare)
504 584

  
505
  node = nodes[0]
506
  node["_count"] = node.get("_count", 0) + 1
507
  return node
585
  return nodes[0].Use()
508 586

  
509 587

  
510 588
def AcquireManyNodes(num, exclude=None):
......
539 617

  
540 618

  
541 619
def ReleaseNode(node):
542
  node["_count"] = node.get("_count", 0) - 1
620
  assert node.use_count > 0
621

  
622
  node.use_count -= 1
543 623

  
544 624

  
545 625
def ReleaseManyNodes(nodes):

Also available in: Unified diff