Statistics
| Branch: | Tag: | Revision:

root / qa / qa_config.py @ 47aa6ec9

History | View | Annotate | Download (13.1 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 2176724e Michael Hanselmann
    "_used",
48 02a5fe0e 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 2176724e Michael Hanselmann
    self._used = None
58 02a5fe0e 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 2176724e Michael Hanselmann
  def Use(self):
74 2176724e Michael Hanselmann
    """Marks instance as being in use.
75 2176724e Michael Hanselmann

76 2176724e Michael Hanselmann
    """
77 2176724e Michael Hanselmann
    assert not self._used
78 2176724e Michael Hanselmann
    assert self._disk_template is None
79 2176724e Michael Hanselmann
80 2176724e Michael Hanselmann
    self._used = True
81 2176724e Michael Hanselmann
82 6f88e076 Michael Hanselmann
  def Release(self):
83 6f88e076 Michael Hanselmann
    """Releases instance and makes it available again.
84 6f88e076 Michael Hanselmann

85 6f88e076 Michael Hanselmann
    """
86 2176724e Michael Hanselmann
    assert self._used, \
87 6f88e076 Michael Hanselmann
      ("Instance '%s' was never acquired or released more than once" %
88 6f88e076 Michael Hanselmann
       self.name)
89 6f88e076 Michael Hanselmann
90 2176724e Michael Hanselmann
    self._used = False
91 02a5fe0e Michael Hanselmann
    self._disk_template = None
92 6f88e076 Michael Hanselmann
93 6a654276 Michael Hanselmann
  def GetNicMacAddr(self, idx, default):
94 6a654276 Michael Hanselmann
    """Returns MAC address for NIC.
95 6a654276 Michael Hanselmann

96 6a654276 Michael Hanselmann
    @type idx: int
97 6a654276 Michael Hanselmann
    @param idx: NIC index
98 6a654276 Michael Hanselmann
    @param default: Default value
99 6a654276 Michael Hanselmann

100 6a654276 Michael Hanselmann
    """
101 6a654276 Michael Hanselmann
    if len(self.nicmac) > idx:
102 6a654276 Michael Hanselmann
      return self.nicmac[idx]
103 6a654276 Michael Hanselmann
    else:
104 6a654276 Michael Hanselmann
      return default
105 6a654276 Michael Hanselmann
106 02a5fe0e Michael Hanselmann
  def SetDiskTemplate(self, template):
107 02a5fe0e Michael Hanselmann
    """Set the disk template.
108 02a5fe0e Michael Hanselmann

109 02a5fe0e Michael Hanselmann
    """
110 02a5fe0e Michael Hanselmann
    assert template in constants.DISK_TEMPLATES
111 02a5fe0e Michael Hanselmann
112 02a5fe0e Michael Hanselmann
    self._disk_template = template
113 02a5fe0e Michael Hanselmann
114 02a5fe0e Michael Hanselmann
  @property
115 2176724e Michael Hanselmann
  def used(self):
116 2176724e Michael Hanselmann
    """Returns boolean denoting whether instance is in use.
117 2176724e Michael Hanselmann

118 2176724e Michael Hanselmann
    """
119 2176724e Michael Hanselmann
    return self._used
120 2176724e Michael Hanselmann
121 2176724e Michael Hanselmann
  @property
122 02a5fe0e Michael Hanselmann
  def disk_template(self):
123 02a5fe0e Michael Hanselmann
    """Returns the current disk template.
124 02a5fe0e Michael Hanselmann

125 02a5fe0e Michael Hanselmann
    """
126 02a5fe0e Michael Hanselmann
    return self._disk_template
127 02a5fe0e Michael Hanselmann
128 6a654276 Michael Hanselmann
129 dbdb0594 Michael Hanselmann
class _QaNode(object):
130 dbdb0594 Michael Hanselmann
  __slots__ = [
131 dbdb0594 Michael Hanselmann
    "primary",
132 dbdb0594 Michael Hanselmann
    "secondary",
133 dbdb0594 Michael Hanselmann
    "_added",
134 565cb4bf Michael Hanselmann
    "_use_count",
135 dbdb0594 Michael Hanselmann
    ]
136 dbdb0594 Michael Hanselmann
137 dbdb0594 Michael Hanselmann
  def __init__(self, primary, secondary):
138 dbdb0594 Michael Hanselmann
    """Initializes instances of this class.
139 dbdb0594 Michael Hanselmann

140 dbdb0594 Michael Hanselmann
    """
141 dbdb0594 Michael Hanselmann
    self.primary = primary
142 dbdb0594 Michael Hanselmann
    self.secondary = secondary
143 dbdb0594 Michael Hanselmann
    self._added = False
144 565cb4bf Michael Hanselmann
    self._use_count = 0
145 dbdb0594 Michael Hanselmann
146 dbdb0594 Michael Hanselmann
  @classmethod
147 dbdb0594 Michael Hanselmann
  def FromDict(cls, data):
148 dbdb0594 Michael Hanselmann
    """Creates node object from JSON dictionary.
149 dbdb0594 Michael Hanselmann

150 dbdb0594 Michael Hanselmann
    """
151 dbdb0594 Michael Hanselmann
    return cls(primary=data["primary"], secondary=data.get("secondary"))
152 dbdb0594 Michael Hanselmann
153 dbdb0594 Michael Hanselmann
  def Use(self):
154 dbdb0594 Michael Hanselmann
    """Marks a node as being in use.
155 dbdb0594 Michael Hanselmann

156 dbdb0594 Michael Hanselmann
    """
157 565cb4bf Michael Hanselmann
    assert self._use_count >= 0
158 dbdb0594 Michael Hanselmann
159 565cb4bf Michael Hanselmann
    self._use_count += 1
160 dbdb0594 Michael Hanselmann
161 dbdb0594 Michael Hanselmann
    return self
162 dbdb0594 Michael Hanselmann
163 565cb4bf Michael Hanselmann
  def Release(self):
164 565cb4bf Michael Hanselmann
    """Release a node (opposite of L{Use}).
165 565cb4bf Michael Hanselmann

166 565cb4bf Michael Hanselmann
    """
167 565cb4bf Michael Hanselmann
    assert self.use_count > 0
168 565cb4bf Michael Hanselmann
169 565cb4bf Michael Hanselmann
    self._use_count -= 1
170 565cb4bf Michael Hanselmann
171 dbdb0594 Michael Hanselmann
  def MarkAdded(self):
172 dbdb0594 Michael Hanselmann
    """Marks node as having been added to a cluster.
173 dbdb0594 Michael Hanselmann

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

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

189 dbdb0594 Michael Hanselmann
    """
190 dbdb0594 Michael Hanselmann
    return self._added
191 dbdb0594 Michael Hanselmann
192 565cb4bf Michael Hanselmann
  @property
193 565cb4bf Michael Hanselmann
  def use_count(self):
194 565cb4bf Michael Hanselmann
    """Returns number of current uses (controlled by L{Use} and L{Release}).
195 565cb4bf Michael Hanselmann

196 565cb4bf Michael Hanselmann
    """
197 565cb4bf Michael Hanselmann
    return self._use_count
198 565cb4bf Michael Hanselmann
199 dbdb0594 Michael Hanselmann
200 6a654276 Michael Hanselmann
_RESOURCE_CONVERTER = {
201 6a654276 Michael Hanselmann
  "instances": _QaInstance.FromDict,
202 dbdb0594 Michael Hanselmann
  "nodes": _QaNode.FromDict,
203 6a654276 Michael Hanselmann
  }
204 6a654276 Michael Hanselmann
205 6a654276 Michael Hanselmann
206 6a654276 Michael Hanselmann
def _ConvertResources((key, value)):
207 6a654276 Michael Hanselmann
  """Converts cluster resources in configuration to Python objects.
208 6a654276 Michael Hanselmann

209 6a654276 Michael Hanselmann
  """
210 6a654276 Michael Hanselmann
  fn = _RESOURCE_CONVERTER.get(key, None)
211 6a654276 Michael Hanselmann
  if fn:
212 6a654276 Michael Hanselmann
    return (key, map(fn, value))
213 6a654276 Michael Hanselmann
  else:
214 6a654276 Michael Hanselmann
    return (key, value)
215 6a654276 Michael Hanselmann
216 6a654276 Michael Hanselmann
217 8a96c5a6 Michael Hanselmann
class _QaConfig(object):
218 8a96c5a6 Michael Hanselmann
  def __init__(self, data):
219 8a96c5a6 Michael Hanselmann
    """Initializes instances of this class.
220 cec9845c Michael Hanselmann

221 8a96c5a6 Michael Hanselmann
    """
222 8a96c5a6 Michael Hanselmann
    self._data = data
223 8a96c5a6 Michael Hanselmann
224 a08e181f Michael Hanselmann
    #: Cluster-wide run-time value of the exclusive storage flag
225 a08e181f Michael Hanselmann
    self._exclusive_storage = None
226 a08e181f Michael Hanselmann
227 8a96c5a6 Michael Hanselmann
  @classmethod
228 8a96c5a6 Michael Hanselmann
  def Load(cls, filename):
229 8a96c5a6 Michael Hanselmann
    """Loads a configuration file and produces a configuration object.
230 8a96c5a6 Michael Hanselmann

231 8a96c5a6 Michael Hanselmann
    @type filename: string
232 8a96c5a6 Michael Hanselmann
    @param filename: Path to configuration file
233 8a96c5a6 Michael Hanselmann
    @rtype: L{_QaConfig}
234 8a96c5a6 Michael Hanselmann

235 8a96c5a6 Michael Hanselmann
    """
236 8a96c5a6 Michael Hanselmann
    data = serializer.LoadJson(utils.ReadFile(filename))
237 8a96c5a6 Michael Hanselmann
238 6a654276 Michael Hanselmann
    result = cls(dict(map(_ConvertResources,
239 6a654276 Michael Hanselmann
                          data.items()))) # pylint: disable=E1103
240 8a96c5a6 Michael Hanselmann
    result.Validate()
241 8a96c5a6 Michael Hanselmann
242 8a96c5a6 Michael Hanselmann
    return result
243 8a96c5a6 Michael Hanselmann
244 8a96c5a6 Michael Hanselmann
  def Validate(self):
245 8a96c5a6 Michael Hanselmann
    """Validates loaded configuration data.
246 8a96c5a6 Michael Hanselmann

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

283 8a96c5a6 Michael Hanselmann
    @type name: string
284 8a96c5a6 Michael Hanselmann
    @param name: Name of configuration entry
285 8a96c5a6 Michael Hanselmann

286 8a96c5a6 Michael Hanselmann
    """
287 8a96c5a6 Michael Hanselmann
    return self._data[name]
288 8a96c5a6 Michael Hanselmann
289 8a96c5a6 Michael Hanselmann
  def get(self, name, default=None):
290 8a96c5a6 Michael Hanselmann
    """Returns configuration value.
291 8a96c5a6 Michael Hanselmann

292 8a96c5a6 Michael Hanselmann
    @type name: string
293 8a96c5a6 Michael Hanselmann
    @param name: Name of configuration entry
294 8a96c5a6 Michael Hanselmann
    @param default: Default value
295 8a96c5a6 Michael Hanselmann

296 8a96c5a6 Michael Hanselmann
    """
297 8a96c5a6 Michael Hanselmann
    return self._data.get(name, default)
298 cec9845c Michael Hanselmann
299 8a96c5a6 Michael Hanselmann
  def GetMasterNode(self):
300 8a96c5a6 Michael Hanselmann
    """Returns the default master node for the cluster.
301 cec9845c Michael Hanselmann

302 8a96c5a6 Michael Hanselmann
    """
303 8a96c5a6 Michael Hanselmann
    return self["nodes"][0]
304 8a96c5a6 Michael Hanselmann
305 8a96c5a6 Michael Hanselmann
  def GetInstanceCheckScript(self):
306 8a96c5a6 Michael Hanselmann
    """Returns path to instance check script or C{None}.
307 8a96c5a6 Michael Hanselmann

308 8a96c5a6 Michael Hanselmann
    """
309 8a96c5a6 Michael Hanselmann
    return self._data.get(_INSTANCE_CHECK_KEY, None)
310 cec9845c Michael Hanselmann
311 8a96c5a6 Michael Hanselmann
  def GetEnabledHypervisors(self):
312 8a96c5a6 Michael Hanselmann
    """Returns list of enabled hypervisors.
313 cec9845c Michael Hanselmann

314 8a96c5a6 Michael Hanselmann
    @rtype: list
315 cec9845c Michael Hanselmann

316 8a96c5a6 Michael Hanselmann
    """
317 c9e05005 Michael Hanselmann
    try:
318 8a96c5a6 Michael Hanselmann
      value = self._data[_ENABLED_HV_KEY]
319 8a96c5a6 Michael Hanselmann
    except KeyError:
320 8a96c5a6 Michael Hanselmann
      return [constants.DEFAULT_ENABLED_HYPERVISOR]
321 8a96c5a6 Michael Hanselmann
    else:
322 8a96c5a6 Michael Hanselmann
      if value is None:
323 8a96c5a6 Michael Hanselmann
        return []
324 8a96c5a6 Michael Hanselmann
      elif isinstance(value, basestring):
325 8a96c5a6 Michael Hanselmann
        # The configuration key ("enabled-hypervisors") implies there can be
326 8a96c5a6 Michael Hanselmann
        # multiple values. Multiple hypervisors are comma-separated on the
327 8a96c5a6 Michael Hanselmann
        # command line option to "gnt-cluster init", so we need to handle them
328 8a96c5a6 Michael Hanselmann
        # equally here.
329 8a96c5a6 Michael Hanselmann
        return value.split(",")
330 8a96c5a6 Michael Hanselmann
      else:
331 8a96c5a6 Michael Hanselmann
        return value
332 8a96c5a6 Michael Hanselmann
333 8a96c5a6 Michael Hanselmann
  def GetDefaultHypervisor(self):
334 8a96c5a6 Michael Hanselmann
    """Returns the default hypervisor to be used.
335 8a96c5a6 Michael Hanselmann

336 8a96c5a6 Michael Hanselmann
    """
337 8a96c5a6 Michael Hanselmann
    return self.GetEnabledHypervisors()[0]
338 8a96c5a6 Michael Hanselmann
339 a08e181f Michael Hanselmann
  def SetExclusiveStorage(self, value):
340 a08e181f Michael Hanselmann
    """Set the expected value of the C{exclusive_storage} flag for the cluster.
341 a08e181f Michael Hanselmann

342 a08e181f Michael Hanselmann
    """
343 a08e181f Michael Hanselmann
    self._exclusive_storage = bool(value)
344 a08e181f Michael Hanselmann
345 a08e181f Michael Hanselmann
  def GetExclusiveStorage(self):
346 a08e181f Michael Hanselmann
    """Get the expected value of the C{exclusive_storage} flag for the cluster.
347 a08e181f Michael Hanselmann

348 a08e181f Michael Hanselmann
    """
349 a08e181f Michael Hanselmann
    value = self._exclusive_storage
350 a08e181f Michael Hanselmann
    assert value is not None
351 a08e181f Michael Hanselmann
    return value
352 a08e181f Michael Hanselmann
353 a08e181f Michael Hanselmann
  def IsTemplateSupported(self, templ):
354 a08e181f Michael Hanselmann
    """Is the given disk template supported by the current configuration?
355 a08e181f Michael Hanselmann

356 a08e181f Michael Hanselmann
    """
357 cf62af3a Michael Hanselmann
    return (not self.GetExclusiveStorage() or
358 cf62af3a Michael Hanselmann
            templ in constants.DTS_EXCL_STORAGE)
359 a08e181f Michael Hanselmann
360 8a96c5a6 Michael Hanselmann
361 8a96c5a6 Michael Hanselmann
def Load(path):
362 8a96c5a6 Michael Hanselmann
  """Loads the passed configuration file.
363 8a96c5a6 Michael Hanselmann

364 8a96c5a6 Michael Hanselmann
  """
365 8a96c5a6 Michael Hanselmann
  global _config # pylint: disable=W0603
366 8a96c5a6 Michael Hanselmann
367 8a96c5a6 Michael Hanselmann
  _config = _QaConfig.Load(path)
368 c9e05005 Michael Hanselmann
369 e7b6183b Michael Hanselmann
370 8a96c5a6 Michael Hanselmann
def GetConfig():
371 8a96c5a6 Michael Hanselmann
  """Returns the configuration object.
372 8a96c5a6 Michael Hanselmann

373 8a96c5a6 Michael Hanselmann
  """
374 8a96c5a6 Michael Hanselmann
  if _config is None:
375 8a96c5a6 Michael Hanselmann
    raise RuntimeError("Configuration not yet loaded")
376 8a96c5a6 Michael Hanselmann
377 8a96c5a6 Michael Hanselmann
  return _config
378 e7b6183b Michael Hanselmann
379 cec9845c Michael Hanselmann
380 cec9845c Michael Hanselmann
def get(name, default=None):
381 8a96c5a6 Michael Hanselmann
  """Wrapper for L{_QaConfig.get}.
382 8a96c5a6 Michael Hanselmann

383 8a96c5a6 Michael Hanselmann
  """
384 8a96c5a6 Michael Hanselmann
  return GetConfig().get(name, default=default)
385 cec9845c Michael Hanselmann
386 cec9845c Michael Hanselmann
387 a0c3e726 Michael Hanselmann
class Either:
388 a0c3e726 Michael Hanselmann
  def __init__(self, tests):
389 a0c3e726 Michael Hanselmann
    """Initializes this class.
390 a0c3e726 Michael Hanselmann

391 a0c3e726 Michael Hanselmann
    @type tests: list or string
392 a0c3e726 Michael Hanselmann
    @param tests: List of test names
393 a0c3e726 Michael Hanselmann
    @see: L{TestEnabled} for details
394 a0c3e726 Michael Hanselmann

395 a0c3e726 Michael Hanselmann
    """
396 a0c3e726 Michael Hanselmann
    self.tests = tests
397 a0c3e726 Michael Hanselmann
398 a0c3e726 Michael Hanselmann
399 a0c3e726 Michael Hanselmann
def _MakeSequence(value):
400 a0c3e726 Michael Hanselmann
  """Make sequence of single argument.
401 a0c3e726 Michael Hanselmann

402 a0c3e726 Michael Hanselmann
  If the single argument is not already a list or tuple, a list with the
403 a0c3e726 Michael Hanselmann
  argument as a single item is returned.
404 a0c3e726 Michael Hanselmann

405 a0c3e726 Michael Hanselmann
  """
406 a0c3e726 Michael Hanselmann
  if isinstance(value, (list, tuple)):
407 a0c3e726 Michael Hanselmann
    return value
408 a0c3e726 Michael Hanselmann
  else:
409 a0c3e726 Michael Hanselmann
    return [value]
410 a0c3e726 Michael Hanselmann
411 a0c3e726 Michael Hanselmann
412 a0c3e726 Michael Hanselmann
def _TestEnabledInner(check_fn, names, fn):
413 a0c3e726 Michael Hanselmann
  """Evaluate test conditions.
414 a0c3e726 Michael Hanselmann

415 a0c3e726 Michael Hanselmann
  @type check_fn: callable
416 a0c3e726 Michael Hanselmann
  @param check_fn: Callback to check whether a test is enabled
417 a0c3e726 Michael Hanselmann
  @type names: sequence or string
418 a0c3e726 Michael Hanselmann
  @param names: Test name(s)
419 a0c3e726 Michael Hanselmann
  @type fn: callable
420 a0c3e726 Michael Hanselmann
  @param fn: Aggregation function
421 a0c3e726 Michael Hanselmann
  @rtype: bool
422 a0c3e726 Michael Hanselmann
  @return: Whether test is enabled
423 a0c3e726 Michael Hanselmann

424 a0c3e726 Michael Hanselmann
  """
425 a0c3e726 Michael Hanselmann
  names = _MakeSequence(names)
426 a0c3e726 Michael Hanselmann
427 a0c3e726 Michael Hanselmann
  result = []
428 a0c3e726 Michael Hanselmann
429 a0c3e726 Michael Hanselmann
  for name in names:
430 a0c3e726 Michael Hanselmann
    if isinstance(name, Either):
431 a0c3e726 Michael Hanselmann
      value = _TestEnabledInner(check_fn, name.tests, compat.any)
432 a0c3e726 Michael Hanselmann
    elif isinstance(name, (list, tuple)):
433 a0c3e726 Michael Hanselmann
      value = _TestEnabledInner(check_fn, name, compat.all)
434 a0c3e726 Michael Hanselmann
    else:
435 a0c3e726 Michael Hanselmann
      value = check_fn(name)
436 a0c3e726 Michael Hanselmann
437 a0c3e726 Michael Hanselmann
    result.append(value)
438 a0c3e726 Michael Hanselmann
439 a0c3e726 Michael Hanselmann
  return fn(result)
440 a0c3e726 Michael Hanselmann
441 a0c3e726 Michael Hanselmann
442 a0c3e726 Michael Hanselmann
def TestEnabled(tests, _cfg=None):
443 7d88f255 Iustin Pop
  """Returns True if the given tests are enabled.
444 7d88f255 Iustin Pop

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

448 1010ec70 Michael Hanselmann
  """
449 a0c3e726 Michael Hanselmann
  if _cfg is None:
450 8a96c5a6 Michael Hanselmann
    cfg = GetConfig()
451 8a96c5a6 Michael Hanselmann
  else:
452 8a96c5a6 Michael Hanselmann
    cfg = _cfg
453 59a8fe48 Michael Hanselmann
454 59a8fe48 Michael Hanselmann
  # Get settings for all tests
455 8a96c5a6 Michael Hanselmann
  cfg_tests = cfg.get("tests", {})
456 59a8fe48 Michael Hanselmann
457 59a8fe48 Michael Hanselmann
  # Get default setting
458 a0c3e726 Michael Hanselmann
  default = cfg_tests.get("default", True)
459 59a8fe48 Michael Hanselmann
460 a0c3e726 Michael Hanselmann
  return _TestEnabledInner(lambda name: cfg_tests.get(name, default),
461 a0c3e726 Michael Hanselmann
                           tests, compat.all)
462 cec9845c Michael Hanselmann
463 cec9845c Michael Hanselmann
464 8a96c5a6 Michael Hanselmann
def GetInstanceCheckScript(*args):
465 8a96c5a6 Michael Hanselmann
  """Wrapper for L{_QaConfig.GetInstanceCheckScript}.
466 c9e05005 Michael Hanselmann

467 c9e05005 Michael Hanselmann
  """
468 8a96c5a6 Michael Hanselmann
  return GetConfig().GetInstanceCheckScript(*args)
469 c9e05005 Michael Hanselmann
470 e7b6183b Michael Hanselmann
471 8a96c5a6 Michael Hanselmann
def GetEnabledHypervisors(*args):
472 8a96c5a6 Michael Hanselmann
  """Wrapper for L{_QaConfig.GetEnabledHypervisors}.
473 e7b6183b Michael Hanselmann

474 e7b6183b Michael Hanselmann
  """
475 8a96c5a6 Michael Hanselmann
  return GetConfig().GetEnabledHypervisors(*args)
476 e7b6183b Michael Hanselmann
477 e7b6183b Michael Hanselmann
478 8a96c5a6 Michael Hanselmann
def GetDefaultHypervisor(*args):
479 8a96c5a6 Michael Hanselmann
  """Wrapper for L{_QaConfig.GetDefaultHypervisor}.
480 e7b6183b Michael Hanselmann

481 e7b6183b Michael Hanselmann
  """
482 8a96c5a6 Michael Hanselmann
  return GetConfig().GetDefaultHypervisor(*args)
483 e7b6183b Michael Hanselmann
484 e7b6183b Michael Hanselmann
485 cec9845c Michael Hanselmann
def GetMasterNode():
486 8a96c5a6 Michael Hanselmann
  """Wrapper for L{_QaConfig.GetMasterNode}.
487 8a96c5a6 Michael Hanselmann

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

495 cec9845c Michael Hanselmann
  """
496 6a654276 Michael Hanselmann
  if _cfg is None:
497 6a654276 Michael Hanselmann
    cfg = GetConfig()
498 6a654276 Michael Hanselmann
  else:
499 6a654276 Michael Hanselmann
    cfg = _cfg
500 6a654276 Michael Hanselmann
501 cec9845c Michael Hanselmann
  # Filter out unwanted instances
502 6a654276 Michael Hanselmann
  instances = filter(lambda inst: not inst.used, cfg["instances"])
503 cec9845c Michael Hanselmann
504 6a654276 Michael Hanselmann
  if not instances:
505 cec9845c Michael Hanselmann
    raise qa_error.OutOfInstancesError("No instances left")
506 cec9845c Michael Hanselmann
507 2176724e Michael Hanselmann
  instance = instances[0]
508 2176724e Michael Hanselmann
  instance.Use()
509 6a654276 Michael Hanselmann
510 2176724e Michael Hanselmann
  return instance
511 cec9845c Michael Hanselmann
512 cec9845c Michael Hanselmann
513 6a0f22e1 Bernardo Dal Seno
def SetExclusiveStorage(value):
514 a08e181f Michael Hanselmann
  """Wrapper for L{_QaConfig.SetExclusiveStorage}.
515 6a0f22e1 Bernardo Dal Seno

516 6a0f22e1 Bernardo Dal Seno
  """
517 a08e181f Michael Hanselmann
  return GetConfig().SetExclusiveStorage(value)
518 6a0f22e1 Bernardo Dal Seno
519 6a0f22e1 Bernardo Dal Seno
520 6a0f22e1 Bernardo Dal Seno
def GetExclusiveStorage():
521 a08e181f Michael Hanselmann
  """Wrapper for L{_QaConfig.GetExclusiveStorage}.
522 6a0f22e1 Bernardo Dal Seno

523 6a0f22e1 Bernardo Dal Seno
  """
524 a08e181f Michael Hanselmann
  return GetConfig().GetExclusiveStorage()
525 6a0f22e1 Bernardo Dal Seno
526 6a0f22e1 Bernardo Dal Seno
527 27eba428 Bernardo Dal Seno
def IsTemplateSupported(templ):
528 a08e181f Michael Hanselmann
  """Wrapper for L{_QaConfig.GetExclusiveStorage}.
529 27eba428 Bernardo Dal Seno

530 27eba428 Bernardo Dal Seno
  """
531 a08e181f Michael Hanselmann
  return GetConfig().IsTemplateSupported(templ)
532 27eba428 Bernardo Dal Seno
533 27eba428 Bernardo Dal Seno
534 dbdb0594 Michael Hanselmann
def AcquireNode(exclude=None, _cfg=None):
535 cec9845c Michael Hanselmann
  """Returns the least used node.
536 cec9845c Michael Hanselmann

537 cec9845c Michael Hanselmann
  """
538 dbdb0594 Michael Hanselmann
  if _cfg is None:
539 dbdb0594 Michael Hanselmann
    cfg = GetConfig()
540 dbdb0594 Michael Hanselmann
  else:
541 dbdb0594 Michael Hanselmann
    cfg = _cfg
542 dbdb0594 Michael Hanselmann
543 dbdb0594 Michael Hanselmann
  master = cfg.GetMasterNode()
544 cec9845c Michael Hanselmann
545 cec9845c Michael Hanselmann
  # Filter out unwanted nodes
546 cec9845c Michael Hanselmann
  # TODO: Maybe combine filters
547 cec9845c Michael Hanselmann
  if exclude is None:
548 d0c8c01d Iustin Pop
    nodes = cfg["nodes"][:]
549 4b62db14 Michael Hanselmann
  elif isinstance(exclude, (list, tuple)):
550 d0c8c01d Iustin Pop
    nodes = filter(lambda node: node not in exclude, cfg["nodes"])
551 cec9845c Michael Hanselmann
  else:
552 d0c8c01d Iustin Pop
    nodes = filter(lambda node: node != exclude, cfg["nodes"])
553 cec9845c Michael Hanselmann
554 dbdb0594 Michael Hanselmann
  nodes = filter(lambda node: node.added or node == master, nodes)
555 cec9845c Michael Hanselmann
556 dbdb0594 Michael Hanselmann
  if not nodes:
557 cec9845c Michael Hanselmann
    raise qa_error.OutOfNodesError("No nodes left")
558 cec9845c Michael Hanselmann
559 cec9845c Michael Hanselmann
  # Get node with least number of uses
560 dbdb0594 Michael Hanselmann
  # TODO: Switch to computing sort key instead of comparing directly
561 cec9845c Michael Hanselmann
  def compare(a, b):
562 dbdb0594 Michael Hanselmann
    result = cmp(a.use_count, b.use_count)
563 cec9845c Michael Hanselmann
    if result == 0:
564 dbdb0594 Michael Hanselmann
      result = cmp(a.primary, b.primary)
565 cec9845c Michael Hanselmann
    return result
566 cec9845c Michael Hanselmann
567 cec9845c Michael Hanselmann
  nodes.sort(cmp=compare)
568 cec9845c Michael Hanselmann
569 dbdb0594 Michael Hanselmann
  return nodes[0].Use()
570 cec9845c Michael Hanselmann
571 cec9845c Michael Hanselmann
572 7d4f1b45 Bernardo Dal Seno
def AcquireManyNodes(num, exclude=None):
573 7d4f1b45 Bernardo Dal Seno
  """Return the least used nodes.
574 7d4f1b45 Bernardo Dal Seno

575 7d4f1b45 Bernardo Dal Seno
  @type num: int
576 7d4f1b45 Bernardo Dal Seno
  @param num: Number of nodes; can be 0.
577 7d4f1b45 Bernardo Dal Seno
  @type exclude: list of nodes or C{None}
578 7d4f1b45 Bernardo Dal Seno
  @param exclude: nodes to be excluded from the choice
579 7d4f1b45 Bernardo Dal Seno
  @rtype: list of nodes
580 7d4f1b45 Bernardo Dal Seno
  @return: C{num} different nodes
581 7d4f1b45 Bernardo Dal Seno

582 7d4f1b45 Bernardo Dal Seno
  """
583 7d4f1b45 Bernardo Dal Seno
  nodes = []
584 7d4f1b45 Bernardo Dal Seno
  if exclude is None:
585 7d4f1b45 Bernardo Dal Seno
    exclude = []
586 7d4f1b45 Bernardo Dal Seno
  elif isinstance(exclude, (list, tuple)):
587 7d4f1b45 Bernardo Dal Seno
    # Don't modify the incoming argument
588 7d4f1b45 Bernardo Dal Seno
    exclude = list(exclude)
589 7d4f1b45 Bernardo Dal Seno
  else:
590 7d4f1b45 Bernardo Dal Seno
    exclude = [exclude]
591 7d4f1b45 Bernardo Dal Seno
592 7d4f1b45 Bernardo Dal Seno
  try:
593 7d4f1b45 Bernardo Dal Seno
    for _ in range(0, num):
594 7d4f1b45 Bernardo Dal Seno
      n = AcquireNode(exclude=exclude)
595 7d4f1b45 Bernardo Dal Seno
      nodes.append(n)
596 7d4f1b45 Bernardo Dal Seno
      exclude.append(n)
597 7d4f1b45 Bernardo Dal Seno
  except qa_error.OutOfNodesError:
598 7d4f1b45 Bernardo Dal Seno
    ReleaseManyNodes(nodes)
599 7d4f1b45 Bernardo Dal Seno
    raise
600 7d4f1b45 Bernardo Dal Seno
  return nodes
601 7d4f1b45 Bernardo Dal Seno
602 7d4f1b45 Bernardo Dal Seno
603 7d4f1b45 Bernardo Dal Seno
def ReleaseManyNodes(nodes):
604 565cb4bf Michael Hanselmann
  for node in nodes:
605 565cb4bf Michael Hanselmann
    node.Release()