Statistics
| Branch: | Tag: | Revision:

root / qa / qa_config.py @ dbdb0594

History | View | Annotate | Download (13.4 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 f9329a6c Michael Hanselmann
39 8a96c5a6 Michael Hanselmann
#: QA configuration (L{_QaConfig})
40 8a96c5a6 Michael Hanselmann
_config = None
41 cec9845c Michael Hanselmann
42 cec9845c Michael Hanselmann
43 6a654276 Michael Hanselmann
class _QaInstance(object):
44 6a654276 Michael Hanselmann
  __slots__ = [
45 6a654276 Michael Hanselmann
    "name",
46 6a654276 Michael Hanselmann
    "nicmac",
47 6a654276 Michael Hanselmann
    "used",
48 6a654276 Michael Hanselmann
    "disk_template",
49 6a654276 Michael Hanselmann
    ]
50 6a654276 Michael Hanselmann
51 6a654276 Michael Hanselmann
  def __init__(self, name, nicmac):
52 6a654276 Michael Hanselmann
    """Initializes instances of this class.
53 6a654276 Michael Hanselmann

54 6a654276 Michael Hanselmann
    """
55 6a654276 Michael Hanselmann
    self.name = name
56 6a654276 Michael Hanselmann
    self.nicmac = nicmac
57 6a654276 Michael Hanselmann
    self.used = None
58 6a654276 Michael Hanselmann
    self.disk_template = None
59 6a654276 Michael Hanselmann
60 6a654276 Michael Hanselmann
  @classmethod
61 6a654276 Michael Hanselmann
  def FromDict(cls, data):
62 6a654276 Michael Hanselmann
    """Creates instance object from JSON dictionary.
63 6a654276 Michael Hanselmann

64 6a654276 Michael Hanselmann
    """
65 6a654276 Michael Hanselmann
    nicmac = []
66 6a654276 Michael Hanselmann
67 6a654276 Michael Hanselmann
    macaddr = data.get("nic.mac/0")
68 6a654276 Michael Hanselmann
    if macaddr:
69 6a654276 Michael Hanselmann
      nicmac.append(macaddr)
70 6a654276 Michael Hanselmann
71 6a654276 Michael Hanselmann
    return cls(name=data["name"], nicmac=nicmac)
72 6a654276 Michael Hanselmann
73 6a654276 Michael Hanselmann
  def __getitem__(self, key):
74 6a654276 Michael Hanselmann
    """Legacy dict-like interface.
75 6a654276 Michael Hanselmann

76 6a654276 Michael Hanselmann
    """
77 6a654276 Michael Hanselmann
    if key == "name":
78 6a654276 Michael Hanselmann
      return self.name
79 6a654276 Michael Hanselmann
    else:
80 6a654276 Michael Hanselmann
      raise KeyError(key)
81 6a654276 Michael Hanselmann
82 6a654276 Michael Hanselmann
  def get(self, key, default):
83 6a654276 Michael Hanselmann
    """Legacy dict-like interface.
84 6a654276 Michael Hanselmann

85 6a654276 Michael Hanselmann
    """
86 6a654276 Michael Hanselmann
    try:
87 6a654276 Michael Hanselmann
      return self[key]
88 6a654276 Michael Hanselmann
    except KeyError:
89 6a654276 Michael Hanselmann
      return default
90 6a654276 Michael Hanselmann
91 6f88e076 Michael Hanselmann
  def Release(self):
92 6f88e076 Michael Hanselmann
    """Releases instance and makes it available again.
93 6f88e076 Michael Hanselmann

94 6f88e076 Michael Hanselmann
    """
95 6f88e076 Michael Hanselmann
    assert self.used, \
96 6f88e076 Michael Hanselmann
      ("Instance '%s' was never acquired or released more than once" %
97 6f88e076 Michael Hanselmann
       self.name)
98 6f88e076 Michael Hanselmann
99 6f88e076 Michael Hanselmann
    self.used = False
100 6f88e076 Michael Hanselmann
    self.disk_template = None
101 6f88e076 Michael Hanselmann
102 6a654276 Michael Hanselmann
  def GetNicMacAddr(self, idx, default):
103 6a654276 Michael Hanselmann
    """Returns MAC address for NIC.
104 6a654276 Michael Hanselmann

105 6a654276 Michael Hanselmann
    @type idx: int
106 6a654276 Michael Hanselmann
    @param idx: NIC index
107 6a654276 Michael Hanselmann
    @param default: Default value
108 6a654276 Michael Hanselmann

109 6a654276 Michael Hanselmann
    """
110 6a654276 Michael Hanselmann
    if len(self.nicmac) > idx:
111 6a654276 Michael Hanselmann
      return self.nicmac[idx]
112 6a654276 Michael Hanselmann
    else:
113 6a654276 Michael Hanselmann
      return default
114 6a654276 Michael Hanselmann
115 6a654276 Michael Hanselmann
116 dbdb0594 Michael Hanselmann
class _QaNode(object):
117 dbdb0594 Michael Hanselmann
  __slots__ = [
118 dbdb0594 Michael Hanselmann
    "primary",
119 dbdb0594 Michael Hanselmann
    "secondary",
120 dbdb0594 Michael Hanselmann
    "_added",
121 dbdb0594 Michael Hanselmann
    "use_count",
122 dbdb0594 Michael Hanselmann
    ]
123 dbdb0594 Michael Hanselmann
124 dbdb0594 Michael Hanselmann
  def __init__(self, primary, secondary):
125 dbdb0594 Michael Hanselmann
    """Initializes instances of this class.
126 dbdb0594 Michael Hanselmann

127 dbdb0594 Michael Hanselmann
    """
128 dbdb0594 Michael Hanselmann
    self.primary = primary
129 dbdb0594 Michael Hanselmann
    self.secondary = secondary
130 dbdb0594 Michael Hanselmann
    self.use_count = 0
131 dbdb0594 Michael Hanselmann
    self._added = False
132 dbdb0594 Michael Hanselmann
133 dbdb0594 Michael Hanselmann
  @classmethod
134 dbdb0594 Michael Hanselmann
  def FromDict(cls, data):
135 dbdb0594 Michael Hanselmann
    """Creates node object from JSON dictionary.
136 dbdb0594 Michael Hanselmann

137 dbdb0594 Michael Hanselmann
    """
138 dbdb0594 Michael Hanselmann
    return cls(primary=data["primary"], secondary=data.get("secondary"))
139 dbdb0594 Michael Hanselmann
140 dbdb0594 Michael Hanselmann
  def __getitem__(self, key):
141 dbdb0594 Michael Hanselmann
    """Legacy dict-like interface.
142 dbdb0594 Michael Hanselmann

143 dbdb0594 Michael Hanselmann
    """
144 dbdb0594 Michael Hanselmann
    if key == "primary":
145 dbdb0594 Michael Hanselmann
      return self.primary
146 dbdb0594 Michael Hanselmann
    elif key == "secondary":
147 dbdb0594 Michael Hanselmann
      return self.secondary
148 dbdb0594 Michael Hanselmann
    else:
149 dbdb0594 Michael Hanselmann
      raise KeyError(key)
150 dbdb0594 Michael Hanselmann
151 dbdb0594 Michael Hanselmann
  def get(self, key, default):
152 dbdb0594 Michael Hanselmann
    """Legacy dict-like interface.
153 dbdb0594 Michael Hanselmann

154 dbdb0594 Michael Hanselmann
    """
155 dbdb0594 Michael Hanselmann
    try:
156 dbdb0594 Michael Hanselmann
      return self[key]
157 dbdb0594 Michael Hanselmann
    except KeyError:
158 dbdb0594 Michael Hanselmann
      return default
159 dbdb0594 Michael Hanselmann
160 dbdb0594 Michael Hanselmann
  def Use(self):
161 dbdb0594 Michael Hanselmann
    """Marks a node as being in use.
162 dbdb0594 Michael Hanselmann

163 dbdb0594 Michael Hanselmann
    """
164 dbdb0594 Michael Hanselmann
    assert self.use_count >= 0
165 dbdb0594 Michael Hanselmann
166 dbdb0594 Michael Hanselmann
    self.use_count += 1
167 dbdb0594 Michael Hanselmann
168 dbdb0594 Michael Hanselmann
    return self
169 dbdb0594 Michael Hanselmann
170 dbdb0594 Michael Hanselmann
  def MarkAdded(self):
171 dbdb0594 Michael Hanselmann
    """Marks node as having been added to a cluster.
172 dbdb0594 Michael Hanselmann

173 dbdb0594 Michael Hanselmann
    """
174 dbdb0594 Michael Hanselmann
    assert not self._added
175 dbdb0594 Michael Hanselmann
    self._added = True
176 dbdb0594 Michael Hanselmann
177 dbdb0594 Michael Hanselmann
  def MarkRemoved(self):
178 dbdb0594 Michael Hanselmann
    """Marks node as having been removed from a cluster.
179 dbdb0594 Michael Hanselmann

180 dbdb0594 Michael Hanselmann
    """
181 dbdb0594 Michael Hanselmann
    assert self._added
182 dbdb0594 Michael Hanselmann
    self._added = False
183 dbdb0594 Michael Hanselmann
184 dbdb0594 Michael Hanselmann
  @property
185 dbdb0594 Michael Hanselmann
  def added(self):
186 dbdb0594 Michael Hanselmann
    """Returns whether a node is part of a cluster.
187 dbdb0594 Michael Hanselmann

188 dbdb0594 Michael Hanselmann
    """
189 dbdb0594 Michael Hanselmann
    return self._added
190 dbdb0594 Michael Hanselmann
191 dbdb0594 Michael Hanselmann
192 6a654276 Michael Hanselmann
_RESOURCE_CONVERTER = {
193 6a654276 Michael Hanselmann
  "instances": _QaInstance.FromDict,
194 dbdb0594 Michael Hanselmann
  "nodes": _QaNode.FromDict,
195 6a654276 Michael Hanselmann
  }
196 6a654276 Michael Hanselmann
197 6a654276 Michael Hanselmann
198 6a654276 Michael Hanselmann
def _ConvertResources((key, value)):
199 6a654276 Michael Hanselmann
  """Converts cluster resources in configuration to Python objects.
200 6a654276 Michael Hanselmann

201 6a654276 Michael Hanselmann
  """
202 6a654276 Michael Hanselmann
  fn = _RESOURCE_CONVERTER.get(key, None)
203 6a654276 Michael Hanselmann
  if fn:
204 6a654276 Michael Hanselmann
    return (key, map(fn, value))
205 6a654276 Michael Hanselmann
  else:
206 6a654276 Michael Hanselmann
    return (key, value)
207 6a654276 Michael Hanselmann
208 6a654276 Michael Hanselmann
209 8a96c5a6 Michael Hanselmann
class _QaConfig(object):
210 8a96c5a6 Michael Hanselmann
  def __init__(self, data):
211 8a96c5a6 Michael Hanselmann
    """Initializes instances of this class.
212 cec9845c Michael Hanselmann

213 8a96c5a6 Michael Hanselmann
    """
214 8a96c5a6 Michael Hanselmann
    self._data = data
215 8a96c5a6 Michael Hanselmann
216 a08e181f Michael Hanselmann
    #: Cluster-wide run-time value of the exclusive storage flag
217 a08e181f Michael Hanselmann
    self._exclusive_storage = None
218 a08e181f Michael Hanselmann
219 8a96c5a6 Michael Hanselmann
  @classmethod
220 8a96c5a6 Michael Hanselmann
  def Load(cls, filename):
221 8a96c5a6 Michael Hanselmann
    """Loads a configuration file and produces a configuration object.
222 8a96c5a6 Michael Hanselmann

223 8a96c5a6 Michael Hanselmann
    @type filename: string
224 8a96c5a6 Michael Hanselmann
    @param filename: Path to configuration file
225 8a96c5a6 Michael Hanselmann
    @rtype: L{_QaConfig}
226 8a96c5a6 Michael Hanselmann

227 8a96c5a6 Michael Hanselmann
    """
228 8a96c5a6 Michael Hanselmann
    data = serializer.LoadJson(utils.ReadFile(filename))
229 8a96c5a6 Michael Hanselmann
230 6a654276 Michael Hanselmann
    result = cls(dict(map(_ConvertResources,
231 6a654276 Michael Hanselmann
                          data.items()))) # pylint: disable=E1103
232 8a96c5a6 Michael Hanselmann
    result.Validate()
233 8a96c5a6 Michael Hanselmann
234 8a96c5a6 Michael Hanselmann
    return result
235 8a96c5a6 Michael Hanselmann
236 8a96c5a6 Michael Hanselmann
  def Validate(self):
237 8a96c5a6 Michael Hanselmann
    """Validates loaded configuration data.
238 8a96c5a6 Michael Hanselmann

239 8a96c5a6 Michael Hanselmann
    """
240 8a96c5a6 Michael Hanselmann
    if not self.get("nodes"):
241 8a96c5a6 Michael Hanselmann
      raise qa_error.Error("Need at least one node")
242 8a96c5a6 Michael Hanselmann
243 8a96c5a6 Michael Hanselmann
    if not self.get("instances"):
244 8a96c5a6 Michael Hanselmann
      raise qa_error.Error("Need at least one instance")
245 8a96c5a6 Michael Hanselmann
246 8a96c5a6 Michael Hanselmann
    if (self.get("disk") is None or
247 8a96c5a6 Michael Hanselmann
        self.get("disk-growth") is None or
248 8a96c5a6 Michael Hanselmann
        len(self.get("disk")) != len(self.get("disk-growth"))):
249 8a96c5a6 Michael Hanselmann
      raise qa_error.Error("Config options 'disk' and 'disk-growth' must exist"
250 8a96c5a6 Michael Hanselmann
                           " and have the same number of items")
251 8a96c5a6 Michael Hanselmann
252 8a96c5a6 Michael Hanselmann
    check = self.GetInstanceCheckScript()
253 8a96c5a6 Michael Hanselmann
    if check:
254 8a96c5a6 Michael Hanselmann
      try:
255 8a96c5a6 Michael Hanselmann
        os.stat(check)
256 8a96c5a6 Michael Hanselmann
      except EnvironmentError, err:
257 8a96c5a6 Michael Hanselmann
        raise qa_error.Error("Can't find instance check script '%s': %s" %
258 8a96c5a6 Michael Hanselmann
                             (check, err))
259 8a96c5a6 Michael Hanselmann
260 8a96c5a6 Michael Hanselmann
    enabled_hv = frozenset(self.GetEnabledHypervisors())
261 8a96c5a6 Michael Hanselmann
    if not enabled_hv:
262 8a96c5a6 Michael Hanselmann
      raise qa_error.Error("No hypervisor is enabled")
263 8a96c5a6 Michael Hanselmann
264 8a96c5a6 Michael Hanselmann
    difference = enabled_hv - constants.HYPER_TYPES
265 8a96c5a6 Michael Hanselmann
    if difference:
266 8a96c5a6 Michael Hanselmann
      raise qa_error.Error("Unknown hypervisor(s) enabled: %s" %
267 8a96c5a6 Michael Hanselmann
                           utils.CommaJoin(difference))
268 8a96c5a6 Michael Hanselmann
269 8a96c5a6 Michael Hanselmann
  def __getitem__(self, name):
270 8a96c5a6 Michael Hanselmann
    """Returns configuration value.
271 8a96c5a6 Michael Hanselmann

272 8a96c5a6 Michael Hanselmann
    @type name: string
273 8a96c5a6 Michael Hanselmann
    @param name: Name of configuration entry
274 8a96c5a6 Michael Hanselmann

275 8a96c5a6 Michael Hanselmann
    """
276 8a96c5a6 Michael Hanselmann
    return self._data[name]
277 8a96c5a6 Michael Hanselmann
278 8a96c5a6 Michael Hanselmann
  def get(self, name, default=None):
279 8a96c5a6 Michael Hanselmann
    """Returns configuration value.
280 8a96c5a6 Michael Hanselmann

281 8a96c5a6 Michael Hanselmann
    @type name: string
282 8a96c5a6 Michael Hanselmann
    @param name: Name of configuration entry
283 8a96c5a6 Michael Hanselmann
    @param default: Default value
284 8a96c5a6 Michael Hanselmann

285 8a96c5a6 Michael Hanselmann
    """
286 8a96c5a6 Michael Hanselmann
    return self._data.get(name, default)
287 cec9845c Michael Hanselmann
288 8a96c5a6 Michael Hanselmann
  def GetMasterNode(self):
289 8a96c5a6 Michael Hanselmann
    """Returns the default master node for the cluster.
290 cec9845c Michael Hanselmann

291 8a96c5a6 Michael Hanselmann
    """
292 8a96c5a6 Michael Hanselmann
    return self["nodes"][0]
293 8a96c5a6 Michael Hanselmann
294 8a96c5a6 Michael Hanselmann
  def GetInstanceCheckScript(self):
295 8a96c5a6 Michael Hanselmann
    """Returns path to instance check script or C{None}.
296 8a96c5a6 Michael Hanselmann

297 8a96c5a6 Michael Hanselmann
    """
298 8a96c5a6 Michael Hanselmann
    return self._data.get(_INSTANCE_CHECK_KEY, None)
299 cec9845c Michael Hanselmann
300 8a96c5a6 Michael Hanselmann
  def GetEnabledHypervisors(self):
301 8a96c5a6 Michael Hanselmann
    """Returns list of enabled hypervisors.
302 cec9845c Michael Hanselmann

303 8a96c5a6 Michael Hanselmann
    @rtype: list
304 cec9845c Michael Hanselmann

305 8a96c5a6 Michael Hanselmann
    """
306 c9e05005 Michael Hanselmann
    try:
307 8a96c5a6 Michael Hanselmann
      value = self._data[_ENABLED_HV_KEY]
308 8a96c5a6 Michael Hanselmann
    except KeyError:
309 8a96c5a6 Michael Hanselmann
      return [constants.DEFAULT_ENABLED_HYPERVISOR]
310 8a96c5a6 Michael Hanselmann
    else:
311 8a96c5a6 Michael Hanselmann
      if value is None:
312 8a96c5a6 Michael Hanselmann
        return []
313 8a96c5a6 Michael Hanselmann
      elif isinstance(value, basestring):
314 8a96c5a6 Michael Hanselmann
        # The configuration key ("enabled-hypervisors") implies there can be
315 8a96c5a6 Michael Hanselmann
        # multiple values. Multiple hypervisors are comma-separated on the
316 8a96c5a6 Michael Hanselmann
        # command line option to "gnt-cluster init", so we need to handle them
317 8a96c5a6 Michael Hanselmann
        # equally here.
318 8a96c5a6 Michael Hanselmann
        return value.split(",")
319 8a96c5a6 Michael Hanselmann
      else:
320 8a96c5a6 Michael Hanselmann
        return value
321 8a96c5a6 Michael Hanselmann
322 8a96c5a6 Michael Hanselmann
  def GetDefaultHypervisor(self):
323 8a96c5a6 Michael Hanselmann
    """Returns the default hypervisor to be used.
324 8a96c5a6 Michael Hanselmann

325 8a96c5a6 Michael Hanselmann
    """
326 8a96c5a6 Michael Hanselmann
    return self.GetEnabledHypervisors()[0]
327 8a96c5a6 Michael Hanselmann
328 a08e181f Michael Hanselmann
  def SetExclusiveStorage(self, value):
329 a08e181f Michael Hanselmann
    """Set the expected value of the C{exclusive_storage} flag for the cluster.
330 a08e181f Michael Hanselmann

331 a08e181f Michael Hanselmann
    """
332 a08e181f Michael Hanselmann
    self._exclusive_storage = bool(value)
333 a08e181f Michael Hanselmann
334 a08e181f Michael Hanselmann
  def GetExclusiveStorage(self):
335 a08e181f Michael Hanselmann
    """Get the expected value of the C{exclusive_storage} flag for the cluster.
336 a08e181f Michael Hanselmann

337 a08e181f Michael Hanselmann
    """
338 a08e181f Michael Hanselmann
    value = self._exclusive_storage
339 a08e181f Michael Hanselmann
    assert value is not None
340 a08e181f Michael Hanselmann
    return value
341 a08e181f Michael Hanselmann
342 a08e181f Michael Hanselmann
  def IsTemplateSupported(self, templ):
343 a08e181f Michael Hanselmann
    """Is the given disk template supported by the current configuration?
344 a08e181f Michael Hanselmann

345 a08e181f Michael Hanselmann
    """
346 cf62af3a Michael Hanselmann
    return (not self.GetExclusiveStorage() or
347 cf62af3a Michael Hanselmann
            templ in constants.DTS_EXCL_STORAGE)
348 a08e181f Michael Hanselmann
349 8a96c5a6 Michael Hanselmann
350 8a96c5a6 Michael Hanselmann
def Load(path):
351 8a96c5a6 Michael Hanselmann
  """Loads the passed configuration file.
352 8a96c5a6 Michael Hanselmann

353 8a96c5a6 Michael Hanselmann
  """
354 8a96c5a6 Michael Hanselmann
  global _config # pylint: disable=W0603
355 8a96c5a6 Michael Hanselmann
356 8a96c5a6 Michael Hanselmann
  _config = _QaConfig.Load(path)
357 c9e05005 Michael Hanselmann
358 e7b6183b Michael Hanselmann
359 8a96c5a6 Michael Hanselmann
def GetConfig():
360 8a96c5a6 Michael Hanselmann
  """Returns the configuration object.
361 8a96c5a6 Michael Hanselmann

362 8a96c5a6 Michael Hanselmann
  """
363 8a96c5a6 Michael Hanselmann
  if _config is None:
364 8a96c5a6 Michael Hanselmann
    raise RuntimeError("Configuration not yet loaded")
365 8a96c5a6 Michael Hanselmann
366 8a96c5a6 Michael Hanselmann
  return _config
367 e7b6183b Michael Hanselmann
368 cec9845c Michael Hanselmann
369 cec9845c Michael Hanselmann
def get(name, default=None):
370 8a96c5a6 Michael Hanselmann
  """Wrapper for L{_QaConfig.get}.
371 8a96c5a6 Michael Hanselmann

372 8a96c5a6 Michael Hanselmann
  """
373 8a96c5a6 Michael Hanselmann
  return GetConfig().get(name, default=default)
374 cec9845c Michael Hanselmann
375 cec9845c Michael Hanselmann
376 a0c3e726 Michael Hanselmann
class Either:
377 a0c3e726 Michael Hanselmann
  def __init__(self, tests):
378 a0c3e726 Michael Hanselmann
    """Initializes this class.
379 a0c3e726 Michael Hanselmann

380 a0c3e726 Michael Hanselmann
    @type tests: list or string
381 a0c3e726 Michael Hanselmann
    @param tests: List of test names
382 a0c3e726 Michael Hanselmann
    @see: L{TestEnabled} for details
383 a0c3e726 Michael Hanselmann

384 a0c3e726 Michael Hanselmann
    """
385 a0c3e726 Michael Hanselmann
    self.tests = tests
386 a0c3e726 Michael Hanselmann
387 a0c3e726 Michael Hanselmann
388 a0c3e726 Michael Hanselmann
def _MakeSequence(value):
389 a0c3e726 Michael Hanselmann
  """Make sequence of single argument.
390 a0c3e726 Michael Hanselmann

391 a0c3e726 Michael Hanselmann
  If the single argument is not already a list or tuple, a list with the
392 a0c3e726 Michael Hanselmann
  argument as a single item is returned.
393 a0c3e726 Michael Hanselmann

394 a0c3e726 Michael Hanselmann
  """
395 a0c3e726 Michael Hanselmann
  if isinstance(value, (list, tuple)):
396 a0c3e726 Michael Hanselmann
    return value
397 a0c3e726 Michael Hanselmann
  else:
398 a0c3e726 Michael Hanselmann
    return [value]
399 a0c3e726 Michael Hanselmann
400 a0c3e726 Michael Hanselmann
401 a0c3e726 Michael Hanselmann
def _TestEnabledInner(check_fn, names, fn):
402 a0c3e726 Michael Hanselmann
  """Evaluate test conditions.
403 a0c3e726 Michael Hanselmann

404 a0c3e726 Michael Hanselmann
  @type check_fn: callable
405 a0c3e726 Michael Hanselmann
  @param check_fn: Callback to check whether a test is enabled
406 a0c3e726 Michael Hanselmann
  @type names: sequence or string
407 a0c3e726 Michael Hanselmann
  @param names: Test name(s)
408 a0c3e726 Michael Hanselmann
  @type fn: callable
409 a0c3e726 Michael Hanselmann
  @param fn: Aggregation function
410 a0c3e726 Michael Hanselmann
  @rtype: bool
411 a0c3e726 Michael Hanselmann
  @return: Whether test is enabled
412 a0c3e726 Michael Hanselmann

413 a0c3e726 Michael Hanselmann
  """
414 a0c3e726 Michael Hanselmann
  names = _MakeSequence(names)
415 a0c3e726 Michael Hanselmann
416 a0c3e726 Michael Hanselmann
  result = []
417 a0c3e726 Michael Hanselmann
418 a0c3e726 Michael Hanselmann
  for name in names:
419 a0c3e726 Michael Hanselmann
    if isinstance(name, Either):
420 a0c3e726 Michael Hanselmann
      value = _TestEnabledInner(check_fn, name.tests, compat.any)
421 a0c3e726 Michael Hanselmann
    elif isinstance(name, (list, tuple)):
422 a0c3e726 Michael Hanselmann
      value = _TestEnabledInner(check_fn, name, compat.all)
423 a0c3e726 Michael Hanselmann
    else:
424 a0c3e726 Michael Hanselmann
      value = check_fn(name)
425 a0c3e726 Michael Hanselmann
426 a0c3e726 Michael Hanselmann
    result.append(value)
427 a0c3e726 Michael Hanselmann
428 a0c3e726 Michael Hanselmann
  return fn(result)
429 a0c3e726 Michael Hanselmann
430 a0c3e726 Michael Hanselmann
431 a0c3e726 Michael Hanselmann
def TestEnabled(tests, _cfg=None):
432 7d88f255 Iustin Pop
  """Returns True if the given tests are enabled.
433 7d88f255 Iustin Pop

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

437 1010ec70 Michael Hanselmann
  """
438 a0c3e726 Michael Hanselmann
  if _cfg is None:
439 8a96c5a6 Michael Hanselmann
    cfg = GetConfig()
440 8a96c5a6 Michael Hanselmann
  else:
441 8a96c5a6 Michael Hanselmann
    cfg = _cfg
442 59a8fe48 Michael Hanselmann
443 59a8fe48 Michael Hanselmann
  # Get settings for all tests
444 8a96c5a6 Michael Hanselmann
  cfg_tests = cfg.get("tests", {})
445 59a8fe48 Michael Hanselmann
446 59a8fe48 Michael Hanselmann
  # Get default setting
447 a0c3e726 Michael Hanselmann
  default = cfg_tests.get("default", True)
448 59a8fe48 Michael Hanselmann
449 a0c3e726 Michael Hanselmann
  return _TestEnabledInner(lambda name: cfg_tests.get(name, default),
450 a0c3e726 Michael Hanselmann
                           tests, compat.all)
451 cec9845c Michael Hanselmann
452 cec9845c Michael Hanselmann
453 8a96c5a6 Michael Hanselmann
def GetInstanceCheckScript(*args):
454 8a96c5a6 Michael Hanselmann
  """Wrapper for L{_QaConfig.GetInstanceCheckScript}.
455 c9e05005 Michael Hanselmann

456 c9e05005 Michael Hanselmann
  """
457 8a96c5a6 Michael Hanselmann
  return GetConfig().GetInstanceCheckScript(*args)
458 c9e05005 Michael Hanselmann
459 e7b6183b Michael Hanselmann
460 8a96c5a6 Michael Hanselmann
def GetEnabledHypervisors(*args):
461 8a96c5a6 Michael Hanselmann
  """Wrapper for L{_QaConfig.GetEnabledHypervisors}.
462 e7b6183b Michael Hanselmann

463 e7b6183b Michael Hanselmann
  """
464 8a96c5a6 Michael Hanselmann
  return GetConfig().GetEnabledHypervisors(*args)
465 e7b6183b Michael Hanselmann
466 e7b6183b Michael Hanselmann
467 8a96c5a6 Michael Hanselmann
def GetDefaultHypervisor(*args):
468 8a96c5a6 Michael Hanselmann
  """Wrapper for L{_QaConfig.GetDefaultHypervisor}.
469 e7b6183b Michael Hanselmann

470 e7b6183b Michael Hanselmann
  """
471 8a96c5a6 Michael Hanselmann
  return GetConfig().GetDefaultHypervisor(*args)
472 e7b6183b Michael Hanselmann
473 e7b6183b Michael Hanselmann
474 f346a7d9 Michael Hanselmann
def GetInstanceNicMac(inst, default=None):
475 f346a7d9 Michael Hanselmann
  """Returns MAC address for instance's network interface.
476 f346a7d9 Michael Hanselmann

477 f346a7d9 Michael Hanselmann
  """
478 6a654276 Michael Hanselmann
  return inst.GetNicMacAddr(0, default)
479 f346a7d9 Michael Hanselmann
480 f346a7d9 Michael Hanselmann
481 cec9845c Michael Hanselmann
def GetMasterNode():
482 8a96c5a6 Michael Hanselmann
  """Wrapper for L{_QaConfig.GetMasterNode}.
483 8a96c5a6 Michael Hanselmann

484 8a96c5a6 Michael Hanselmann
  """
485 8a96c5a6 Michael Hanselmann
  return GetConfig().GetMasterNode()
486 cec9845c Michael Hanselmann
487 cec9845c Michael Hanselmann
488 6a654276 Michael Hanselmann
def AcquireInstance(_cfg=None):
489 cec9845c Michael Hanselmann
  """Returns an instance which isn't in use.
490 cec9845c Michael Hanselmann

491 cec9845c Michael Hanselmann
  """
492 6a654276 Michael Hanselmann
  if _cfg is None:
493 6a654276 Michael Hanselmann
    cfg = GetConfig()
494 6a654276 Michael Hanselmann
  else:
495 6a654276 Michael Hanselmann
    cfg = _cfg
496 6a654276 Michael Hanselmann
497 cec9845c Michael Hanselmann
  # Filter out unwanted instances
498 6a654276 Michael Hanselmann
  instances = filter(lambda inst: not inst.used, cfg["instances"])
499 cec9845c Michael Hanselmann
500 6a654276 Michael Hanselmann
  if not instances:
501 cec9845c Michael Hanselmann
    raise qa_error.OutOfInstancesError("No instances left")
502 cec9845c Michael Hanselmann
503 cec9845c Michael Hanselmann
  inst = instances[0]
504 6a654276 Michael Hanselmann
505 6a654276 Michael Hanselmann
  assert not inst.used
506 6a654276 Michael Hanselmann
  assert inst.disk_template is None
507 6a654276 Michael Hanselmann
508 6a654276 Michael Hanselmann
  inst.used = True
509 6a654276 Michael Hanselmann
510 cec9845c Michael Hanselmann
  return inst
511 cec9845c Michael Hanselmann
512 cec9845c Michael Hanselmann
513 906a0346 Bernardo Dal Seno
def GetInstanceTemplate(inst):
514 906a0346 Bernardo Dal Seno
  """Return the disk template of an instance.
515 906a0346 Bernardo Dal Seno

516 906a0346 Bernardo Dal Seno
  """
517 6a654276 Michael Hanselmann
  templ = inst.disk_template
518 906a0346 Bernardo Dal Seno
  assert templ is not None
519 906a0346 Bernardo Dal Seno
  return templ
520 906a0346 Bernardo Dal Seno
521 906a0346 Bernardo Dal Seno
522 906a0346 Bernardo Dal Seno
def SetInstanceTemplate(inst, template):
523 906a0346 Bernardo Dal Seno
  """Set the disk template for an instance.
524 906a0346 Bernardo Dal Seno

525 906a0346 Bernardo Dal Seno
  """
526 6a654276 Michael Hanselmann
  inst.disk_template = template
527 906a0346 Bernardo Dal Seno
528 906a0346 Bernardo Dal Seno
529 6a0f22e1 Bernardo Dal Seno
def SetExclusiveStorage(value):
530 a08e181f Michael Hanselmann
  """Wrapper for L{_QaConfig.SetExclusiveStorage}.
531 6a0f22e1 Bernardo Dal Seno

532 6a0f22e1 Bernardo Dal Seno
  """
533 a08e181f Michael Hanselmann
  return GetConfig().SetExclusiveStorage(value)
534 6a0f22e1 Bernardo Dal Seno
535 6a0f22e1 Bernardo Dal Seno
536 6a0f22e1 Bernardo Dal Seno
def GetExclusiveStorage():
537 a08e181f Michael Hanselmann
  """Wrapper for L{_QaConfig.GetExclusiveStorage}.
538 6a0f22e1 Bernardo Dal Seno

539 6a0f22e1 Bernardo Dal Seno
  """
540 a08e181f Michael Hanselmann
  return GetConfig().GetExclusiveStorage()
541 6a0f22e1 Bernardo Dal Seno
542 6a0f22e1 Bernardo Dal Seno
543 27eba428 Bernardo Dal Seno
def IsTemplateSupported(templ):
544 a08e181f Michael Hanselmann
  """Wrapper for L{_QaConfig.GetExclusiveStorage}.
545 27eba428 Bernardo Dal Seno

546 27eba428 Bernardo Dal Seno
  """
547 a08e181f Michael Hanselmann
  return GetConfig().IsTemplateSupported(templ)
548 27eba428 Bernardo Dal Seno
549 27eba428 Bernardo Dal Seno
550 dbdb0594 Michael Hanselmann
def AcquireNode(exclude=None, _cfg=None):
551 cec9845c Michael Hanselmann
  """Returns the least used node.
552 cec9845c Michael Hanselmann

553 cec9845c Michael Hanselmann
  """
554 dbdb0594 Michael Hanselmann
  if _cfg is None:
555 dbdb0594 Michael Hanselmann
    cfg = GetConfig()
556 dbdb0594 Michael Hanselmann
  else:
557 dbdb0594 Michael Hanselmann
    cfg = _cfg
558 dbdb0594 Michael Hanselmann
559 dbdb0594 Michael Hanselmann
  master = cfg.GetMasterNode()
560 cec9845c Michael Hanselmann
561 cec9845c Michael Hanselmann
  # Filter out unwanted nodes
562 cec9845c Michael Hanselmann
  # TODO: Maybe combine filters
563 cec9845c Michael Hanselmann
  if exclude is None:
564 d0c8c01d Iustin Pop
    nodes = cfg["nodes"][:]
565 4b62db14 Michael Hanselmann
  elif isinstance(exclude, (list, tuple)):
566 d0c8c01d Iustin Pop
    nodes = filter(lambda node: node not in exclude, cfg["nodes"])
567 cec9845c Michael Hanselmann
  else:
568 d0c8c01d Iustin Pop
    nodes = filter(lambda node: node != exclude, cfg["nodes"])
569 cec9845c Michael Hanselmann
570 dbdb0594 Michael Hanselmann
  nodes = filter(lambda node: node.added or node == master, nodes)
571 cec9845c Michael Hanselmann
572 dbdb0594 Michael Hanselmann
  if not nodes:
573 cec9845c Michael Hanselmann
    raise qa_error.OutOfNodesError("No nodes left")
574 cec9845c Michael Hanselmann
575 cec9845c Michael Hanselmann
  # Get node with least number of uses
576 dbdb0594 Michael Hanselmann
  # TODO: Switch to computing sort key instead of comparing directly
577 cec9845c Michael Hanselmann
  def compare(a, b):
578 dbdb0594 Michael Hanselmann
    result = cmp(a.use_count, b.use_count)
579 cec9845c Michael Hanselmann
    if result == 0:
580 dbdb0594 Michael Hanselmann
      result = cmp(a.primary, b.primary)
581 cec9845c Michael Hanselmann
    return result
582 cec9845c Michael Hanselmann
583 cec9845c Michael Hanselmann
  nodes.sort(cmp=compare)
584 cec9845c Michael Hanselmann
585 dbdb0594 Michael Hanselmann
  return nodes[0].Use()
586 cec9845c Michael Hanselmann
587 cec9845c Michael Hanselmann
588 7d4f1b45 Bernardo Dal Seno
def AcquireManyNodes(num, exclude=None):
589 7d4f1b45 Bernardo Dal Seno
  """Return the least used nodes.
590 7d4f1b45 Bernardo Dal Seno

591 7d4f1b45 Bernardo Dal Seno
  @type num: int
592 7d4f1b45 Bernardo Dal Seno
  @param num: Number of nodes; can be 0.
593 7d4f1b45 Bernardo Dal Seno
  @type exclude: list of nodes or C{None}
594 7d4f1b45 Bernardo Dal Seno
  @param exclude: nodes to be excluded from the choice
595 7d4f1b45 Bernardo Dal Seno
  @rtype: list of nodes
596 7d4f1b45 Bernardo Dal Seno
  @return: C{num} different nodes
597 7d4f1b45 Bernardo Dal Seno

598 7d4f1b45 Bernardo Dal Seno
  """
599 7d4f1b45 Bernardo Dal Seno
  nodes = []
600 7d4f1b45 Bernardo Dal Seno
  if exclude is None:
601 7d4f1b45 Bernardo Dal Seno
    exclude = []
602 7d4f1b45 Bernardo Dal Seno
  elif isinstance(exclude, (list, tuple)):
603 7d4f1b45 Bernardo Dal Seno
    # Don't modify the incoming argument
604 7d4f1b45 Bernardo Dal Seno
    exclude = list(exclude)
605 7d4f1b45 Bernardo Dal Seno
  else:
606 7d4f1b45 Bernardo Dal Seno
    exclude = [exclude]
607 7d4f1b45 Bernardo Dal Seno
608 7d4f1b45 Bernardo Dal Seno
  try:
609 7d4f1b45 Bernardo Dal Seno
    for _ in range(0, num):
610 7d4f1b45 Bernardo Dal Seno
      n = AcquireNode(exclude=exclude)
611 7d4f1b45 Bernardo Dal Seno
      nodes.append(n)
612 7d4f1b45 Bernardo Dal Seno
      exclude.append(n)
613 7d4f1b45 Bernardo Dal Seno
  except qa_error.OutOfNodesError:
614 7d4f1b45 Bernardo Dal Seno
    ReleaseManyNodes(nodes)
615 7d4f1b45 Bernardo Dal Seno
    raise
616 7d4f1b45 Bernardo Dal Seno
  return nodes
617 7d4f1b45 Bernardo Dal Seno
618 7d4f1b45 Bernardo Dal Seno
619 cec9845c Michael Hanselmann
def ReleaseNode(node):
620 dbdb0594 Michael Hanselmann
  assert node.use_count > 0
621 dbdb0594 Michael Hanselmann
622 dbdb0594 Michael Hanselmann
  node.use_count -= 1
623 7d4f1b45 Bernardo Dal Seno
624 7d4f1b45 Bernardo Dal Seno
625 7d4f1b45 Bernardo Dal Seno
def ReleaseManyNodes(nodes):
626 7d4f1b45 Bernardo Dal Seno
  for n in nodes:
627 7d4f1b45 Bernardo Dal Seno
    ReleaseNode(n)