Revision 6a654276

b/qa/qa_config.py
40 40
_config = None
41 41

  
42 42

  
43
class _QaInstance(object):
44
  __slots__ = [
45
    "name",
46
    "nicmac",
47
    "used",
48
    "disk_template",
49
    ]
50

  
51
  def __init__(self, name, nicmac):
52
    """Initializes instances of this class.
53

  
54
    """
55
    self.name = name
56
    self.nicmac = nicmac
57
    self.used = None
58
    self.disk_template = None
59

  
60
  @classmethod
61
  def FromDict(cls, data):
62
    """Creates instance object from JSON dictionary.
63

  
64
    """
65
    nicmac = []
66

  
67
    macaddr = data.get("nic.mac/0")
68
    if macaddr:
69
      nicmac.append(macaddr)
70

  
71
    return cls(name=data["name"], nicmac=nicmac)
72

  
73
  def __getitem__(self, key):
74
    """Legacy dict-like interface.
75

  
76
    """
77
    if key == "name":
78
      return self.name
79
    else:
80
      raise KeyError(key)
81

  
82
  def get(self, key, default):
83
    """Legacy dict-like interface.
84

  
85
    """
86
    try:
87
      return self[key]
88
    except KeyError:
89
      return default
90

  
91
  def GetNicMacAddr(self, idx, default):
92
    """Returns MAC address for NIC.
93

  
94
    @type idx: int
95
    @param idx: NIC index
96
    @param default: Default value
97

  
98
    """
99
    if len(self.nicmac) > idx:
100
      return self.nicmac[idx]
101
    else:
102
      return default
103

  
104

  
105
_RESOURCE_CONVERTER = {
106
  "instances": _QaInstance.FromDict,
107
  }
108

  
109

  
110
def _ConvertResources((key, value)):
111
  """Converts cluster resources in configuration to Python objects.
112

  
113
  """
114
  fn = _RESOURCE_CONVERTER.get(key, None)
115
  if fn:
116
    return (key, map(fn, value))
117
  else:
118
    return (key, value)
119

  
120

  
43 121
class _QaConfig(object):
44 122
  def __init__(self, data):
45 123
    """Initializes instances of this class.
......
61 139
    """
62 140
    data = serializer.LoadJson(utils.ReadFile(filename))
63 141

  
64
    result = cls(data)
142
    result = cls(dict(map(_ConvertResources,
143
                          data.items()))) # pylint: disable=E1103
65 144
    result.Validate()
66 145

  
67 146
    return result
......
308 387
  """Returns MAC address for instance's network interface.
309 388

  
310 389
  """
311
  return inst.get("nic.mac/0", default)
390
  return inst.GetNicMacAddr(0, default)
312 391

  
313 392

  
314 393
def GetMasterNode():
......
318 397
  return GetConfig().GetMasterNode()
319 398

  
320 399

  
321
def AcquireInstance():
400
def AcquireInstance(_cfg=None):
322 401
  """Returns an instance which isn't in use.
323 402

  
324 403
  """
404
  if _cfg is None:
405
    cfg = GetConfig()
406
  else:
407
    cfg = _cfg
408

  
325 409
  # Filter out unwanted instances
326
  tmp_flt = lambda inst: not inst.get("_used", False)
327
  instances = filter(tmp_flt, GetConfig()["instances"])
328
  del tmp_flt
410
  instances = filter(lambda inst: not inst.used, cfg["instances"])
329 411

  
330
  if len(instances) == 0:
412
  if not instances:
331 413
    raise qa_error.OutOfInstancesError("No instances left")
332 414

  
333 415
  inst = instances[0]
334
  inst["_used"] = True
335
  inst["_template"] = None
416

  
417
  assert not inst.used
418
  assert inst.disk_template is None
419

  
420
  inst.used = True
421

  
336 422
  return inst
337 423

  
338 424

  
339 425
def ReleaseInstance(inst):
340
  inst["_used"] = False
426
  inst.used = False
427
  inst.disk_template = None
341 428

  
342 429

  
343 430
def GetInstanceTemplate(inst):
344 431
  """Return the disk template of an instance.
345 432

  
346 433
  """
347
  templ = inst["_template"]
434
  templ = inst.disk_template
348 435
  assert templ is not None
349 436
  return templ
350 437

  
......
353 440
  """Set the disk template for an instance.
354 441

  
355 442
  """
356
  inst["_template"] = template
443
  inst.disk_template = template
357 444

  
358 445

  
359 446
def SetExclusiveStorage(value):
b/test/py/qa.qa_config_unittest.py
25 25
import tempfile
26 26
import shutil
27 27
import os
28
import operator
28 29

  
29 30
from ganeti import utils
30 31
from ganeti import serializer
......
272 273
        else:
273 274
          self.assertTrue(self.config.IsTemplateSupported(template))
274 275

  
276
  def testInstanceConversion(self):
277
    self.assertTrue(isinstance(self.config["instances"][0],
278
                               qa_config._QaInstance))
279

  
280
  def testAcquireAndReleaseInstance(self):
281
    self.assertFalse(compat.any(map(operator.attrgetter("used"),
282
                                    self.config["instances"])))
283

  
284
    inst = qa_config.AcquireInstance(_cfg=self.config)
285
    self.assertTrue(inst.used)
286
    self.assertTrue(inst.disk_template is None)
287

  
288
    qa_config.ReleaseInstance(inst)
289

  
290
    self.assertFalse(inst.used)
291
    self.assertTrue(inst.disk_template is None)
292

  
293
    self.assertFalse(compat.any(map(operator.attrgetter("used"),
294
                                    self.config["instances"])))
295

  
296
  def testAcquireInstanceTooMany(self):
297
    # Acquire all instances
298
    for _ in range(len(self.config["instances"])):
299
      inst = qa_config.AcquireInstance(_cfg=self.config)
300
      self.assertTrue(inst.used)
301
      self.assertTrue(inst.disk_template is None)
302

  
303
    # The next acquisition must fail
304
    self.assertRaises(qa_error.OutOfInstancesError,
305
                      qa_config.AcquireInstance, _cfg=self.config)
306

  
275 307

  
276 308
if __name__ == "__main__":
277 309
  testutils.GanetiTestProgram()

Also available in: Unified diff