Split QA script into different modules.
[ganeti-local] / qa / qa_config.py
1 # Copyright (C) 2007 Google Inc.
2 #
3 # This program is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation; either version 2 of the License, or
6 # (at your option) any later version.
7 #
8 # This program is distributed in the hope that it will be useful, but
9 # WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 # General Public License for more details.
12 #
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software
15 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16 # 02110-1301, USA.
17
18
19 """QA configuration.
20
21 """
22
23
24 import yaml
25
26 import qa_error
27
28
29 cfg = None
30 options = None
31
32
33 def Load(path):
34   """Loads the passed configuration file.
35
36   """
37   global cfg
38
39   f = open(path, 'r')
40   try:
41     cfg = yaml.load(f.read())
42   finally:
43     f.close()
44
45   Validate()
46
47
48 def Validate():
49   if len(cfg['nodes']) < 1:
50     raise qa_error.Error("Need at least one node")
51   if len(cfg['instances']) < 1:
52     raise qa_error.Error("Need at least one instance")
53
54
55 def get(name, default=None):
56   return cfg.get(name, default)
57
58
59 def TestEnabled(test):
60   """Returns True if the given test is enabled."""
61   return cfg.get('tests', {}).get(test, False)
62
63
64 def GetMasterNode():
65   return cfg['nodes'][0]
66
67
68 def AcquireInstance():
69   """Returns an instance which isn't in use.
70
71   """
72   # Filter out unwanted instances
73   tmp_flt = lambda inst: not inst.get('_used', False)
74   instances = filter(tmp_flt, cfg['instances'])
75   del tmp_flt
76
77   if len(instances) == 0:
78     raise qa_error.OutOfInstancesError("No instances left")
79
80   inst = instances[0]
81   inst['_used'] = True
82   return inst
83
84
85 def ReleaseInstance(inst):
86   inst['_used'] = False
87
88
89 def AcquireNode(exclude=None):
90   """Returns the least used node.
91
92   """
93   master = GetMasterNode()
94
95   # Filter out unwanted nodes
96   # TODO: Maybe combine filters
97   if exclude is None:
98     nodes = cfg['nodes'][:]
99   else:
100     nodes = filter(lambda node: node != exclude, cfg['nodes'])
101
102   tmp_flt = lambda node: node.get('_added', False) or node == master
103   nodes = filter(tmp_flt, nodes)
104   del tmp_flt
105
106   if len(nodes) == 0:
107     raise qa_error.OutOfNodesError("No nodes left")
108
109   # Get node with least number of uses
110   def compare(a, b):
111     result = cmp(a.get('_count', 0), b.get('_count', 0))
112     if result == 0:
113       result = cmp(a['primary'], b['primary'])
114     return result
115
116   nodes.sort(cmp=compare)
117
118   node = nodes[0]
119   node['_count'] = node.get('_count', 0) + 1
120   return node
121
122
123 def ReleaseNode(node):
124   node['_count'] = node.get('_count', 0) - 1