Statistics
| Branch: | Tag: | Revision:

root / qa / qa_config.py @ e80edd3b

History | View | Annotate | Download (13.7 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 e80edd3b Michael Hanselmann
  def __repr__(self):
74 e80edd3b Michael Hanselmann
    status = [
75 e80edd3b Michael Hanselmann
      "%s.%s" % (self.__class__.__module__, self.__class__.__name__),
76 e80edd3b Michael Hanselmann
      "name=%s" % self.name,
77 e80edd3b Michael Hanselmann
      "nicmac=%s" % self.nicmac,
78 e80edd3b Michael Hanselmann
      "used=%s" % self._used,
79 e80edd3b Michael Hanselmann
      "disk_template=%s" % self._disk_template,
80 e80edd3b Michael Hanselmann
      ]
81 e80edd3b Michael Hanselmann
82 e80edd3b Michael Hanselmann
    return "<%s at %#x>" % (" ".join(status), id(self))
83 e80edd3b Michael Hanselmann
84 2176724e Michael Hanselmann
  def Use(self):
85 2176724e Michael Hanselmann
    """Marks instance as being in use.
86 2176724e Michael Hanselmann

87 2176724e Michael Hanselmann
    """
88 2176724e Michael Hanselmann
    assert not self._used
89 2176724e Michael Hanselmann
    assert self._disk_template is None
90 2176724e Michael Hanselmann
91 2176724e Michael Hanselmann
    self._used = True
92 2176724e Michael Hanselmann
93 6f88e076 Michael Hanselmann
  def Release(self):
94 6f88e076 Michael Hanselmann
    """Releases instance and makes it available again.
95 6f88e076 Michael Hanselmann

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

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

111 6a654276 Michael Hanselmann
    """
112 6a654276 Michael Hanselmann
    if len(self.nicmac) > idx:
113 6a654276 Michael Hanselmann
      return self.nicmac[idx]
114 6a654276 Michael Hanselmann
    else:
115 6a654276 Michael Hanselmann
      return default
116 6a654276 Michael Hanselmann
117 02a5fe0e Michael Hanselmann
  def SetDiskTemplate(self, template):
118 02a5fe0e Michael Hanselmann
    """Set the disk template.
119 02a5fe0e Michael Hanselmann

120 02a5fe0e Michael Hanselmann
    """
121 02a5fe0e Michael Hanselmann
    assert template in constants.DISK_TEMPLATES
122 02a5fe0e Michael Hanselmann
123 02a5fe0e Michael Hanselmann
    self._disk_template = template
124 02a5fe0e Michael Hanselmann
125 02a5fe0e Michael Hanselmann
  @property
126 2176724e Michael Hanselmann
  def used(self):
127 2176724e Michael Hanselmann
    """Returns boolean denoting whether instance is in use.
128 2176724e Michael Hanselmann

129 2176724e Michael Hanselmann
    """
130 2176724e Michael Hanselmann
    return self._used
131 2176724e Michael Hanselmann
132 2176724e Michael Hanselmann
  @property
133 02a5fe0e Michael Hanselmann
  def disk_template(self):
134 02a5fe0e Michael Hanselmann
    """Returns the current disk template.
135 02a5fe0e Michael Hanselmann

136 02a5fe0e Michael Hanselmann
    """
137 02a5fe0e Michael Hanselmann
    return self._disk_template
138 02a5fe0e Michael Hanselmann
139 6a654276 Michael Hanselmann
140 dbdb0594 Michael Hanselmann
class _QaNode(object):
141 dbdb0594 Michael Hanselmann
  __slots__ = [
142 dbdb0594 Michael Hanselmann
    "primary",
143 dbdb0594 Michael Hanselmann
    "secondary",
144 dbdb0594 Michael Hanselmann
    "_added",
145 565cb4bf Michael Hanselmann
    "_use_count",
146 dbdb0594 Michael Hanselmann
    ]
147 dbdb0594 Michael Hanselmann
148 dbdb0594 Michael Hanselmann
  def __init__(self, primary, secondary):
149 dbdb0594 Michael Hanselmann
    """Initializes instances of this class.
150 dbdb0594 Michael Hanselmann

151 dbdb0594 Michael Hanselmann
    """
152 dbdb0594 Michael Hanselmann
    self.primary = primary
153 dbdb0594 Michael Hanselmann
    self.secondary = secondary
154 dbdb0594 Michael Hanselmann
    self._added = False
155 565cb4bf Michael Hanselmann
    self._use_count = 0
156 dbdb0594 Michael Hanselmann
157 dbdb0594 Michael Hanselmann
  @classmethod
158 dbdb0594 Michael Hanselmann
  def FromDict(cls, data):
159 dbdb0594 Michael Hanselmann
    """Creates node object from JSON dictionary.
160 dbdb0594 Michael Hanselmann

161 dbdb0594 Michael Hanselmann
    """
162 dbdb0594 Michael Hanselmann
    return cls(primary=data["primary"], secondary=data.get("secondary"))
163 dbdb0594 Michael Hanselmann
164 e80edd3b Michael Hanselmann
  def __repr__(self):
165 e80edd3b Michael Hanselmann
    status = [
166 e80edd3b Michael Hanselmann
      "%s.%s" % (self.__class__.__module__, self.__class__.__name__),
167 e80edd3b Michael Hanselmann
      "primary=%s" % self.primary,
168 e80edd3b Michael Hanselmann
      "secondary=%s" % self.secondary,
169 e80edd3b Michael Hanselmann
      "added=%s" % self._added,
170 e80edd3b Michael Hanselmann
      "use_count=%s" % self._use_count,
171 e80edd3b Michael Hanselmann
      ]
172 e80edd3b Michael Hanselmann
173 e80edd3b Michael Hanselmann
    return "<%s at %#x>" % (" ".join(status), id(self))
174 e80edd3b Michael Hanselmann
175 dbdb0594 Michael Hanselmann
  def Use(self):
176 dbdb0594 Michael Hanselmann
    """Marks a node as being in use.
177 dbdb0594 Michael Hanselmann

178 dbdb0594 Michael Hanselmann
    """
179 565cb4bf Michael Hanselmann
    assert self._use_count >= 0
180 dbdb0594 Michael Hanselmann
181 565cb4bf Michael Hanselmann
    self._use_count += 1
182 dbdb0594 Michael Hanselmann
183 dbdb0594 Michael Hanselmann
    return self
184 dbdb0594 Michael Hanselmann
185 565cb4bf Michael Hanselmann
  def Release(self):
186 565cb4bf Michael Hanselmann
    """Release a node (opposite of L{Use}).
187 565cb4bf Michael Hanselmann

188 565cb4bf Michael Hanselmann
    """
189 565cb4bf Michael Hanselmann
    assert self.use_count > 0
190 565cb4bf Michael Hanselmann
191 565cb4bf Michael Hanselmann
    self._use_count -= 1
192 565cb4bf Michael Hanselmann
193 dbdb0594 Michael Hanselmann
  def MarkAdded(self):
194 dbdb0594 Michael Hanselmann
    """Marks node as having been added to a cluster.
195 dbdb0594 Michael Hanselmann

196 dbdb0594 Michael Hanselmann
    """
197 dbdb0594 Michael Hanselmann
    assert not self._added
198 dbdb0594 Michael Hanselmann
    self._added = True
199 dbdb0594 Michael Hanselmann
200 dbdb0594 Michael Hanselmann
  def MarkRemoved(self):
201 dbdb0594 Michael Hanselmann
    """Marks node as having been removed from a cluster.
202 dbdb0594 Michael Hanselmann

203 dbdb0594 Michael Hanselmann
    """
204 dbdb0594 Michael Hanselmann
    assert self._added
205 dbdb0594 Michael Hanselmann
    self._added = False
206 dbdb0594 Michael Hanselmann
207 dbdb0594 Michael Hanselmann
  @property
208 dbdb0594 Michael Hanselmann
  def added(self):
209 dbdb0594 Michael Hanselmann
    """Returns whether a node is part of a cluster.
210 dbdb0594 Michael Hanselmann

211 dbdb0594 Michael Hanselmann
    """
212 dbdb0594 Michael Hanselmann
    return self._added
213 dbdb0594 Michael Hanselmann
214 565cb4bf Michael Hanselmann
  @property
215 565cb4bf Michael Hanselmann
  def use_count(self):
216 565cb4bf Michael Hanselmann
    """Returns number of current uses (controlled by L{Use} and L{Release}).
217 565cb4bf Michael Hanselmann

218 565cb4bf Michael Hanselmann
    """
219 565cb4bf Michael Hanselmann
    return self._use_count
220 565cb4bf Michael Hanselmann
221 dbdb0594 Michael Hanselmann
222 6a654276 Michael Hanselmann
_RESOURCE_CONVERTER = {
223 6a654276 Michael Hanselmann
  "instances": _QaInstance.FromDict,
224 dbdb0594 Michael Hanselmann
  "nodes": _QaNode.FromDict,
225 6a654276 Michael Hanselmann
  }
226 6a654276 Michael Hanselmann
227 6a654276 Michael Hanselmann
228 6a654276 Michael Hanselmann
def _ConvertResources((key, value)):
229 6a654276 Michael Hanselmann
  """Converts cluster resources in configuration to Python objects.
230 6a654276 Michael Hanselmann

231 6a654276 Michael Hanselmann
  """
232 6a654276 Michael Hanselmann
  fn = _RESOURCE_CONVERTER.get(key, None)
233 6a654276 Michael Hanselmann
  if fn:
234 6a654276 Michael Hanselmann
    return (key, map(fn, value))
235 6a654276 Michael Hanselmann
  else:
236 6a654276 Michael Hanselmann
    return (key, value)
237 6a654276 Michael Hanselmann
238 6a654276 Michael Hanselmann
239 8a96c5a6 Michael Hanselmann
class _QaConfig(object):
240 8a96c5a6 Michael Hanselmann
  def __init__(self, data):
241 8a96c5a6 Michael Hanselmann
    """Initializes instances of this class.
242 cec9845c Michael Hanselmann

243 8a96c5a6 Michael Hanselmann
    """
244 8a96c5a6 Michael Hanselmann
    self._data = data
245 8a96c5a6 Michael Hanselmann
246 a08e181f Michael Hanselmann
    #: Cluster-wide run-time value of the exclusive storage flag
247 a08e181f Michael Hanselmann
    self._exclusive_storage = None
248 a08e181f Michael Hanselmann
249 8a96c5a6 Michael Hanselmann
  @classmethod
250 8a96c5a6 Michael Hanselmann
  def Load(cls, filename):
251 8a96c5a6 Michael Hanselmann
    """Loads a configuration file and produces a configuration object.
252 8a96c5a6 Michael Hanselmann

253 8a96c5a6 Michael Hanselmann
    @type filename: string
254 8a96c5a6 Michael Hanselmann
    @param filename: Path to configuration file
255 8a96c5a6 Michael Hanselmann
    @rtype: L{_QaConfig}
256 8a96c5a6 Michael Hanselmann

257 8a96c5a6 Michael Hanselmann
    """
258 8a96c5a6 Michael Hanselmann
    data = serializer.LoadJson(utils.ReadFile(filename))
259 8a96c5a6 Michael Hanselmann
260 6a654276 Michael Hanselmann
    result = cls(dict(map(_ConvertResources,
261 6a654276 Michael Hanselmann
                          data.items()))) # pylint: disable=E1103
262 8a96c5a6 Michael Hanselmann
    result.Validate()
263 8a96c5a6 Michael Hanselmann
264 8a96c5a6 Michael Hanselmann
    return result
265 8a96c5a6 Michael Hanselmann
266 8a96c5a6 Michael Hanselmann
  def Validate(self):
267 8a96c5a6 Michael Hanselmann
    """Validates loaded configuration data.
268 8a96c5a6 Michael Hanselmann

269 8a96c5a6 Michael Hanselmann
    """
270 47aa6ec9 Michael Hanselmann
    if not self.get("name"):
271 47aa6ec9 Michael Hanselmann
      raise qa_error.Error("Cluster name is required")
272 47aa6ec9 Michael Hanselmann
273 8a96c5a6 Michael Hanselmann
    if not self.get("nodes"):
274 8a96c5a6 Michael Hanselmann
      raise qa_error.Error("Need at least one node")
275 8a96c5a6 Michael Hanselmann
276 8a96c5a6 Michael Hanselmann
    if not self.get("instances"):
277 8a96c5a6 Michael Hanselmann
      raise qa_error.Error("Need at least one instance")
278 8a96c5a6 Michael Hanselmann
279 8a96c5a6 Michael Hanselmann
    if (self.get("disk") is None or
280 8a96c5a6 Michael Hanselmann
        self.get("disk-growth") is None or
281 8a96c5a6 Michael Hanselmann
        len(self.get("disk")) != len(self.get("disk-growth"))):
282 8a96c5a6 Michael Hanselmann
      raise qa_error.Error("Config options 'disk' and 'disk-growth' must exist"
283 8a96c5a6 Michael Hanselmann
                           " and have the same number of items")
284 8a96c5a6 Michael Hanselmann
285 8a96c5a6 Michael Hanselmann
    check = self.GetInstanceCheckScript()
286 8a96c5a6 Michael Hanselmann
    if check:
287 8a96c5a6 Michael Hanselmann
      try:
288 8a96c5a6 Michael Hanselmann
        os.stat(check)
289 8a96c5a6 Michael Hanselmann
      except EnvironmentError, err:
290 8a96c5a6 Michael Hanselmann
        raise qa_error.Error("Can't find instance check script '%s': %s" %
291 8a96c5a6 Michael Hanselmann
                             (check, err))
292 8a96c5a6 Michael Hanselmann
293 8a96c5a6 Michael Hanselmann
    enabled_hv = frozenset(self.GetEnabledHypervisors())
294 8a96c5a6 Michael Hanselmann
    if not enabled_hv:
295 8a96c5a6 Michael Hanselmann
      raise qa_error.Error("No hypervisor is enabled")
296 8a96c5a6 Michael Hanselmann
297 8a96c5a6 Michael Hanselmann
    difference = enabled_hv - constants.HYPER_TYPES
298 8a96c5a6 Michael Hanselmann
    if difference:
299 8a96c5a6 Michael Hanselmann
      raise qa_error.Error("Unknown hypervisor(s) enabled: %s" %
300 8a96c5a6 Michael Hanselmann
                           utils.CommaJoin(difference))
301 8a96c5a6 Michael Hanselmann
302 8a96c5a6 Michael Hanselmann
  def __getitem__(self, name):
303 8a96c5a6 Michael Hanselmann
    """Returns configuration value.
304 8a96c5a6 Michael Hanselmann

305 8a96c5a6 Michael Hanselmann
    @type name: string
306 8a96c5a6 Michael Hanselmann
    @param name: Name of configuration entry
307 8a96c5a6 Michael Hanselmann

308 8a96c5a6 Michael Hanselmann
    """
309 8a96c5a6 Michael Hanselmann
    return self._data[name]
310 8a96c5a6 Michael Hanselmann
311 8a96c5a6 Michael Hanselmann
  def get(self, name, default=None):
312 8a96c5a6 Michael Hanselmann
    """Returns configuration value.
313 8a96c5a6 Michael Hanselmann

314 8a96c5a6 Michael Hanselmann
    @type name: string
315 8a96c5a6 Michael Hanselmann
    @param name: Name of configuration entry
316 8a96c5a6 Michael Hanselmann
    @param default: Default value
317 8a96c5a6 Michael Hanselmann

318 8a96c5a6 Michael Hanselmann
    """
319 8a96c5a6 Michael Hanselmann
    return self._data.get(name, default)
320 cec9845c Michael Hanselmann
321 8a96c5a6 Michael Hanselmann
  def GetMasterNode(self):
322 8a96c5a6 Michael Hanselmann
    """Returns the default master node for the cluster.
323 cec9845c Michael Hanselmann

324 8a96c5a6 Michael Hanselmann
    """
325 8a96c5a6 Michael Hanselmann
    return self["nodes"][0]
326 8a96c5a6 Michael Hanselmann
327 8a96c5a6 Michael Hanselmann
  def GetInstanceCheckScript(self):
328 8a96c5a6 Michael Hanselmann
    """Returns path to instance check script or C{None}.
329 8a96c5a6 Michael Hanselmann

330 8a96c5a6 Michael Hanselmann
    """
331 8a96c5a6 Michael Hanselmann
    return self._data.get(_INSTANCE_CHECK_KEY, None)
332 cec9845c Michael Hanselmann
333 8a96c5a6 Michael Hanselmann
  def GetEnabledHypervisors(self):
334 8a96c5a6 Michael Hanselmann
    """Returns list of enabled hypervisors.
335 cec9845c Michael Hanselmann

336 8a96c5a6 Michael Hanselmann
    @rtype: list
337 cec9845c Michael Hanselmann

338 8a96c5a6 Michael Hanselmann
    """
339 c9e05005 Michael Hanselmann
    try:
340 8a96c5a6 Michael Hanselmann
      value = self._data[_ENABLED_HV_KEY]
341 8a96c5a6 Michael Hanselmann
    except KeyError:
342 8a96c5a6 Michael Hanselmann
      return [constants.DEFAULT_ENABLED_HYPERVISOR]
343 8a96c5a6 Michael Hanselmann
    else:
344 8a96c5a6 Michael Hanselmann
      if value is None:
345 8a96c5a6 Michael Hanselmann
        return []
346 8a96c5a6 Michael Hanselmann
      elif isinstance(value, basestring):
347 8a96c5a6 Michael Hanselmann
        # The configuration key ("enabled-hypervisors") implies there can be
348 8a96c5a6 Michael Hanselmann
        # multiple values. Multiple hypervisors are comma-separated on the
349 8a96c5a6 Michael Hanselmann
        # command line option to "gnt-cluster init", so we need to handle them
350 8a96c5a6 Michael Hanselmann
        # equally here.
351 8a96c5a6 Michael Hanselmann
        return value.split(",")
352 8a96c5a6 Michael Hanselmann
      else:
353 8a96c5a6 Michael Hanselmann
        return value
354 8a96c5a6 Michael Hanselmann
355 8a96c5a6 Michael Hanselmann
  def GetDefaultHypervisor(self):
356 8a96c5a6 Michael Hanselmann
    """Returns the default hypervisor to be used.
357 8a96c5a6 Michael Hanselmann

358 8a96c5a6 Michael Hanselmann
    """
359 8a96c5a6 Michael Hanselmann
    return self.GetEnabledHypervisors()[0]
360 8a96c5a6 Michael Hanselmann
361 a08e181f Michael Hanselmann
  def SetExclusiveStorage(self, value):
362 a08e181f Michael Hanselmann
    """Set the expected value of the C{exclusive_storage} flag for the cluster.
363 a08e181f Michael Hanselmann

364 a08e181f Michael Hanselmann
    """
365 a08e181f Michael Hanselmann
    self._exclusive_storage = bool(value)
366 a08e181f Michael Hanselmann
367 a08e181f Michael Hanselmann
  def GetExclusiveStorage(self):
368 a08e181f Michael Hanselmann
    """Get the expected value of the C{exclusive_storage} flag for the cluster.
369 a08e181f Michael Hanselmann

370 a08e181f Michael Hanselmann
    """
371 a08e181f Michael Hanselmann
    value = self._exclusive_storage
372 a08e181f Michael Hanselmann
    assert value is not None
373 a08e181f Michael Hanselmann
    return value
374 a08e181f Michael Hanselmann
375 a08e181f Michael Hanselmann
  def IsTemplateSupported(self, templ):
376 a08e181f Michael Hanselmann
    """Is the given disk template supported by the current configuration?
377 a08e181f Michael Hanselmann

378 a08e181f Michael Hanselmann
    """
379 cf62af3a Michael Hanselmann
    return (not self.GetExclusiveStorage() or
380 cf62af3a Michael Hanselmann
            templ in constants.DTS_EXCL_STORAGE)
381 a08e181f Michael Hanselmann
382 8a96c5a6 Michael Hanselmann
383 8a96c5a6 Michael Hanselmann
def Load(path):
384 8a96c5a6 Michael Hanselmann
  """Loads the passed configuration file.
385 8a96c5a6 Michael Hanselmann

386 8a96c5a6 Michael Hanselmann
  """
387 8a96c5a6 Michael Hanselmann
  global _config # pylint: disable=W0603
388 8a96c5a6 Michael Hanselmann
389 8a96c5a6 Michael Hanselmann
  _config = _QaConfig.Load(path)
390 c9e05005 Michael Hanselmann
391 e7b6183b Michael Hanselmann
392 8a96c5a6 Michael Hanselmann
def GetConfig():
393 8a96c5a6 Michael Hanselmann
  """Returns the configuration object.
394 8a96c5a6 Michael Hanselmann

395 8a96c5a6 Michael Hanselmann
  """
396 8a96c5a6 Michael Hanselmann
  if _config is None:
397 8a96c5a6 Michael Hanselmann
    raise RuntimeError("Configuration not yet loaded")
398 8a96c5a6 Michael Hanselmann
399 8a96c5a6 Michael Hanselmann
  return _config
400 e7b6183b Michael Hanselmann
401 cec9845c Michael Hanselmann
402 cec9845c Michael Hanselmann
def get(name, default=None):
403 8a96c5a6 Michael Hanselmann
  """Wrapper for L{_QaConfig.get}.
404 8a96c5a6 Michael Hanselmann

405 8a96c5a6 Michael Hanselmann
  """
406 8a96c5a6 Michael Hanselmann
  return GetConfig().get(name, default=default)
407 cec9845c Michael Hanselmann
408 cec9845c Michael Hanselmann
409 a0c3e726 Michael Hanselmann
class Either:
410 a0c3e726 Michael Hanselmann
  def __init__(self, tests):
411 a0c3e726 Michael Hanselmann
    """Initializes this class.
412 a0c3e726 Michael Hanselmann

413 a0c3e726 Michael Hanselmann
    @type tests: list or string
414 a0c3e726 Michael Hanselmann
    @param tests: List of test names
415 a0c3e726 Michael Hanselmann
    @see: L{TestEnabled} for details
416 a0c3e726 Michael Hanselmann

417 a0c3e726 Michael Hanselmann
    """
418 a0c3e726 Michael Hanselmann
    self.tests = tests
419 a0c3e726 Michael Hanselmann
420 a0c3e726 Michael Hanselmann
421 a0c3e726 Michael Hanselmann
def _MakeSequence(value):
422 a0c3e726 Michael Hanselmann
  """Make sequence of single argument.
423 a0c3e726 Michael Hanselmann

424 a0c3e726 Michael Hanselmann
  If the single argument is not already a list or tuple, a list with the
425 a0c3e726 Michael Hanselmann
  argument as a single item is returned.
426 a0c3e726 Michael Hanselmann

427 a0c3e726 Michael Hanselmann
  """
428 a0c3e726 Michael Hanselmann
  if isinstance(value, (list, tuple)):
429 a0c3e726 Michael Hanselmann
    return value
430 a0c3e726 Michael Hanselmann
  else:
431 a0c3e726 Michael Hanselmann
    return [value]
432 a0c3e726 Michael Hanselmann
433 a0c3e726 Michael Hanselmann
434 a0c3e726 Michael Hanselmann
def _TestEnabledInner(check_fn, names, fn):
435 a0c3e726 Michael Hanselmann
  """Evaluate test conditions.
436 a0c3e726 Michael Hanselmann

437 a0c3e726 Michael Hanselmann
  @type check_fn: callable
438 a0c3e726 Michael Hanselmann
  @param check_fn: Callback to check whether a test is enabled
439 a0c3e726 Michael Hanselmann
  @type names: sequence or string
440 a0c3e726 Michael Hanselmann
  @param names: Test name(s)
441 a0c3e726 Michael Hanselmann
  @type fn: callable
442 a0c3e726 Michael Hanselmann
  @param fn: Aggregation function
443 a0c3e726 Michael Hanselmann
  @rtype: bool
444 a0c3e726 Michael Hanselmann
  @return: Whether test is enabled
445 a0c3e726 Michael Hanselmann

446 a0c3e726 Michael Hanselmann
  """
447 a0c3e726 Michael Hanselmann
  names = _MakeSequence(names)
448 a0c3e726 Michael Hanselmann
449 a0c3e726 Michael Hanselmann
  result = []
450 a0c3e726 Michael Hanselmann
451 a0c3e726 Michael Hanselmann
  for name in names:
452 a0c3e726 Michael Hanselmann
    if isinstance(name, Either):
453 a0c3e726 Michael Hanselmann
      value = _TestEnabledInner(check_fn, name.tests, compat.any)
454 a0c3e726 Michael Hanselmann
    elif isinstance(name, (list, tuple)):
455 a0c3e726 Michael Hanselmann
      value = _TestEnabledInner(check_fn, name, compat.all)
456 a0c3e726 Michael Hanselmann
    else:
457 a0c3e726 Michael Hanselmann
      value = check_fn(name)
458 a0c3e726 Michael Hanselmann
459 a0c3e726 Michael Hanselmann
    result.append(value)
460 a0c3e726 Michael Hanselmann
461 a0c3e726 Michael Hanselmann
  return fn(result)
462 a0c3e726 Michael Hanselmann
463 a0c3e726 Michael Hanselmann
464 a0c3e726 Michael Hanselmann
def TestEnabled(tests, _cfg=None):
465 7d88f255 Iustin Pop
  """Returns True if the given tests are enabled.
466 7d88f255 Iustin Pop

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

470 1010ec70 Michael Hanselmann
  """
471 a0c3e726 Michael Hanselmann
  if _cfg is None:
472 8a96c5a6 Michael Hanselmann
    cfg = GetConfig()
473 8a96c5a6 Michael Hanselmann
  else:
474 8a96c5a6 Michael Hanselmann
    cfg = _cfg
475 59a8fe48 Michael Hanselmann
476 59a8fe48 Michael Hanselmann
  # Get settings for all tests
477 8a96c5a6 Michael Hanselmann
  cfg_tests = cfg.get("tests", {})
478 59a8fe48 Michael Hanselmann
479 59a8fe48 Michael Hanselmann
  # Get default setting
480 a0c3e726 Michael Hanselmann
  default = cfg_tests.get("default", True)
481 59a8fe48 Michael Hanselmann
482 a0c3e726 Michael Hanselmann
  return _TestEnabledInner(lambda name: cfg_tests.get(name, default),
483 a0c3e726 Michael Hanselmann
                           tests, compat.all)
484 cec9845c Michael Hanselmann
485 cec9845c Michael Hanselmann
486 8a96c5a6 Michael Hanselmann
def GetInstanceCheckScript(*args):
487 8a96c5a6 Michael Hanselmann
  """Wrapper for L{_QaConfig.GetInstanceCheckScript}.
488 c9e05005 Michael Hanselmann

489 c9e05005 Michael Hanselmann
  """
490 8a96c5a6 Michael Hanselmann
  return GetConfig().GetInstanceCheckScript(*args)
491 c9e05005 Michael Hanselmann
492 e7b6183b Michael Hanselmann
493 8a96c5a6 Michael Hanselmann
def GetEnabledHypervisors(*args):
494 8a96c5a6 Michael Hanselmann
  """Wrapper for L{_QaConfig.GetEnabledHypervisors}.
495 e7b6183b Michael Hanselmann

496 e7b6183b Michael Hanselmann
  """
497 8a96c5a6 Michael Hanselmann
  return GetConfig().GetEnabledHypervisors(*args)
498 e7b6183b Michael Hanselmann
499 e7b6183b Michael Hanselmann
500 8a96c5a6 Michael Hanselmann
def GetDefaultHypervisor(*args):
501 8a96c5a6 Michael Hanselmann
  """Wrapper for L{_QaConfig.GetDefaultHypervisor}.
502 e7b6183b Michael Hanselmann

503 e7b6183b Michael Hanselmann
  """
504 8a96c5a6 Michael Hanselmann
  return GetConfig().GetDefaultHypervisor(*args)
505 e7b6183b Michael Hanselmann
506 e7b6183b Michael Hanselmann
507 cec9845c Michael Hanselmann
def GetMasterNode():
508 8a96c5a6 Michael Hanselmann
  """Wrapper for L{_QaConfig.GetMasterNode}.
509 8a96c5a6 Michael Hanselmann

510 8a96c5a6 Michael Hanselmann
  """
511 8a96c5a6 Michael Hanselmann
  return GetConfig().GetMasterNode()
512 cec9845c Michael Hanselmann
513 cec9845c Michael Hanselmann
514 6a654276 Michael Hanselmann
def AcquireInstance(_cfg=None):
515 cec9845c Michael Hanselmann
  """Returns an instance which isn't in use.
516 cec9845c Michael Hanselmann

517 cec9845c Michael Hanselmann
  """
518 6a654276 Michael Hanselmann
  if _cfg is None:
519 6a654276 Michael Hanselmann
    cfg = GetConfig()
520 6a654276 Michael Hanselmann
  else:
521 6a654276 Michael Hanselmann
    cfg = _cfg
522 6a654276 Michael Hanselmann
523 cec9845c Michael Hanselmann
  # Filter out unwanted instances
524 6a654276 Michael Hanselmann
  instances = filter(lambda inst: not inst.used, cfg["instances"])
525 cec9845c Michael Hanselmann
526 6a654276 Michael Hanselmann
  if not instances:
527 cec9845c Michael Hanselmann
    raise qa_error.OutOfInstancesError("No instances left")
528 cec9845c Michael Hanselmann
529 2176724e Michael Hanselmann
  instance = instances[0]
530 2176724e Michael Hanselmann
  instance.Use()
531 6a654276 Michael Hanselmann
532 2176724e Michael Hanselmann
  return instance
533 cec9845c Michael Hanselmann
534 cec9845c Michael Hanselmann
535 6a0f22e1 Bernardo Dal Seno
def SetExclusiveStorage(value):
536 a08e181f Michael Hanselmann
  """Wrapper for L{_QaConfig.SetExclusiveStorage}.
537 6a0f22e1 Bernardo Dal Seno

538 6a0f22e1 Bernardo Dal Seno
  """
539 a08e181f Michael Hanselmann
  return GetConfig().SetExclusiveStorage(value)
540 6a0f22e1 Bernardo Dal Seno
541 6a0f22e1 Bernardo Dal Seno
542 6a0f22e1 Bernardo Dal Seno
def GetExclusiveStorage():
543 a08e181f Michael Hanselmann
  """Wrapper for L{_QaConfig.GetExclusiveStorage}.
544 6a0f22e1 Bernardo Dal Seno

545 6a0f22e1 Bernardo Dal Seno
  """
546 a08e181f Michael Hanselmann
  return GetConfig().GetExclusiveStorage()
547 6a0f22e1 Bernardo Dal Seno
548 6a0f22e1 Bernardo Dal Seno
549 27eba428 Bernardo Dal Seno
def IsTemplateSupported(templ):
550 a08e181f Michael Hanselmann
  """Wrapper for L{_QaConfig.GetExclusiveStorage}.
551 27eba428 Bernardo Dal Seno

552 27eba428 Bernardo Dal Seno
  """
553 a08e181f Michael Hanselmann
  return GetConfig().IsTemplateSupported(templ)
554 27eba428 Bernardo Dal Seno
555 27eba428 Bernardo Dal Seno
556 dbdb0594 Michael Hanselmann
def AcquireNode(exclude=None, _cfg=None):
557 cec9845c Michael Hanselmann
  """Returns the least used node.
558 cec9845c Michael Hanselmann

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

597 7d4f1b45 Bernardo Dal Seno
  @type num: int
598 7d4f1b45 Bernardo Dal Seno
  @param num: Number of nodes; can be 0.
599 7d4f1b45 Bernardo Dal Seno
  @type exclude: list of nodes or C{None}
600 7d4f1b45 Bernardo Dal Seno
  @param exclude: nodes to be excluded from the choice
601 7d4f1b45 Bernardo Dal Seno
  @rtype: list of nodes
602 7d4f1b45 Bernardo Dal Seno
  @return: C{num} different nodes
603 7d4f1b45 Bernardo Dal Seno

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