Statistics
| Branch: | Tag: | Revision:

root / qa / qa_config.py @ 6d3d13ab

History | View | Annotate | Download (7.8 kB)

1 c68d1f43 Michael Hanselmann
#
2 c68d1f43 Michael Hanselmann
#
3 c68d1f43 Michael Hanselmann
4 906a0346 Bernardo Dal Seno
# Copyright (C) 2007, 2011, 2012, 2013 Google Inc.
5 cec9845c Michael Hanselmann
#
6 cec9845c Michael Hanselmann
# This program is free software; you can redistribute it and/or modify
7 cec9845c Michael Hanselmann
# it under the terms of the GNU General Public License as published by
8 cec9845c Michael Hanselmann
# the Free Software Foundation; either version 2 of the License, or
9 cec9845c Michael Hanselmann
# (at your option) any later version.
10 cec9845c Michael Hanselmann
#
11 cec9845c Michael Hanselmann
# This program is distributed in the hope that it will be useful, but
12 cec9845c Michael Hanselmann
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 cec9845c Michael Hanselmann
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 cec9845c Michael Hanselmann
# General Public License for more details.
15 cec9845c Michael Hanselmann
#
16 cec9845c Michael Hanselmann
# You should have received a copy of the GNU General Public License
17 cec9845c Michael Hanselmann
# along with this program; if not, write to the Free Software
18 cec9845c Michael Hanselmann
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 cec9845c Michael Hanselmann
# 02110-1301, USA.
20 cec9845c Michael Hanselmann
21 cec9845c Michael Hanselmann
22 cec9845c Michael Hanselmann
"""QA configuration.
23 cec9845c Michael Hanselmann

24 cec9845c Michael Hanselmann
"""
25 cec9845c Michael Hanselmann
26 c9e05005 Michael Hanselmann
import os
27 cec9845c Michael Hanselmann
28 e7b6183b Michael Hanselmann
from ganeti import constants
29 a705dc05 Michael Hanselmann
from ganeti import utils
30 a705dc05 Michael Hanselmann
from ganeti import serializer
31 7d88f255 Iustin Pop
from ganeti import compat
32 cec9845c Michael Hanselmann
33 cec9845c Michael Hanselmann
import qa_error
34 cec9845c Michael Hanselmann
35 cec9845c Michael Hanselmann
36 c9e05005 Michael Hanselmann
_INSTANCE_CHECK_KEY = "instance-check"
37 e7b6183b Michael Hanselmann
_ENABLED_HV_KEY = "enabled-hypervisors"
38 6a0f22e1 Bernardo Dal Seno
# Key to store the cluster-wide run-time value of the exclusive storage flag
39 6a0f22e1 Bernardo Dal Seno
_EXCLUSIVE_STORAGE_KEY = "_exclusive_storage"
40 c9e05005 Michael Hanselmann
41 c9e05005 Michael Hanselmann
42 cf632f3e Bernardo Dal Seno
cfg = {}
43 cec9845c Michael Hanselmann
options = None
44 cec9845c Michael Hanselmann
45 cec9845c Michael Hanselmann
46 cec9845c Michael Hanselmann
def Load(path):
47 cec9845c Michael Hanselmann
  """Loads the passed configuration file.
48 cec9845c Michael Hanselmann

49 cec9845c Michael Hanselmann
  """
50 b459a848 Andrea Spadaccini
  global cfg # pylint: disable=W0603
51 cec9845c Michael Hanselmann
52 a705dc05 Michael Hanselmann
  cfg = serializer.LoadJson(utils.ReadFile(path))
53 cec9845c Michael Hanselmann
54 cec9845c Michael Hanselmann
  Validate()
55 cec9845c Michael Hanselmann
56 cec9845c Michael Hanselmann
57 cec9845c Michael Hanselmann
def Validate():
58 d0c8c01d Iustin Pop
  if len(cfg["nodes"]) < 1:
59 cec9845c Michael Hanselmann
    raise qa_error.Error("Need at least one node")
60 d0c8c01d Iustin Pop
  if len(cfg["instances"]) < 1:
61 cec9845c Michael Hanselmann
    raise qa_error.Error("Need at least one instance")
62 1d693311 Michael Hanselmann
  if len(cfg["disk"]) != len(cfg["disk-growth"]):
63 1d693311 Michael Hanselmann
    raise qa_error.Error("Config options 'disk' and 'disk-growth' must have"
64 1d693311 Michael Hanselmann
                         " the same number of items")
65 cec9845c Michael Hanselmann
66 c9e05005 Michael Hanselmann
  check = GetInstanceCheckScript()
67 c9e05005 Michael Hanselmann
  if check:
68 c9e05005 Michael Hanselmann
    try:
69 c9e05005 Michael Hanselmann
      os.stat(check)
70 c9e05005 Michael Hanselmann
    except EnvironmentError, err:
71 c9e05005 Michael Hanselmann
      raise qa_error.Error("Can't find instance check script '%s': %s" %
72 c9e05005 Michael Hanselmann
                           (check, err))
73 c9e05005 Michael Hanselmann
74 e7b6183b Michael Hanselmann
  enabled_hv = frozenset(GetEnabledHypervisors())
75 e7b6183b Michael Hanselmann
  if not enabled_hv:
76 e7b6183b Michael Hanselmann
    raise qa_error.Error("No hypervisor is enabled")
77 e7b6183b Michael Hanselmann
78 e7b6183b Michael Hanselmann
  difference = enabled_hv - constants.HYPER_TYPES
79 e7b6183b Michael Hanselmann
  if difference:
80 e7b6183b Michael Hanselmann
    raise qa_error.Error("Unknown hypervisor(s) enabled: %s" %
81 e7b6183b Michael Hanselmann
                         utils.CommaJoin(difference))
82 e7b6183b Michael Hanselmann
83 cec9845c Michael Hanselmann
84 cec9845c Michael Hanselmann
def get(name, default=None):
85 cf632f3e Bernardo Dal Seno
  return cfg.get(name, default)
86 cec9845c Michael Hanselmann
87 cec9845c Michael Hanselmann
88 a0c3e726 Michael Hanselmann
class Either:
89 a0c3e726 Michael Hanselmann
  def __init__(self, tests):
90 a0c3e726 Michael Hanselmann
    """Initializes this class.
91 a0c3e726 Michael Hanselmann

92 a0c3e726 Michael Hanselmann
    @type tests: list or string
93 a0c3e726 Michael Hanselmann
    @param tests: List of test names
94 a0c3e726 Michael Hanselmann
    @see: L{TestEnabled} for details
95 a0c3e726 Michael Hanselmann

96 a0c3e726 Michael Hanselmann
    """
97 a0c3e726 Michael Hanselmann
    self.tests = tests
98 a0c3e726 Michael Hanselmann
99 a0c3e726 Michael Hanselmann
100 a0c3e726 Michael Hanselmann
def _MakeSequence(value):
101 a0c3e726 Michael Hanselmann
  """Make sequence of single argument.
102 a0c3e726 Michael Hanselmann

103 a0c3e726 Michael Hanselmann
  If the single argument is not already a list or tuple, a list with the
104 a0c3e726 Michael Hanselmann
  argument as a single item is returned.
105 a0c3e726 Michael Hanselmann

106 a0c3e726 Michael Hanselmann
  """
107 a0c3e726 Michael Hanselmann
  if isinstance(value, (list, tuple)):
108 a0c3e726 Michael Hanselmann
    return value
109 a0c3e726 Michael Hanselmann
  else:
110 a0c3e726 Michael Hanselmann
    return [value]
111 a0c3e726 Michael Hanselmann
112 a0c3e726 Michael Hanselmann
113 a0c3e726 Michael Hanselmann
def _TestEnabledInner(check_fn, names, fn):
114 a0c3e726 Michael Hanselmann
  """Evaluate test conditions.
115 a0c3e726 Michael Hanselmann

116 a0c3e726 Michael Hanselmann
  @type check_fn: callable
117 a0c3e726 Michael Hanselmann
  @param check_fn: Callback to check whether a test is enabled
118 a0c3e726 Michael Hanselmann
  @type names: sequence or string
119 a0c3e726 Michael Hanselmann
  @param names: Test name(s)
120 a0c3e726 Michael Hanselmann
  @type fn: callable
121 a0c3e726 Michael Hanselmann
  @param fn: Aggregation function
122 a0c3e726 Michael Hanselmann
  @rtype: bool
123 a0c3e726 Michael Hanselmann
  @return: Whether test is enabled
124 a0c3e726 Michael Hanselmann

125 a0c3e726 Michael Hanselmann
  """
126 a0c3e726 Michael Hanselmann
  names = _MakeSequence(names)
127 a0c3e726 Michael Hanselmann
128 a0c3e726 Michael Hanselmann
  result = []
129 a0c3e726 Michael Hanselmann
130 a0c3e726 Michael Hanselmann
  for name in names:
131 a0c3e726 Michael Hanselmann
    if isinstance(name, Either):
132 a0c3e726 Michael Hanselmann
      value = _TestEnabledInner(check_fn, name.tests, compat.any)
133 a0c3e726 Michael Hanselmann
    elif isinstance(name, (list, tuple)):
134 a0c3e726 Michael Hanselmann
      value = _TestEnabledInner(check_fn, name, compat.all)
135 a0c3e726 Michael Hanselmann
    else:
136 a0c3e726 Michael Hanselmann
      value = check_fn(name)
137 a0c3e726 Michael Hanselmann
138 a0c3e726 Michael Hanselmann
    result.append(value)
139 a0c3e726 Michael Hanselmann
140 a0c3e726 Michael Hanselmann
  return fn(result)
141 a0c3e726 Michael Hanselmann
142 a0c3e726 Michael Hanselmann
143 a0c3e726 Michael Hanselmann
def TestEnabled(tests, _cfg=None):
144 7d88f255 Iustin Pop
  """Returns True if the given tests are enabled.
145 7d88f255 Iustin Pop

146 a0c3e726 Michael Hanselmann
  @param tests: A single test as a string, or a list of tests to check; can
147 a0c3e726 Michael Hanselmann
    contain L{Either} for OR conditions, AND is default
148 1010ec70 Michael Hanselmann

149 1010ec70 Michael Hanselmann
  """
150 a0c3e726 Michael Hanselmann
  if _cfg is None:
151 a0c3e726 Michael Hanselmann
    _cfg = cfg
152 59a8fe48 Michael Hanselmann
153 59a8fe48 Michael Hanselmann
  # Get settings for all tests
154 cf632f3e Bernardo Dal Seno
  cfg_tests = _cfg.get("tests", {})
155 59a8fe48 Michael Hanselmann
156 59a8fe48 Michael Hanselmann
  # Get default setting
157 a0c3e726 Michael Hanselmann
  default = cfg_tests.get("default", True)
158 59a8fe48 Michael Hanselmann
159 a0c3e726 Michael Hanselmann
  return _TestEnabledInner(lambda name: cfg_tests.get(name, default),
160 a0c3e726 Michael Hanselmann
                           tests, compat.all)
161 cec9845c Michael Hanselmann
162 cec9845c Michael Hanselmann
163 c9e05005 Michael Hanselmann
def GetInstanceCheckScript():
164 c9e05005 Michael Hanselmann
  """Returns path to instance check script or C{None}.
165 c9e05005 Michael Hanselmann

166 c9e05005 Michael Hanselmann
  """
167 cf632f3e Bernardo Dal Seno
  return cfg.get(_INSTANCE_CHECK_KEY, None)
168 c9e05005 Michael Hanselmann
169 c9e05005 Michael Hanselmann
170 e7b6183b Michael Hanselmann
def GetEnabledHypervisors():
171 e7b6183b Michael Hanselmann
  """Returns list of enabled hypervisors.
172 e7b6183b Michael Hanselmann

173 e7b6183b Michael Hanselmann
  @rtype: list
174 e7b6183b Michael Hanselmann

175 e7b6183b Michael Hanselmann
  """
176 e7b6183b Michael Hanselmann
  try:
177 e7b6183b Michael Hanselmann
    value = cfg[_ENABLED_HV_KEY]
178 e7b6183b Michael Hanselmann
  except KeyError:
179 e7b6183b Michael Hanselmann
    return [constants.DEFAULT_ENABLED_HYPERVISOR]
180 e7b6183b Michael Hanselmann
  else:
181 e7b6183b Michael Hanselmann
    if isinstance(value, basestring):
182 e7b6183b Michael Hanselmann
      # The configuration key ("enabled-hypervisors") implies there can be
183 e7b6183b Michael Hanselmann
      # multiple values. Multiple hypervisors are comma-separated on the
184 e7b6183b Michael Hanselmann
      # command line option to "gnt-cluster init", so we need to handle them
185 e7b6183b Michael Hanselmann
      # equally here.
186 e7b6183b Michael Hanselmann
      return value.split(",")
187 e7b6183b Michael Hanselmann
    else:
188 e7b6183b Michael Hanselmann
      return value
189 e7b6183b Michael Hanselmann
190 e7b6183b Michael Hanselmann
191 e7b6183b Michael Hanselmann
def GetDefaultHypervisor():
192 e7b6183b Michael Hanselmann
  """Returns the default hypervisor to be used.
193 e7b6183b Michael Hanselmann

194 e7b6183b Michael Hanselmann
  """
195 e7b6183b Michael Hanselmann
  return GetEnabledHypervisors()[0]
196 e7b6183b Michael Hanselmann
197 e7b6183b Michael Hanselmann
198 f346a7d9 Michael Hanselmann
def GetInstanceNicMac(inst, default=None):
199 f346a7d9 Michael Hanselmann
  """Returns MAC address for instance's network interface.
200 f346a7d9 Michael Hanselmann

201 f346a7d9 Michael Hanselmann
  """
202 f346a7d9 Michael Hanselmann
  return inst.get("nic.mac/0", default)
203 f346a7d9 Michael Hanselmann
204 f346a7d9 Michael Hanselmann
205 cec9845c Michael Hanselmann
def GetMasterNode():
206 d0c8c01d Iustin Pop
  return cfg["nodes"][0]
207 cec9845c Michael Hanselmann
208 cec9845c Michael Hanselmann
209 cec9845c Michael Hanselmann
def AcquireInstance():
210 cec9845c Michael Hanselmann
  """Returns an instance which isn't in use.
211 cec9845c Michael Hanselmann

212 cec9845c Michael Hanselmann
  """
213 cec9845c Michael Hanselmann
  # Filter out unwanted instances
214 d0c8c01d Iustin Pop
  tmp_flt = lambda inst: not inst.get("_used", False)
215 d0c8c01d Iustin Pop
  instances = filter(tmp_flt, cfg["instances"])
216 cec9845c Michael Hanselmann
  del tmp_flt
217 cec9845c Michael Hanselmann
218 cec9845c Michael Hanselmann
  if len(instances) == 0:
219 cec9845c Michael Hanselmann
    raise qa_error.OutOfInstancesError("No instances left")
220 cec9845c Michael Hanselmann
221 cec9845c Michael Hanselmann
  inst = instances[0]
222 d0c8c01d Iustin Pop
  inst["_used"] = True
223 906a0346 Bernardo Dal Seno
  inst["_template"] = None
224 cec9845c Michael Hanselmann
  return inst
225 cec9845c Michael Hanselmann
226 cec9845c Michael Hanselmann
227 cec9845c Michael Hanselmann
def ReleaseInstance(inst):
228 d0c8c01d Iustin Pop
  inst["_used"] = False
229 cec9845c Michael Hanselmann
230 cec9845c Michael Hanselmann
231 906a0346 Bernardo Dal Seno
def GetInstanceTemplate(inst):
232 906a0346 Bernardo Dal Seno
  """Return the disk template of an instance.
233 906a0346 Bernardo Dal Seno

234 906a0346 Bernardo Dal Seno
  """
235 906a0346 Bernardo Dal Seno
  templ = inst["_template"]
236 906a0346 Bernardo Dal Seno
  assert templ is not None
237 906a0346 Bernardo Dal Seno
  return templ
238 906a0346 Bernardo Dal Seno
239 906a0346 Bernardo Dal Seno
240 906a0346 Bernardo Dal Seno
def SetInstanceTemplate(inst, template):
241 906a0346 Bernardo Dal Seno
  """Set the disk template for an instance.
242 906a0346 Bernardo Dal Seno

243 906a0346 Bernardo Dal Seno
  """
244 906a0346 Bernardo Dal Seno
  inst["_template"] = template
245 906a0346 Bernardo Dal Seno
246 906a0346 Bernardo Dal Seno
247 6a0f22e1 Bernardo Dal Seno
def SetExclusiveStorage(value):
248 6a0f22e1 Bernardo Dal Seno
  """Set the expected value of the exclusive_storage flag for the cluster.
249 6a0f22e1 Bernardo Dal Seno

250 6a0f22e1 Bernardo Dal Seno
  """
251 6a0f22e1 Bernardo Dal Seno
  cfg[_EXCLUSIVE_STORAGE_KEY] = bool(value)
252 6a0f22e1 Bernardo Dal Seno
253 6a0f22e1 Bernardo Dal Seno
254 6a0f22e1 Bernardo Dal Seno
def GetExclusiveStorage():
255 6a0f22e1 Bernardo Dal Seno
  """Get the expected value of the exclusive_storage flag for the cluster.
256 6a0f22e1 Bernardo Dal Seno

257 6a0f22e1 Bernardo Dal Seno
  """
258 6a0f22e1 Bernardo Dal Seno
  val = cfg.get(_EXCLUSIVE_STORAGE_KEY)
259 6a0f22e1 Bernardo Dal Seno
  assert val is not None
260 6a0f22e1 Bernardo Dal Seno
  return val
261 6a0f22e1 Bernardo Dal Seno
262 6a0f22e1 Bernardo Dal Seno
263 27eba428 Bernardo Dal Seno
def IsTemplateSupported(templ):
264 27eba428 Bernardo Dal Seno
  """Is the given templated supported by the current configuration?
265 27eba428 Bernardo Dal Seno

266 27eba428 Bernardo Dal Seno
  """
267 27eba428 Bernardo Dal Seno
  if GetExclusiveStorage():
268 27eba428 Bernardo Dal Seno
    return templ in constants.DTS_EXCL_STORAGE
269 27eba428 Bernardo Dal Seno
  else:
270 27eba428 Bernardo Dal Seno
    return True
271 27eba428 Bernardo Dal Seno
272 27eba428 Bernardo Dal Seno
273 cec9845c Michael Hanselmann
def AcquireNode(exclude=None):
274 cec9845c Michael Hanselmann
  """Returns the least used node.
275 cec9845c Michael Hanselmann

276 cec9845c Michael Hanselmann
  """
277 cec9845c Michael Hanselmann
  master = GetMasterNode()
278 cec9845c Michael Hanselmann
279 cec9845c Michael Hanselmann
  # Filter out unwanted nodes
280 cec9845c Michael Hanselmann
  # TODO: Maybe combine filters
281 cec9845c Michael Hanselmann
  if exclude is None:
282 d0c8c01d Iustin Pop
    nodes = cfg["nodes"][:]
283 4b62db14 Michael Hanselmann
  elif isinstance(exclude, (list, tuple)):
284 d0c8c01d Iustin Pop
    nodes = filter(lambda node: node not in exclude, cfg["nodes"])
285 cec9845c Michael Hanselmann
  else:
286 d0c8c01d Iustin Pop
    nodes = filter(lambda node: node != exclude, cfg["nodes"])
287 cec9845c Michael Hanselmann
288 d0c8c01d Iustin Pop
  tmp_flt = lambda node: node.get("_added", False) or node == master
289 cec9845c Michael Hanselmann
  nodes = filter(tmp_flt, nodes)
290 cec9845c Michael Hanselmann
  del tmp_flt
291 cec9845c Michael Hanselmann
292 cec9845c Michael Hanselmann
  if len(nodes) == 0:
293 cec9845c Michael Hanselmann
    raise qa_error.OutOfNodesError("No nodes left")
294 cec9845c Michael Hanselmann
295 cec9845c Michael Hanselmann
  # Get node with least number of uses
296 cec9845c Michael Hanselmann
  def compare(a, b):
297 d0c8c01d Iustin Pop
    result = cmp(a.get("_count", 0), b.get("_count", 0))
298 cec9845c Michael Hanselmann
    if result == 0:
299 d0c8c01d Iustin Pop
      result = cmp(a["primary"], b["primary"])
300 cec9845c Michael Hanselmann
    return result
301 cec9845c Michael Hanselmann
302 cec9845c Michael Hanselmann
  nodes.sort(cmp=compare)
303 cec9845c Michael Hanselmann
304 cec9845c Michael Hanselmann
  node = nodes[0]
305 d0c8c01d Iustin Pop
  node["_count"] = node.get("_count", 0) + 1
306 cec9845c Michael Hanselmann
  return node
307 cec9845c Michael Hanselmann
308 cec9845c Michael Hanselmann
309 7d4f1b45 Bernardo Dal Seno
def AcquireManyNodes(num, exclude=None):
310 7d4f1b45 Bernardo Dal Seno
  """Return the least used nodes.
311 7d4f1b45 Bernardo Dal Seno

312 7d4f1b45 Bernardo Dal Seno
  @type num: int
313 7d4f1b45 Bernardo Dal Seno
  @param num: Number of nodes; can be 0.
314 7d4f1b45 Bernardo Dal Seno
  @type exclude: list of nodes or C{None}
315 7d4f1b45 Bernardo Dal Seno
  @param exclude: nodes to be excluded from the choice
316 7d4f1b45 Bernardo Dal Seno
  @rtype: list of nodes
317 7d4f1b45 Bernardo Dal Seno
  @return: C{num} different nodes
318 7d4f1b45 Bernardo Dal Seno

319 7d4f1b45 Bernardo Dal Seno
  """
320 7d4f1b45 Bernardo Dal Seno
  nodes = []
321 7d4f1b45 Bernardo Dal Seno
  if exclude is None:
322 7d4f1b45 Bernardo Dal Seno
    exclude = []
323 7d4f1b45 Bernardo Dal Seno
  elif isinstance(exclude, (list, tuple)):
324 7d4f1b45 Bernardo Dal Seno
    # Don't modify the incoming argument
325 7d4f1b45 Bernardo Dal Seno
    exclude = list(exclude)
326 7d4f1b45 Bernardo Dal Seno
  else:
327 7d4f1b45 Bernardo Dal Seno
    exclude = [exclude]
328 7d4f1b45 Bernardo Dal Seno
329 7d4f1b45 Bernardo Dal Seno
  try:
330 7d4f1b45 Bernardo Dal Seno
    for _ in range(0, num):
331 7d4f1b45 Bernardo Dal Seno
      n = AcquireNode(exclude=exclude)
332 7d4f1b45 Bernardo Dal Seno
      nodes.append(n)
333 7d4f1b45 Bernardo Dal Seno
      exclude.append(n)
334 7d4f1b45 Bernardo Dal Seno
  except qa_error.OutOfNodesError:
335 7d4f1b45 Bernardo Dal Seno
    ReleaseManyNodes(nodes)
336 7d4f1b45 Bernardo Dal Seno
    raise
337 7d4f1b45 Bernardo Dal Seno
  return nodes
338 7d4f1b45 Bernardo Dal Seno
339 7d4f1b45 Bernardo Dal Seno
340 cec9845c Michael Hanselmann
def ReleaseNode(node):
341 d0c8c01d Iustin Pop
  node["_count"] = node.get("_count", 0) - 1
342 7d4f1b45 Bernardo Dal Seno
343 7d4f1b45 Bernardo Dal Seno
344 7d4f1b45 Bernardo Dal Seno
def ReleaseManyNodes(nodes):
345 7d4f1b45 Bernardo Dal Seno
  for n in nodes:
346 7d4f1b45 Bernardo Dal Seno
    ReleaseNode(n)