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