Statistics
| Branch: | Tag: | Revision:

root / qa / qa_config.py @ c072e788

History | View | Annotate | Download (15 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 76fda900 Michael Hanselmann
from ganeti import ht
33 cec9845c Michael Hanselmann
34 cec9845c Michael Hanselmann
import qa_error
35 cec9845c Michael Hanselmann
36 cec9845c Michael Hanselmann
37 c9e05005 Michael Hanselmann
_INSTANCE_CHECK_KEY = "instance-check"
38 e7b6183b Michael Hanselmann
_ENABLED_HV_KEY = "enabled-hypervisors"
39 76fda900 Michael Hanselmann
_VCLUSTER_MASTER_KEY = "vcluster-master"
40 76fda900 Michael Hanselmann
_VCLUSTER_BASEDIR_KEY = "vcluster-basedir"
41 f9329a6c Michael Hanselmann
42 8a96c5a6 Michael Hanselmann
#: QA configuration (L{_QaConfig})
43 8a96c5a6 Michael Hanselmann
_config = None
44 cec9845c Michael Hanselmann
45 cec9845c Michael Hanselmann
46 6a654276 Michael Hanselmann
class _QaInstance(object):
47 6a654276 Michael Hanselmann
  __slots__ = [
48 6a654276 Michael Hanselmann
    "name",
49 6a654276 Michael Hanselmann
    "nicmac",
50 2176724e Michael Hanselmann
    "_used",
51 02a5fe0e Michael Hanselmann
    "_disk_template",
52 6a654276 Michael Hanselmann
    ]
53 6a654276 Michael Hanselmann
54 6a654276 Michael Hanselmann
  def __init__(self, name, nicmac):
55 6a654276 Michael Hanselmann
    """Initializes instances of this class.
56 6a654276 Michael Hanselmann

57 6a654276 Michael Hanselmann
    """
58 6a654276 Michael Hanselmann
    self.name = name
59 6a654276 Michael Hanselmann
    self.nicmac = nicmac
60 2176724e Michael Hanselmann
    self._used = None
61 02a5fe0e Michael Hanselmann
    self._disk_template = None
62 6a654276 Michael Hanselmann
63 6a654276 Michael Hanselmann
  @classmethod
64 6a654276 Michael Hanselmann
  def FromDict(cls, data):
65 6a654276 Michael Hanselmann
    """Creates instance object from JSON dictionary.
66 6a654276 Michael Hanselmann

67 6a654276 Michael Hanselmann
    """
68 6a654276 Michael Hanselmann
    nicmac = []
69 6a654276 Michael Hanselmann
70 6a654276 Michael Hanselmann
    macaddr = data.get("nic.mac/0")
71 6a654276 Michael Hanselmann
    if macaddr:
72 6a654276 Michael Hanselmann
      nicmac.append(macaddr)
73 6a654276 Michael Hanselmann
74 6a654276 Michael Hanselmann
    return cls(name=data["name"], nicmac=nicmac)
75 6a654276 Michael Hanselmann
76 e80edd3b Michael Hanselmann
  def __repr__(self):
77 e80edd3b Michael Hanselmann
    status = [
78 e80edd3b Michael Hanselmann
      "%s.%s" % (self.__class__.__module__, self.__class__.__name__),
79 e80edd3b Michael Hanselmann
      "name=%s" % self.name,
80 e80edd3b Michael Hanselmann
      "nicmac=%s" % self.nicmac,
81 e80edd3b Michael Hanselmann
      "used=%s" % self._used,
82 e80edd3b Michael Hanselmann
      "disk_template=%s" % self._disk_template,
83 e80edd3b Michael Hanselmann
      ]
84 e80edd3b Michael Hanselmann
85 e80edd3b Michael Hanselmann
    return "<%s at %#x>" % (" ".join(status), id(self))
86 e80edd3b Michael Hanselmann
87 2176724e Michael Hanselmann
  def Use(self):
88 2176724e Michael Hanselmann
    """Marks instance as being in use.
89 2176724e Michael Hanselmann

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

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

110 6a654276 Michael Hanselmann
    @type idx: int
111 6a654276 Michael Hanselmann
    @param idx: NIC index
112 6a654276 Michael Hanselmann
    @param default: Default value
113 6a654276 Michael Hanselmann

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

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

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

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

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

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

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

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

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

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

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

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

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

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

256 8a96c5a6 Michael Hanselmann
    @type filename: string
257 8a96c5a6 Michael Hanselmann
    @param filename: Path to configuration file
258 8a96c5a6 Michael Hanselmann
    @rtype: L{_QaConfig}
259 8a96c5a6 Michael Hanselmann

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

272 8a96c5a6 Michael Hanselmann
    """
273 47aa6ec9 Michael Hanselmann
    if not self.get("name"):
274 47aa6ec9 Michael Hanselmann
      raise qa_error.Error("Cluster name is required")
275 47aa6ec9 Michael Hanselmann
276 8a96c5a6 Michael Hanselmann
    if not self.get("nodes"):
277 8a96c5a6 Michael Hanselmann
      raise qa_error.Error("Need at least one node")
278 8a96c5a6 Michael Hanselmann
279 8a96c5a6 Michael Hanselmann
    if not self.get("instances"):
280 8a96c5a6 Michael Hanselmann
      raise qa_error.Error("Need at least one instance")
281 8a96c5a6 Michael Hanselmann
282 8a96c5a6 Michael Hanselmann
    if (self.get("disk") is None or
283 8a96c5a6 Michael Hanselmann
        self.get("disk-growth") is None or
284 8a96c5a6 Michael Hanselmann
        len(self.get("disk")) != len(self.get("disk-growth"))):
285 8a96c5a6 Michael Hanselmann
      raise qa_error.Error("Config options 'disk' and 'disk-growth' must exist"
286 8a96c5a6 Michael Hanselmann
                           " and have the same number of items")
287 8a96c5a6 Michael Hanselmann
288 8a96c5a6 Michael Hanselmann
    check = self.GetInstanceCheckScript()
289 8a96c5a6 Michael Hanselmann
    if check:
290 8a96c5a6 Michael Hanselmann
      try:
291 8a96c5a6 Michael Hanselmann
        os.stat(check)
292 8a96c5a6 Michael Hanselmann
      except EnvironmentError, err:
293 8a96c5a6 Michael Hanselmann
        raise qa_error.Error("Can't find instance check script '%s': %s" %
294 8a96c5a6 Michael Hanselmann
                             (check, err))
295 8a96c5a6 Michael Hanselmann
296 8a96c5a6 Michael Hanselmann
    enabled_hv = frozenset(self.GetEnabledHypervisors())
297 8a96c5a6 Michael Hanselmann
    if not enabled_hv:
298 8a96c5a6 Michael Hanselmann
      raise qa_error.Error("No hypervisor is enabled")
299 8a96c5a6 Michael Hanselmann
300 8a96c5a6 Michael Hanselmann
    difference = enabled_hv - constants.HYPER_TYPES
301 8a96c5a6 Michael Hanselmann
    if difference:
302 8a96c5a6 Michael Hanselmann
      raise qa_error.Error("Unknown hypervisor(s) enabled: %s" %
303 8a96c5a6 Michael Hanselmann
                           utils.CommaJoin(difference))
304 8a96c5a6 Michael Hanselmann
305 76fda900 Michael Hanselmann
    (vc_master, vc_basedir) = self.GetVclusterSettings()
306 76fda900 Michael Hanselmann
    if bool(vc_master) != bool(vc_basedir):
307 76fda900 Michael Hanselmann
      raise qa_error.Error("All or none of the config options '%s' and '%s'"
308 76fda900 Michael Hanselmann
                           " must be set" %
309 76fda900 Michael Hanselmann
                           (_VCLUSTER_MASTER_KEY, _VCLUSTER_BASEDIR_KEY))
310 76fda900 Michael Hanselmann
311 76fda900 Michael Hanselmann
    if vc_basedir and not utils.IsNormAbsPath(vc_basedir):
312 76fda900 Michael Hanselmann
      raise qa_error.Error("Path given in option '%s' must be absolute and"
313 76fda900 Michael Hanselmann
                           " normalized" % _VCLUSTER_BASEDIR_KEY)
314 76fda900 Michael Hanselmann
315 8a96c5a6 Michael Hanselmann
  def __getitem__(self, name):
316 8a96c5a6 Michael Hanselmann
    """Returns configuration value.
317 8a96c5a6 Michael Hanselmann

318 8a96c5a6 Michael Hanselmann
    @type name: string
319 8a96c5a6 Michael Hanselmann
    @param name: Name of configuration entry
320 8a96c5a6 Michael Hanselmann

321 8a96c5a6 Michael Hanselmann
    """
322 8a96c5a6 Michael Hanselmann
    return self._data[name]
323 8a96c5a6 Michael Hanselmann
324 8a96c5a6 Michael Hanselmann
  def get(self, name, default=None):
325 8a96c5a6 Michael Hanselmann
    """Returns configuration value.
326 8a96c5a6 Michael Hanselmann

327 8a96c5a6 Michael Hanselmann
    @type name: string
328 8a96c5a6 Michael Hanselmann
    @param name: Name of configuration entry
329 8a96c5a6 Michael Hanselmann
    @param default: Default value
330 8a96c5a6 Michael Hanselmann

331 8a96c5a6 Michael Hanselmann
    """
332 8a96c5a6 Michael Hanselmann
    return self._data.get(name, default)
333 cec9845c Michael Hanselmann
334 8a96c5a6 Michael Hanselmann
  def GetMasterNode(self):
335 8a96c5a6 Michael Hanselmann
    """Returns the default master node for the cluster.
336 cec9845c Michael Hanselmann

337 8a96c5a6 Michael Hanselmann
    """
338 8a96c5a6 Michael Hanselmann
    return self["nodes"][0]
339 8a96c5a6 Michael Hanselmann
340 8a96c5a6 Michael Hanselmann
  def GetInstanceCheckScript(self):
341 8a96c5a6 Michael Hanselmann
    """Returns path to instance check script or C{None}.
342 8a96c5a6 Michael Hanselmann

343 8a96c5a6 Michael Hanselmann
    """
344 8a96c5a6 Michael Hanselmann
    return self._data.get(_INSTANCE_CHECK_KEY, None)
345 cec9845c Michael Hanselmann
346 8a96c5a6 Michael Hanselmann
  def GetEnabledHypervisors(self):
347 8a96c5a6 Michael Hanselmann
    """Returns list of enabled hypervisors.
348 cec9845c Michael Hanselmann

349 8a96c5a6 Michael Hanselmann
    @rtype: list
350 cec9845c Michael Hanselmann

351 8a96c5a6 Michael Hanselmann
    """
352 c9e05005 Michael Hanselmann
    try:
353 8a96c5a6 Michael Hanselmann
      value = self._data[_ENABLED_HV_KEY]
354 8a96c5a6 Michael Hanselmann
    except KeyError:
355 8a96c5a6 Michael Hanselmann
      return [constants.DEFAULT_ENABLED_HYPERVISOR]
356 8a96c5a6 Michael Hanselmann
    else:
357 8a96c5a6 Michael Hanselmann
      if value is None:
358 8a96c5a6 Michael Hanselmann
        return []
359 8a96c5a6 Michael Hanselmann
      elif isinstance(value, basestring):
360 8a96c5a6 Michael Hanselmann
        # The configuration key ("enabled-hypervisors") implies there can be
361 8a96c5a6 Michael Hanselmann
        # multiple values. Multiple hypervisors are comma-separated on the
362 8a96c5a6 Michael Hanselmann
        # command line option to "gnt-cluster init", so we need to handle them
363 8a96c5a6 Michael Hanselmann
        # equally here.
364 8a96c5a6 Michael Hanselmann
        return value.split(",")
365 8a96c5a6 Michael Hanselmann
      else:
366 8a96c5a6 Michael Hanselmann
        return value
367 8a96c5a6 Michael Hanselmann
368 8a96c5a6 Michael Hanselmann
  def GetDefaultHypervisor(self):
369 8a96c5a6 Michael Hanselmann
    """Returns the default hypervisor to be used.
370 8a96c5a6 Michael Hanselmann

371 8a96c5a6 Michael Hanselmann
    """
372 8a96c5a6 Michael Hanselmann
    return self.GetEnabledHypervisors()[0]
373 8a96c5a6 Michael Hanselmann
374 a08e181f Michael Hanselmann
  def SetExclusiveStorage(self, value):
375 a08e181f Michael Hanselmann
    """Set the expected value of the C{exclusive_storage} flag for the cluster.
376 a08e181f Michael Hanselmann

377 a08e181f Michael Hanselmann
    """
378 a08e181f Michael Hanselmann
    self._exclusive_storage = bool(value)
379 a08e181f Michael Hanselmann
380 a08e181f Michael Hanselmann
  def GetExclusiveStorage(self):
381 a08e181f Michael Hanselmann
    """Get the expected value of the C{exclusive_storage} flag for the cluster.
382 a08e181f Michael Hanselmann

383 a08e181f Michael Hanselmann
    """
384 a08e181f Michael Hanselmann
    value = self._exclusive_storage
385 a08e181f Michael Hanselmann
    assert value is not None
386 a08e181f Michael Hanselmann
    return value
387 a08e181f Michael Hanselmann
388 a08e181f Michael Hanselmann
  def IsTemplateSupported(self, templ):
389 a08e181f Michael Hanselmann
    """Is the given disk template supported by the current configuration?
390 a08e181f Michael Hanselmann

391 a08e181f Michael Hanselmann
    """
392 cf62af3a Michael Hanselmann
    return (not self.GetExclusiveStorage() or
393 cf62af3a Michael Hanselmann
            templ in constants.DTS_EXCL_STORAGE)
394 a08e181f Michael Hanselmann
395 76fda900 Michael Hanselmann
  def GetVclusterSettings(self):
396 76fda900 Michael Hanselmann
    """Returns settings for virtual cluster.
397 76fda900 Michael Hanselmann

398 76fda900 Michael Hanselmann
    """
399 76fda900 Michael Hanselmann
    master = self.get(_VCLUSTER_MASTER_KEY)
400 76fda900 Michael Hanselmann
    basedir = self.get(_VCLUSTER_BASEDIR_KEY)
401 76fda900 Michael Hanselmann
402 76fda900 Michael Hanselmann
    return (master, basedir)
403 76fda900 Michael Hanselmann
404 8a96c5a6 Michael Hanselmann
405 8a96c5a6 Michael Hanselmann
def Load(path):
406 8a96c5a6 Michael Hanselmann
  """Loads the passed configuration file.
407 8a96c5a6 Michael Hanselmann

408 8a96c5a6 Michael Hanselmann
  """
409 8a96c5a6 Michael Hanselmann
  global _config # pylint: disable=W0603
410 8a96c5a6 Michael Hanselmann
411 8a96c5a6 Michael Hanselmann
  _config = _QaConfig.Load(path)
412 c9e05005 Michael Hanselmann
413 e7b6183b Michael Hanselmann
414 8a96c5a6 Michael Hanselmann
def GetConfig():
415 8a96c5a6 Michael Hanselmann
  """Returns the configuration object.
416 8a96c5a6 Michael Hanselmann

417 8a96c5a6 Michael Hanselmann
  """
418 8a96c5a6 Michael Hanselmann
  if _config is None:
419 8a96c5a6 Michael Hanselmann
    raise RuntimeError("Configuration not yet loaded")
420 8a96c5a6 Michael Hanselmann
421 8a96c5a6 Michael Hanselmann
  return _config
422 e7b6183b Michael Hanselmann
423 cec9845c Michael Hanselmann
424 cec9845c Michael Hanselmann
def get(name, default=None):
425 8a96c5a6 Michael Hanselmann
  """Wrapper for L{_QaConfig.get}.
426 8a96c5a6 Michael Hanselmann

427 8a96c5a6 Michael Hanselmann
  """
428 8a96c5a6 Michael Hanselmann
  return GetConfig().get(name, default=default)
429 cec9845c Michael Hanselmann
430 cec9845c Michael Hanselmann
431 a0c3e726 Michael Hanselmann
class Either:
432 a0c3e726 Michael Hanselmann
  def __init__(self, tests):
433 a0c3e726 Michael Hanselmann
    """Initializes this class.
434 a0c3e726 Michael Hanselmann

435 a0c3e726 Michael Hanselmann
    @type tests: list or string
436 a0c3e726 Michael Hanselmann
    @param tests: List of test names
437 a0c3e726 Michael Hanselmann
    @see: L{TestEnabled} for details
438 a0c3e726 Michael Hanselmann

439 a0c3e726 Michael Hanselmann
    """
440 a0c3e726 Michael Hanselmann
    self.tests = tests
441 a0c3e726 Michael Hanselmann
442 a0c3e726 Michael Hanselmann
443 a0c3e726 Michael Hanselmann
def _MakeSequence(value):
444 a0c3e726 Michael Hanselmann
  """Make sequence of single argument.
445 a0c3e726 Michael Hanselmann

446 a0c3e726 Michael Hanselmann
  If the single argument is not already a list or tuple, a list with the
447 a0c3e726 Michael Hanselmann
  argument as a single item is returned.
448 a0c3e726 Michael Hanselmann

449 a0c3e726 Michael Hanselmann
  """
450 a0c3e726 Michael Hanselmann
  if isinstance(value, (list, tuple)):
451 a0c3e726 Michael Hanselmann
    return value
452 a0c3e726 Michael Hanselmann
  else:
453 a0c3e726 Michael Hanselmann
    return [value]
454 a0c3e726 Michael Hanselmann
455 a0c3e726 Michael Hanselmann
456 a0c3e726 Michael Hanselmann
def _TestEnabledInner(check_fn, names, fn):
457 a0c3e726 Michael Hanselmann
  """Evaluate test conditions.
458 a0c3e726 Michael Hanselmann

459 a0c3e726 Michael Hanselmann
  @type check_fn: callable
460 a0c3e726 Michael Hanselmann
  @param check_fn: Callback to check whether a test is enabled
461 a0c3e726 Michael Hanselmann
  @type names: sequence or string
462 a0c3e726 Michael Hanselmann
  @param names: Test name(s)
463 a0c3e726 Michael Hanselmann
  @type fn: callable
464 a0c3e726 Michael Hanselmann
  @param fn: Aggregation function
465 a0c3e726 Michael Hanselmann
  @rtype: bool
466 a0c3e726 Michael Hanselmann
  @return: Whether test is enabled
467 a0c3e726 Michael Hanselmann

468 a0c3e726 Michael Hanselmann
  """
469 a0c3e726 Michael Hanselmann
  names = _MakeSequence(names)
470 a0c3e726 Michael Hanselmann
471 a0c3e726 Michael Hanselmann
  result = []
472 a0c3e726 Michael Hanselmann
473 a0c3e726 Michael Hanselmann
  for name in names:
474 a0c3e726 Michael Hanselmann
    if isinstance(name, Either):
475 a0c3e726 Michael Hanselmann
      value = _TestEnabledInner(check_fn, name.tests, compat.any)
476 a0c3e726 Michael Hanselmann
    elif isinstance(name, (list, tuple)):
477 a0c3e726 Michael Hanselmann
      value = _TestEnabledInner(check_fn, name, compat.all)
478 c072e788 Michael Hanselmann
    elif callable(name):
479 c072e788 Michael Hanselmann
      value = name()
480 a0c3e726 Michael Hanselmann
    else:
481 a0c3e726 Michael Hanselmann
      value = check_fn(name)
482 a0c3e726 Michael Hanselmann
483 a0c3e726 Michael Hanselmann
    result.append(value)
484 a0c3e726 Michael Hanselmann
485 a0c3e726 Michael Hanselmann
  return fn(result)
486 a0c3e726 Michael Hanselmann
487 a0c3e726 Michael Hanselmann
488 a0c3e726 Michael Hanselmann
def TestEnabled(tests, _cfg=None):
489 7d88f255 Iustin Pop
  """Returns True if the given tests are enabled.
490 7d88f255 Iustin Pop

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

494 1010ec70 Michael Hanselmann
  """
495 a0c3e726 Michael Hanselmann
  if _cfg is None:
496 8a96c5a6 Michael Hanselmann
    cfg = GetConfig()
497 8a96c5a6 Michael Hanselmann
  else:
498 8a96c5a6 Michael Hanselmann
    cfg = _cfg
499 59a8fe48 Michael Hanselmann
500 59a8fe48 Michael Hanselmann
  # Get settings for all tests
501 8a96c5a6 Michael Hanselmann
  cfg_tests = cfg.get("tests", {})
502 59a8fe48 Michael Hanselmann
503 59a8fe48 Michael Hanselmann
  # Get default setting
504 a0c3e726 Michael Hanselmann
  default = cfg_tests.get("default", True)
505 59a8fe48 Michael Hanselmann
506 a0c3e726 Michael Hanselmann
  return _TestEnabledInner(lambda name: cfg_tests.get(name, default),
507 a0c3e726 Michael Hanselmann
                           tests, compat.all)
508 cec9845c Michael Hanselmann
509 cec9845c Michael Hanselmann
510 8a96c5a6 Michael Hanselmann
def GetInstanceCheckScript(*args):
511 8a96c5a6 Michael Hanselmann
  """Wrapper for L{_QaConfig.GetInstanceCheckScript}.
512 c9e05005 Michael Hanselmann

513 c9e05005 Michael Hanselmann
  """
514 8a96c5a6 Michael Hanselmann
  return GetConfig().GetInstanceCheckScript(*args)
515 c9e05005 Michael Hanselmann
516 e7b6183b Michael Hanselmann
517 8a96c5a6 Michael Hanselmann
def GetEnabledHypervisors(*args):
518 8a96c5a6 Michael Hanselmann
  """Wrapper for L{_QaConfig.GetEnabledHypervisors}.
519 e7b6183b Michael Hanselmann

520 e7b6183b Michael Hanselmann
  """
521 8a96c5a6 Michael Hanselmann
  return GetConfig().GetEnabledHypervisors(*args)
522 e7b6183b Michael Hanselmann
523 e7b6183b Michael Hanselmann
524 8a96c5a6 Michael Hanselmann
def GetDefaultHypervisor(*args):
525 8a96c5a6 Michael Hanselmann
  """Wrapper for L{_QaConfig.GetDefaultHypervisor}.
526 e7b6183b Michael Hanselmann

527 e7b6183b Michael Hanselmann
  """
528 8a96c5a6 Michael Hanselmann
  return GetConfig().GetDefaultHypervisor(*args)
529 e7b6183b Michael Hanselmann
530 e7b6183b Michael Hanselmann
531 cec9845c Michael Hanselmann
def GetMasterNode():
532 8a96c5a6 Michael Hanselmann
  """Wrapper for L{_QaConfig.GetMasterNode}.
533 8a96c5a6 Michael Hanselmann

534 8a96c5a6 Michael Hanselmann
  """
535 8a96c5a6 Michael Hanselmann
  return GetConfig().GetMasterNode()
536 cec9845c Michael Hanselmann
537 cec9845c Michael Hanselmann
538 6a654276 Michael Hanselmann
def AcquireInstance(_cfg=None):
539 cec9845c Michael Hanselmann
  """Returns an instance which isn't in use.
540 cec9845c Michael Hanselmann

541 cec9845c Michael Hanselmann
  """
542 6a654276 Michael Hanselmann
  if _cfg is None:
543 6a654276 Michael Hanselmann
    cfg = GetConfig()
544 6a654276 Michael Hanselmann
  else:
545 6a654276 Michael Hanselmann
    cfg = _cfg
546 6a654276 Michael Hanselmann
547 cec9845c Michael Hanselmann
  # Filter out unwanted instances
548 6a654276 Michael Hanselmann
  instances = filter(lambda inst: not inst.used, cfg["instances"])
549 cec9845c Michael Hanselmann
550 6a654276 Michael Hanselmann
  if not instances:
551 cec9845c Michael Hanselmann
    raise qa_error.OutOfInstancesError("No instances left")
552 cec9845c Michael Hanselmann
553 2176724e Michael Hanselmann
  instance = instances[0]
554 2176724e Michael Hanselmann
  instance.Use()
555 6a654276 Michael Hanselmann
556 2176724e Michael Hanselmann
  return instance
557 cec9845c Michael Hanselmann
558 cec9845c Michael Hanselmann
559 6a0f22e1 Bernardo Dal Seno
def SetExclusiveStorage(value):
560 a08e181f Michael Hanselmann
  """Wrapper for L{_QaConfig.SetExclusiveStorage}.
561 6a0f22e1 Bernardo Dal Seno

562 6a0f22e1 Bernardo Dal Seno
  """
563 a08e181f Michael Hanselmann
  return GetConfig().SetExclusiveStorage(value)
564 6a0f22e1 Bernardo Dal Seno
565 6a0f22e1 Bernardo Dal Seno
566 6a0f22e1 Bernardo Dal Seno
def GetExclusiveStorage():
567 a08e181f Michael Hanselmann
  """Wrapper for L{_QaConfig.GetExclusiveStorage}.
568 6a0f22e1 Bernardo Dal Seno

569 6a0f22e1 Bernardo Dal Seno
  """
570 a08e181f Michael Hanselmann
  return GetConfig().GetExclusiveStorage()
571 6a0f22e1 Bernardo Dal Seno
572 6a0f22e1 Bernardo Dal Seno
573 27eba428 Bernardo Dal Seno
def IsTemplateSupported(templ):
574 a08e181f Michael Hanselmann
  """Wrapper for L{_QaConfig.GetExclusiveStorage}.
575 27eba428 Bernardo Dal Seno

576 27eba428 Bernardo Dal Seno
  """
577 a08e181f Michael Hanselmann
  return GetConfig().IsTemplateSupported(templ)
578 27eba428 Bernardo Dal Seno
579 27eba428 Bernardo Dal Seno
580 41be279f Michael Hanselmann
def _NodeSortKey(node):
581 41be279f Michael Hanselmann
  """Returns sort key for a node.
582 41be279f Michael Hanselmann

583 41be279f Michael Hanselmann
  @type node: L{_QaNode}
584 41be279f Michael Hanselmann

585 41be279f Michael Hanselmann
  """
586 41be279f Michael Hanselmann
  return (node.use_count, utils.NiceSortKey(node.primary))
587 41be279f Michael Hanselmann
588 41be279f Michael Hanselmann
589 dbdb0594 Michael Hanselmann
def AcquireNode(exclude=None, _cfg=None):
590 cec9845c Michael Hanselmann
  """Returns the least used node.
591 cec9845c Michael Hanselmann

592 cec9845c Michael Hanselmann
  """
593 dbdb0594 Michael Hanselmann
  if _cfg is None:
594 dbdb0594 Michael Hanselmann
    cfg = GetConfig()
595 dbdb0594 Michael Hanselmann
  else:
596 dbdb0594 Michael Hanselmann
    cfg = _cfg
597 dbdb0594 Michael Hanselmann
598 dbdb0594 Michael Hanselmann
  master = cfg.GetMasterNode()
599 cec9845c Michael Hanselmann
600 cec9845c Michael Hanselmann
  # Filter out unwanted nodes
601 cec9845c Michael Hanselmann
  # TODO: Maybe combine filters
602 cec9845c Michael Hanselmann
  if exclude is None:
603 d0c8c01d Iustin Pop
    nodes = cfg["nodes"][:]
604 4b62db14 Michael Hanselmann
  elif isinstance(exclude, (list, tuple)):
605 d0c8c01d Iustin Pop
    nodes = filter(lambda node: node not in exclude, cfg["nodes"])
606 cec9845c Michael Hanselmann
  else:
607 d0c8c01d Iustin Pop
    nodes = filter(lambda node: node != exclude, cfg["nodes"])
608 cec9845c Michael Hanselmann
609 dbdb0594 Michael Hanselmann
  nodes = filter(lambda node: node.added or node == master, nodes)
610 cec9845c Michael Hanselmann
611 dbdb0594 Michael Hanselmann
  if not nodes:
612 cec9845c Michael Hanselmann
    raise qa_error.OutOfNodesError("No nodes left")
613 cec9845c Michael Hanselmann
614 41be279f Michael Hanselmann
  # Return node with least number of uses
615 41be279f Michael Hanselmann
  return sorted(nodes, key=_NodeSortKey)[0].Use()
616 cec9845c Michael Hanselmann
617 cec9845c Michael Hanselmann
618 7d4f1b45 Bernardo Dal Seno
def AcquireManyNodes(num, exclude=None):
619 7d4f1b45 Bernardo Dal Seno
  """Return the least used nodes.
620 7d4f1b45 Bernardo Dal Seno

621 7d4f1b45 Bernardo Dal Seno
  @type num: int
622 7d4f1b45 Bernardo Dal Seno
  @param num: Number of nodes; can be 0.
623 7d4f1b45 Bernardo Dal Seno
  @type exclude: list of nodes or C{None}
624 7d4f1b45 Bernardo Dal Seno
  @param exclude: nodes to be excluded from the choice
625 7d4f1b45 Bernardo Dal Seno
  @rtype: list of nodes
626 7d4f1b45 Bernardo Dal Seno
  @return: C{num} different nodes
627 7d4f1b45 Bernardo Dal Seno

628 7d4f1b45 Bernardo Dal Seno
  """
629 7d4f1b45 Bernardo Dal Seno
  nodes = []
630 7d4f1b45 Bernardo Dal Seno
  if exclude is None:
631 7d4f1b45 Bernardo Dal Seno
    exclude = []
632 7d4f1b45 Bernardo Dal Seno
  elif isinstance(exclude, (list, tuple)):
633 7d4f1b45 Bernardo Dal Seno
    # Don't modify the incoming argument
634 7d4f1b45 Bernardo Dal Seno
    exclude = list(exclude)
635 7d4f1b45 Bernardo Dal Seno
  else:
636 7d4f1b45 Bernardo Dal Seno
    exclude = [exclude]
637 7d4f1b45 Bernardo Dal Seno
638 7d4f1b45 Bernardo Dal Seno
  try:
639 7d4f1b45 Bernardo Dal Seno
    for _ in range(0, num):
640 7d4f1b45 Bernardo Dal Seno
      n = AcquireNode(exclude=exclude)
641 7d4f1b45 Bernardo Dal Seno
      nodes.append(n)
642 7d4f1b45 Bernardo Dal Seno
      exclude.append(n)
643 7d4f1b45 Bernardo Dal Seno
  except qa_error.OutOfNodesError:
644 7d4f1b45 Bernardo Dal Seno
    ReleaseManyNodes(nodes)
645 7d4f1b45 Bernardo Dal Seno
    raise
646 7d4f1b45 Bernardo Dal Seno
  return nodes
647 7d4f1b45 Bernardo Dal Seno
648 7d4f1b45 Bernardo Dal Seno
649 7d4f1b45 Bernardo Dal Seno
def ReleaseManyNodes(nodes):
650 565cb4bf Michael Hanselmann
  for node in nodes:
651 565cb4bf Michael Hanselmann
    node.Release()
652 76fda900 Michael Hanselmann
653 76fda900 Michael Hanselmann
654 76fda900 Michael Hanselmann
def GetVclusterSettings():
655 76fda900 Michael Hanselmann
  """Wrapper for L{_QaConfig.GetVclusterSettings}.
656 76fda900 Michael Hanselmann

657 76fda900 Michael Hanselmann
  """
658 76fda900 Michael Hanselmann
  return GetConfig().GetVclusterSettings()
659 76fda900 Michael Hanselmann
660 76fda900 Michael Hanselmann
661 76fda900 Michael Hanselmann
def UseVirtualCluster(_cfg=None):
662 76fda900 Michael Hanselmann
  """Returns whether a virtual cluster is used.
663 76fda900 Michael Hanselmann

664 76fda900 Michael Hanselmann
  @rtype: bool
665 76fda900 Michael Hanselmann

666 76fda900 Michael Hanselmann
  """
667 76fda900 Michael Hanselmann
  if _cfg is None:
668 76fda900 Michael Hanselmann
    cfg = GetConfig()
669 76fda900 Michael Hanselmann
  else:
670 76fda900 Michael Hanselmann
    cfg = _cfg
671 76fda900 Michael Hanselmann
672 76fda900 Michael Hanselmann
  (master, _) = cfg.GetVclusterSettings()
673 76fda900 Michael Hanselmann
674 76fda900 Michael Hanselmann
  return bool(master)
675 76fda900 Michael Hanselmann
676 76fda900 Michael Hanselmann
677 76fda900 Michael Hanselmann
@ht.WithDesc("No virtual cluster")
678 76fda900 Michael Hanselmann
def NoVirtualCluster():
679 76fda900 Michael Hanselmann
  """Used to disable tests for virtual clusters.
680 76fda900 Michael Hanselmann

681 76fda900 Michael Hanselmann
  """
682 76fda900 Michael Hanselmann
  return not UseVirtualCluster()