Add UnescapeAndSplit unittest for multi-escapes
[ganeti-local] / qa / qa_config.py
1 #
2 #
3
4 # Copyright (C) 2007, 2011 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 from ganeti import utils
28 from ganeti import serializer
29 from ganeti import compat
30
31 import qa_error
32
33
34 cfg = None
35 options = None
36
37
38 def Load(path):
39   """Loads the passed configuration file.
40
41   """
42   global cfg # pylint: disable-msg=W0603
43
44   cfg = serializer.LoadJson(utils.ReadFile(path))
45
46   Validate()
47
48
49 def Validate():
50   if len(cfg['nodes']) < 1:
51     raise qa_error.Error("Need at least one node")
52   if len(cfg['instances']) < 1:
53     raise qa_error.Error("Need at least one instance")
54   if len(cfg["disk"]) != len(cfg["disk-growth"]):
55     raise qa_error.Error("Config options 'disk' and 'disk-growth' must have"
56                          " the same number of items")
57
58
59 def get(name, default=None):
60   return cfg.get(name, default)
61
62
63 def TestEnabled(tests):
64   """Returns True if the given tests are enabled.
65
66   @param tests: a single test, or a list of tests to check
67
68   """
69   if isinstance(tests, basestring):
70     tests = [tests]
71   return compat.all(cfg.get("tests", {}).get(t, True) for t in tests)
72
73
74 def GetMasterNode():
75   return cfg['nodes'][0]
76
77
78 def AcquireInstance():
79   """Returns an instance which isn't in use.
80
81   """
82   # Filter out unwanted instances
83   tmp_flt = lambda inst: not inst.get('_used', False)
84   instances = filter(tmp_flt, cfg['instances'])
85   del tmp_flt
86
87   if len(instances) == 0:
88     raise qa_error.OutOfInstancesError("No instances left")
89
90   inst = instances[0]
91   inst['_used'] = True
92   return inst
93
94
95 def ReleaseInstance(inst):
96   inst['_used'] = False
97
98
99 def AcquireNode(exclude=None):
100   """Returns the least used node.
101
102   """
103   master = GetMasterNode()
104
105   # Filter out unwanted nodes
106   # TODO: Maybe combine filters
107   if exclude is None:
108     nodes = cfg['nodes'][:]
109   elif isinstance(exclude, (list, tuple)):
110     nodes = filter(lambda node: node not in exclude, cfg['nodes'])
111   else:
112     nodes = filter(lambda node: node != exclude, cfg['nodes'])
113
114   tmp_flt = lambda node: node.get('_added', False) or node == master
115   nodes = filter(tmp_flt, nodes)
116   del tmp_flt
117
118   if len(nodes) == 0:
119     raise qa_error.OutOfNodesError("No nodes left")
120
121   # Get node with least number of uses
122   def compare(a, b):
123     result = cmp(a.get('_count', 0), b.get('_count', 0))
124     if result == 0:
125       result = cmp(a['primary'], b['primary'])
126     return result
127
128   nodes.sort(cmp=compare)
129
130   node = nodes[0]
131   node['_count'] = node.get('_count', 0) + 1
132   return node
133
134
135 def ReleaseNode(node):
136   node['_count'] = node.get('_count', 0) - 1