Statistics
| Branch: | Tag: | Revision:

root / qa / qa_config.py @ 99f5fa44

History | View | Annotate | Download (13 kB)

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

24 cec9845c Michael Hanselmann
"""
25 cec9845c Michael Hanselmann
26 c9e05005 Michael Hanselmann
import os
27 cec9845c Michael Hanselmann
28 e7b6183b Michael Hanselmann
from ganeti import constants
29 a705dc05 Michael Hanselmann
from ganeti import utils
30 a705dc05 Michael Hanselmann
from ganeti import serializer
31 7d88f255 Iustin Pop
from ganeti import compat
32 cec9845c Michael Hanselmann
33 cec9845c Michael Hanselmann
import qa_error
34 cec9845c Michael Hanselmann
35 cec9845c Michael Hanselmann
36 c9e05005 Michael Hanselmann
_INSTANCE_CHECK_KEY = "instance-check"
37 e7b6183b Michael Hanselmann
_ENABLED_HV_KEY = "enabled-hypervisors"
38 f9329a6c Michael Hanselmann
39 8a96c5a6 Michael Hanselmann
#: QA configuration (L{_QaConfig})
40 8a96c5a6 Michael Hanselmann
_config = None
41 cec9845c Michael Hanselmann
42 cec9845c Michael Hanselmann
43 6a654276 Michael Hanselmann
class _QaInstance(object):
44 6a654276 Michael Hanselmann
  __slots__ = [
45 6a654276 Michael Hanselmann
    "name",
46 6a654276 Michael Hanselmann
    "nicmac",
47 6a654276 Michael Hanselmann
    "used",
48 6a654276 Michael Hanselmann
    "disk_template",
49 6a654276 Michael Hanselmann
    ]
50 6a654276 Michael Hanselmann
51 6a654276 Michael Hanselmann
  def __init__(self, name, nicmac):
52 6a654276 Michael Hanselmann
    """Initializes instances of this class.
53 6a654276 Michael Hanselmann

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

64 6a654276 Michael Hanselmann
    """
65 6a654276 Michael Hanselmann
    nicmac = []
66 6a654276 Michael Hanselmann
67 6a654276 Michael Hanselmann
    macaddr = data.get("nic.mac/0")
68 6a654276 Michael Hanselmann
    if macaddr:
69 6a654276 Michael Hanselmann
      nicmac.append(macaddr)
70 6a654276 Michael Hanselmann
71 6a654276 Michael Hanselmann
    return cls(name=data["name"], nicmac=nicmac)
72 6a654276 Michael Hanselmann
73 6f88e076 Michael Hanselmann
  def Release(self):
74 6f88e076 Michael Hanselmann
    """Releases instance and makes it available again.
75 6f88e076 Michael Hanselmann

76 6f88e076 Michael Hanselmann
    """
77 6f88e076 Michael Hanselmann
    assert self.used, \
78 6f88e076 Michael Hanselmann
      ("Instance '%s' was never acquired or released more than once" %
79 6f88e076 Michael Hanselmann
       self.name)
80 6f88e076 Michael Hanselmann
81 6f88e076 Michael Hanselmann
    self.used = False
82 6f88e076 Michael Hanselmann
    self.disk_template = None
83 6f88e076 Michael Hanselmann
84 6a654276 Michael Hanselmann
  def GetNicMacAddr(self, idx, default):
85 6a654276 Michael Hanselmann
    """Returns MAC address for NIC.
86 6a654276 Michael Hanselmann

87 6a654276 Michael Hanselmann
    @type idx: int
88 6a654276 Michael Hanselmann
    @param idx: NIC index
89 6a654276 Michael Hanselmann
    @param default: Default value
90 6a654276 Michael Hanselmann

91 6a654276 Michael Hanselmann
    """
92 6a654276 Michael Hanselmann
    if len(self.nicmac) > idx:
93 6a654276 Michael Hanselmann
      return self.nicmac[idx]
94 6a654276 Michael Hanselmann
    else:
95 6a654276 Michael Hanselmann
      return default
96 6a654276 Michael Hanselmann
97 6a654276 Michael Hanselmann
98 dbdb0594 Michael Hanselmann
class _QaNode(object):
99 dbdb0594 Michael Hanselmann
  __slots__ = [
100 dbdb0594 Michael Hanselmann
    "primary",
101 dbdb0594 Michael Hanselmann
    "secondary",
102 dbdb0594 Michael Hanselmann
    "_added",
103 565cb4bf Michael Hanselmann
    "_use_count",
104 dbdb0594 Michael Hanselmann
    ]
105 dbdb0594 Michael Hanselmann
106 dbdb0594 Michael Hanselmann
  def __init__(self, primary, secondary):
107 dbdb0594 Michael Hanselmann
    """Initializes instances of this class.
108 dbdb0594 Michael Hanselmann

109 dbdb0594 Michael Hanselmann
    """
110 dbdb0594 Michael Hanselmann
    self.primary = primary
111 dbdb0594 Michael Hanselmann
    self.secondary = secondary
112 dbdb0594 Michael Hanselmann
    self._added = False
113 565cb4bf Michael Hanselmann
    self._use_count = 0
114 dbdb0594 Michael Hanselmann
115 dbdb0594 Michael Hanselmann
  @classmethod
116 dbdb0594 Michael Hanselmann
  def FromDict(cls, data):
117 dbdb0594 Michael Hanselmann
    """Creates node object from JSON dictionary.
118 dbdb0594 Michael Hanselmann

119 dbdb0594 Michael Hanselmann
    """
120 dbdb0594 Michael Hanselmann
    return cls(primary=data["primary"], secondary=data.get("secondary"))
121 dbdb0594 Michael Hanselmann
122 dbdb0594 Michael Hanselmann
  def Use(self):
123 dbdb0594 Michael Hanselmann
    """Marks a node as being in use.
124 dbdb0594 Michael Hanselmann

125 dbdb0594 Michael Hanselmann
    """
126 565cb4bf Michael Hanselmann
    assert self._use_count >= 0
127 dbdb0594 Michael Hanselmann
128 565cb4bf Michael Hanselmann
    self._use_count += 1
129 dbdb0594 Michael Hanselmann
130 dbdb0594 Michael Hanselmann
    return self
131 dbdb0594 Michael Hanselmann
132 565cb4bf Michael Hanselmann
  def Release(self):
133 565cb4bf Michael Hanselmann
    """Release a node (opposite of L{Use}).
134 565cb4bf Michael Hanselmann

135 565cb4bf Michael Hanselmann
    """
136 565cb4bf Michael Hanselmann
    assert self.use_count > 0
137 565cb4bf Michael Hanselmann
138 565cb4bf Michael Hanselmann
    self._use_count -= 1
139 565cb4bf Michael Hanselmann
140 dbdb0594 Michael Hanselmann
  def MarkAdded(self):
141 dbdb0594 Michael Hanselmann
    """Marks node as having been added to a cluster.
142 dbdb0594 Michael Hanselmann

143 dbdb0594 Michael Hanselmann
    """
144 dbdb0594 Michael Hanselmann
    assert not self._added
145 dbdb0594 Michael Hanselmann
    self._added = True
146 dbdb0594 Michael Hanselmann
147 dbdb0594 Michael Hanselmann
  def MarkRemoved(self):
148 dbdb0594 Michael Hanselmann
    """Marks node as having been removed from a cluster.
149 dbdb0594 Michael Hanselmann

150 dbdb0594 Michael Hanselmann
    """
151 dbdb0594 Michael Hanselmann
    assert self._added
152 dbdb0594 Michael Hanselmann
    self._added = False
153 dbdb0594 Michael Hanselmann
154 dbdb0594 Michael Hanselmann
  @property
155 dbdb0594 Michael Hanselmann
  def added(self):
156 dbdb0594 Michael Hanselmann
    """Returns whether a node is part of a cluster.
157 dbdb0594 Michael Hanselmann

158 dbdb0594 Michael Hanselmann
    """
159 dbdb0594 Michael Hanselmann
    return self._added
160 dbdb0594 Michael Hanselmann
161 565cb4bf Michael Hanselmann
  @property
162 565cb4bf Michael Hanselmann
  def use_count(self):
163 565cb4bf Michael Hanselmann
    """Returns number of current uses (controlled by L{Use} and L{Release}).
164 565cb4bf Michael Hanselmann

165 565cb4bf Michael Hanselmann
    """
166 565cb4bf Michael Hanselmann
    return self._use_count
167 565cb4bf Michael Hanselmann
168 dbdb0594 Michael Hanselmann
169 6a654276 Michael Hanselmann
_RESOURCE_CONVERTER = {
170 6a654276 Michael Hanselmann
  "instances": _QaInstance.FromDict,
171 dbdb0594 Michael Hanselmann
  "nodes": _QaNode.FromDict,
172 6a654276 Michael Hanselmann
  }
173 6a654276 Michael Hanselmann
174 6a654276 Michael Hanselmann
175 6a654276 Michael Hanselmann
def _ConvertResources((key, value)):
176 6a654276 Michael Hanselmann
  """Converts cluster resources in configuration to Python objects.
177 6a654276 Michael Hanselmann

178 6a654276 Michael Hanselmann
  """
179 6a654276 Michael Hanselmann
  fn = _RESOURCE_CONVERTER.get(key, None)
180 6a654276 Michael Hanselmann
  if fn:
181 6a654276 Michael Hanselmann
    return (key, map(fn, value))
182 6a654276 Michael Hanselmann
  else:
183 6a654276 Michael Hanselmann
    return (key, value)
184 6a654276 Michael Hanselmann
185 6a654276 Michael Hanselmann
186 8a96c5a6 Michael Hanselmann
class _QaConfig(object):
187 8a96c5a6 Michael Hanselmann
  def __init__(self, data):
188 8a96c5a6 Michael Hanselmann
    """Initializes instances of this class.
189 cec9845c Michael Hanselmann

190 8a96c5a6 Michael Hanselmann
    """
191 8a96c5a6 Michael Hanselmann
    self._data = data
192 8a96c5a6 Michael Hanselmann
193 a08e181f Michael Hanselmann
    #: Cluster-wide run-time value of the exclusive storage flag
194 a08e181f Michael Hanselmann
    self._exclusive_storage = None
195 a08e181f Michael Hanselmann
196 8a96c5a6 Michael Hanselmann
  @classmethod
197 8a96c5a6 Michael Hanselmann
  def Load(cls, filename):
198 8a96c5a6 Michael Hanselmann
    """Loads a configuration file and produces a configuration object.
199 8a96c5a6 Michael Hanselmann

200 8a96c5a6 Michael Hanselmann
    @type filename: string
201 8a96c5a6 Michael Hanselmann
    @param filename: Path to configuration file
202 8a96c5a6 Michael Hanselmann
    @rtype: L{_QaConfig}
203 8a96c5a6 Michael Hanselmann

204 8a96c5a6 Michael Hanselmann
    """
205 8a96c5a6 Michael Hanselmann
    data = serializer.LoadJson(utils.ReadFile(filename))
206 8a96c5a6 Michael Hanselmann
207 6a654276 Michael Hanselmann
    result = cls(dict(map(_ConvertResources,
208 6a654276 Michael Hanselmann
                          data.items()))) # pylint: disable=E1103
209 8a96c5a6 Michael Hanselmann
    result.Validate()
210 8a96c5a6 Michael Hanselmann
211 8a96c5a6 Michael Hanselmann
    return result
212 8a96c5a6 Michael Hanselmann
213 8a96c5a6 Michael Hanselmann
  def Validate(self):
214 8a96c5a6 Michael Hanselmann
    """Validates loaded configuration data.
215 8a96c5a6 Michael Hanselmann

216 8a96c5a6 Michael Hanselmann
    """
217 8a96c5a6 Michael Hanselmann
    if not self.get("nodes"):
218 8a96c5a6 Michael Hanselmann
      raise qa_error.Error("Need at least one node")
219 8a96c5a6 Michael Hanselmann
220 8a96c5a6 Michael Hanselmann
    if not self.get("instances"):
221 8a96c5a6 Michael Hanselmann
      raise qa_error.Error("Need at least one instance")
222 8a96c5a6 Michael Hanselmann
223 8a96c5a6 Michael Hanselmann
    if (self.get("disk") is None or
224 8a96c5a6 Michael Hanselmann
        self.get("disk-growth") is None or
225 8a96c5a6 Michael Hanselmann
        len(self.get("disk")) != len(self.get("disk-growth"))):
226 8a96c5a6 Michael Hanselmann
      raise qa_error.Error("Config options 'disk' and 'disk-growth' must exist"
227 8a96c5a6 Michael Hanselmann
                           " and have the same number of items")
228 8a96c5a6 Michael Hanselmann
229 8a96c5a6 Michael Hanselmann
    check = self.GetInstanceCheckScript()
230 8a96c5a6 Michael Hanselmann
    if check:
231 8a96c5a6 Michael Hanselmann
      try:
232 8a96c5a6 Michael Hanselmann
        os.stat(check)
233 8a96c5a6 Michael Hanselmann
      except EnvironmentError, err:
234 8a96c5a6 Michael Hanselmann
        raise qa_error.Error("Can't find instance check script '%s': %s" %
235 8a96c5a6 Michael Hanselmann
                             (check, err))
236 8a96c5a6 Michael Hanselmann
237 8a96c5a6 Michael Hanselmann
    enabled_hv = frozenset(self.GetEnabledHypervisors())
238 8a96c5a6 Michael Hanselmann
    if not enabled_hv:
239 8a96c5a6 Michael Hanselmann
      raise qa_error.Error("No hypervisor is enabled")
240 8a96c5a6 Michael Hanselmann
241 8a96c5a6 Michael Hanselmann
    difference = enabled_hv - constants.HYPER_TYPES
242 8a96c5a6 Michael Hanselmann
    if difference:
243 8a96c5a6 Michael Hanselmann
      raise qa_error.Error("Unknown hypervisor(s) enabled: %s" %
244 8a96c5a6 Michael Hanselmann
                           utils.CommaJoin(difference))
245 8a96c5a6 Michael Hanselmann
246 8a96c5a6 Michael Hanselmann
  def __getitem__(self, name):
247 8a96c5a6 Michael Hanselmann
    """Returns configuration value.
248 8a96c5a6 Michael Hanselmann

249 8a96c5a6 Michael Hanselmann
    @type name: string
250 8a96c5a6 Michael Hanselmann
    @param name: Name of configuration entry
251 8a96c5a6 Michael Hanselmann

252 8a96c5a6 Michael Hanselmann
    """
253 8a96c5a6 Michael Hanselmann
    return self._data[name]
254 8a96c5a6 Michael Hanselmann
255 8a96c5a6 Michael Hanselmann
  def get(self, name, default=None):
256 8a96c5a6 Michael Hanselmann
    """Returns configuration value.
257 8a96c5a6 Michael Hanselmann

258 8a96c5a6 Michael Hanselmann
    @type name: string
259 8a96c5a6 Michael Hanselmann
    @param name: Name of configuration entry
260 8a96c5a6 Michael Hanselmann
    @param default: Default value
261 8a96c5a6 Michael Hanselmann

262 8a96c5a6 Michael Hanselmann
    """
263 8a96c5a6 Michael Hanselmann
    return self._data.get(name, default)
264 cec9845c Michael Hanselmann
265 8a96c5a6 Michael Hanselmann
  def GetMasterNode(self):
266 8a96c5a6 Michael Hanselmann
    """Returns the default master node for the cluster.
267 cec9845c Michael Hanselmann

268 8a96c5a6 Michael Hanselmann
    """
269 8a96c5a6 Michael Hanselmann
    return self["nodes"][0]
270 8a96c5a6 Michael Hanselmann
271 8a96c5a6 Michael Hanselmann
  def GetInstanceCheckScript(self):
272 8a96c5a6 Michael Hanselmann
    """Returns path to instance check script or C{None}.
273 8a96c5a6 Michael Hanselmann

274 8a96c5a6 Michael Hanselmann
    """
275 8a96c5a6 Michael Hanselmann
    return self._data.get(_INSTANCE_CHECK_KEY, None)
276 cec9845c Michael Hanselmann
277 8a96c5a6 Michael Hanselmann
  def GetEnabledHypervisors(self):
278 8a96c5a6 Michael Hanselmann
    """Returns list of enabled hypervisors.
279 cec9845c Michael Hanselmann

280 8a96c5a6 Michael Hanselmann
    @rtype: list
281 cec9845c Michael Hanselmann

282 8a96c5a6 Michael Hanselmann
    """
283 c9e05005 Michael Hanselmann
    try:
284 8a96c5a6 Michael Hanselmann
      value = self._data[_ENABLED_HV_KEY]
285 8a96c5a6 Michael Hanselmann
    except KeyError:
286 8a96c5a6 Michael Hanselmann
      return [constants.DEFAULT_ENABLED_HYPERVISOR]
287 8a96c5a6 Michael Hanselmann
    else:
288 8a96c5a6 Michael Hanselmann
      if value is None:
289 8a96c5a6 Michael Hanselmann
        return []
290 8a96c5a6 Michael Hanselmann
      elif isinstance(value, basestring):
291 8a96c5a6 Michael Hanselmann
        # The configuration key ("enabled-hypervisors") implies there can be
292 8a96c5a6 Michael Hanselmann
        # multiple values. Multiple hypervisors are comma-separated on the
293 8a96c5a6 Michael Hanselmann
        # command line option to "gnt-cluster init", so we need to handle them
294 8a96c5a6 Michael Hanselmann
        # equally here.
295 8a96c5a6 Michael Hanselmann
        return value.split(",")
296 8a96c5a6 Michael Hanselmann
      else:
297 8a96c5a6 Michael Hanselmann
        return value
298 8a96c5a6 Michael Hanselmann
299 8a96c5a6 Michael Hanselmann
  def GetDefaultHypervisor(self):
300 8a96c5a6 Michael Hanselmann
    """Returns the default hypervisor to be used.
301 8a96c5a6 Michael Hanselmann

302 8a96c5a6 Michael Hanselmann
    """
303 8a96c5a6 Michael Hanselmann
    return self.GetEnabledHypervisors()[0]
304 8a96c5a6 Michael Hanselmann
305 a08e181f Michael Hanselmann
  def SetExclusiveStorage(self, value):
306 a08e181f Michael Hanselmann
    """Set the expected value of the C{exclusive_storage} flag for the cluster.
307 a08e181f Michael Hanselmann

308 a08e181f Michael Hanselmann
    """
309 a08e181f Michael Hanselmann
    self._exclusive_storage = bool(value)
310 a08e181f Michael Hanselmann
311 a08e181f Michael Hanselmann
  def GetExclusiveStorage(self):
312 a08e181f Michael Hanselmann
    """Get the expected value of the C{exclusive_storage} flag for the cluster.
313 a08e181f Michael Hanselmann

314 a08e181f Michael Hanselmann
    """
315 a08e181f Michael Hanselmann
    value = self._exclusive_storage
316 a08e181f Michael Hanselmann
    assert value is not None
317 a08e181f Michael Hanselmann
    return value
318 a08e181f Michael Hanselmann
319 a08e181f Michael Hanselmann
  def IsTemplateSupported(self, templ):
320 a08e181f Michael Hanselmann
    """Is the given disk template supported by the current configuration?
321 a08e181f Michael Hanselmann

322 a08e181f Michael Hanselmann
    """
323 cf62af3a Michael Hanselmann
    return (not self.GetExclusiveStorage() or
324 cf62af3a Michael Hanselmann
            templ in constants.DTS_EXCL_STORAGE)
325 a08e181f Michael Hanselmann
326 8a96c5a6 Michael Hanselmann
327 8a96c5a6 Michael Hanselmann
def Load(path):
328 8a96c5a6 Michael Hanselmann
  """Loads the passed configuration file.
329 8a96c5a6 Michael Hanselmann

330 8a96c5a6 Michael Hanselmann
  """
331 8a96c5a6 Michael Hanselmann
  global _config # pylint: disable=W0603
332 8a96c5a6 Michael Hanselmann
333 8a96c5a6 Michael Hanselmann
  _config = _QaConfig.Load(path)
334 c9e05005 Michael Hanselmann
335 e7b6183b Michael Hanselmann
336 8a96c5a6 Michael Hanselmann
def GetConfig():
337 8a96c5a6 Michael Hanselmann
  """Returns the configuration object.
338 8a96c5a6 Michael Hanselmann

339 8a96c5a6 Michael Hanselmann
  """
340 8a96c5a6 Michael Hanselmann
  if _config is None:
341 8a96c5a6 Michael Hanselmann
    raise RuntimeError("Configuration not yet loaded")
342 8a96c5a6 Michael Hanselmann
343 8a96c5a6 Michael Hanselmann
  return _config
344 e7b6183b Michael Hanselmann
345 cec9845c Michael Hanselmann
346 cec9845c Michael Hanselmann
def get(name, default=None):
347 8a96c5a6 Michael Hanselmann
  """Wrapper for L{_QaConfig.get}.
348 8a96c5a6 Michael Hanselmann

349 8a96c5a6 Michael Hanselmann
  """
350 8a96c5a6 Michael Hanselmann
  return GetConfig().get(name, default=default)
351 cec9845c Michael Hanselmann
352 cec9845c Michael Hanselmann
353 a0c3e726 Michael Hanselmann
class Either:
354 a0c3e726 Michael Hanselmann
  def __init__(self, tests):
355 a0c3e726 Michael Hanselmann
    """Initializes this class.
356 a0c3e726 Michael Hanselmann

357 a0c3e726 Michael Hanselmann
    @type tests: list or string
358 a0c3e726 Michael Hanselmann
    @param tests: List of test names
359 a0c3e726 Michael Hanselmann
    @see: L{TestEnabled} for details
360 a0c3e726 Michael Hanselmann

361 a0c3e726 Michael Hanselmann
    """
362 a0c3e726 Michael Hanselmann
    self.tests = tests
363 a0c3e726 Michael Hanselmann
364 a0c3e726 Michael Hanselmann
365 a0c3e726 Michael Hanselmann
def _MakeSequence(value):
366 a0c3e726 Michael Hanselmann
  """Make sequence of single argument.
367 a0c3e726 Michael Hanselmann

368 a0c3e726 Michael Hanselmann
  If the single argument is not already a list or tuple, a list with the
369 a0c3e726 Michael Hanselmann
  argument as a single item is returned.
370 a0c3e726 Michael Hanselmann

371 a0c3e726 Michael Hanselmann
  """
372 a0c3e726 Michael Hanselmann
  if isinstance(value, (list, tuple)):
373 a0c3e726 Michael Hanselmann
    return value
374 a0c3e726 Michael Hanselmann
  else:
375 a0c3e726 Michael Hanselmann
    return [value]
376 a0c3e726 Michael Hanselmann
377 a0c3e726 Michael Hanselmann
378 a0c3e726 Michael Hanselmann
def _TestEnabledInner(check_fn, names, fn):
379 a0c3e726 Michael Hanselmann
  """Evaluate test conditions.
380 a0c3e726 Michael Hanselmann

381 a0c3e726 Michael Hanselmann
  @type check_fn: callable
382 a0c3e726 Michael Hanselmann
  @param check_fn: Callback to check whether a test is enabled
383 a0c3e726 Michael Hanselmann
  @type names: sequence or string
384 a0c3e726 Michael Hanselmann
  @param names: Test name(s)
385 a0c3e726 Michael Hanselmann
  @type fn: callable
386 a0c3e726 Michael Hanselmann
  @param fn: Aggregation function
387 a0c3e726 Michael Hanselmann
  @rtype: bool
388 a0c3e726 Michael Hanselmann
  @return: Whether test is enabled
389 a0c3e726 Michael Hanselmann

390 a0c3e726 Michael Hanselmann
  """
391 a0c3e726 Michael Hanselmann
  names = _MakeSequence(names)
392 a0c3e726 Michael Hanselmann
393 a0c3e726 Michael Hanselmann
  result = []
394 a0c3e726 Michael Hanselmann
395 a0c3e726 Michael Hanselmann
  for name in names:
396 a0c3e726 Michael Hanselmann
    if isinstance(name, Either):
397 a0c3e726 Michael Hanselmann
      value = _TestEnabledInner(check_fn, name.tests, compat.any)
398 a0c3e726 Michael Hanselmann
    elif isinstance(name, (list, tuple)):
399 a0c3e726 Michael Hanselmann
      value = _TestEnabledInner(check_fn, name, compat.all)
400 a0c3e726 Michael Hanselmann
    else:
401 a0c3e726 Michael Hanselmann
      value = check_fn(name)
402 a0c3e726 Michael Hanselmann
403 a0c3e726 Michael Hanselmann
    result.append(value)
404 a0c3e726 Michael Hanselmann
405 a0c3e726 Michael Hanselmann
  return fn(result)
406 a0c3e726 Michael Hanselmann
407 a0c3e726 Michael Hanselmann
408 a0c3e726 Michael Hanselmann
def TestEnabled(tests, _cfg=None):
409 7d88f255 Iustin Pop
  """Returns True if the given tests are enabled.
410 7d88f255 Iustin Pop

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

414 1010ec70 Michael Hanselmann
  """
415 a0c3e726 Michael Hanselmann
  if _cfg is None:
416 8a96c5a6 Michael Hanselmann
    cfg = GetConfig()
417 8a96c5a6 Michael Hanselmann
  else:
418 8a96c5a6 Michael Hanselmann
    cfg = _cfg
419 59a8fe48 Michael Hanselmann
420 59a8fe48 Michael Hanselmann
  # Get settings for all tests
421 8a96c5a6 Michael Hanselmann
  cfg_tests = cfg.get("tests", {})
422 59a8fe48 Michael Hanselmann
423 59a8fe48 Michael Hanselmann
  # Get default setting
424 a0c3e726 Michael Hanselmann
  default = cfg_tests.get("default", True)
425 59a8fe48 Michael Hanselmann
426 a0c3e726 Michael Hanselmann
  return _TestEnabledInner(lambda name: cfg_tests.get(name, default),
427 a0c3e726 Michael Hanselmann
                           tests, compat.all)
428 cec9845c Michael Hanselmann
429 cec9845c Michael Hanselmann
430 8a96c5a6 Michael Hanselmann
def GetInstanceCheckScript(*args):
431 8a96c5a6 Michael Hanselmann
  """Wrapper for L{_QaConfig.GetInstanceCheckScript}.
432 c9e05005 Michael Hanselmann

433 c9e05005 Michael Hanselmann
  """
434 8a96c5a6 Michael Hanselmann
  return GetConfig().GetInstanceCheckScript(*args)
435 c9e05005 Michael Hanselmann
436 e7b6183b Michael Hanselmann
437 8a96c5a6 Michael Hanselmann
def GetEnabledHypervisors(*args):
438 8a96c5a6 Michael Hanselmann
  """Wrapper for L{_QaConfig.GetEnabledHypervisors}.
439 e7b6183b Michael Hanselmann

440 e7b6183b Michael Hanselmann
  """
441 8a96c5a6 Michael Hanselmann
  return GetConfig().GetEnabledHypervisors(*args)
442 e7b6183b Michael Hanselmann
443 e7b6183b Michael Hanselmann
444 8a96c5a6 Michael Hanselmann
def GetDefaultHypervisor(*args):
445 8a96c5a6 Michael Hanselmann
  """Wrapper for L{_QaConfig.GetDefaultHypervisor}.
446 e7b6183b Michael Hanselmann

447 e7b6183b Michael Hanselmann
  """
448 8a96c5a6 Michael Hanselmann
  return GetConfig().GetDefaultHypervisor(*args)
449 e7b6183b Michael Hanselmann
450 e7b6183b Michael Hanselmann
451 f346a7d9 Michael Hanselmann
def GetInstanceNicMac(inst, default=None):
452 f346a7d9 Michael Hanselmann
  """Returns MAC address for instance's network interface.
453 f346a7d9 Michael Hanselmann

454 f346a7d9 Michael Hanselmann
  """
455 6a654276 Michael Hanselmann
  return inst.GetNicMacAddr(0, default)
456 f346a7d9 Michael Hanselmann
457 f346a7d9 Michael Hanselmann
458 cec9845c Michael Hanselmann
def GetMasterNode():
459 8a96c5a6 Michael Hanselmann
  """Wrapper for L{_QaConfig.GetMasterNode}.
460 8a96c5a6 Michael Hanselmann

461 8a96c5a6 Michael Hanselmann
  """
462 8a96c5a6 Michael Hanselmann
  return GetConfig().GetMasterNode()
463 cec9845c Michael Hanselmann
464 cec9845c Michael Hanselmann
465 6a654276 Michael Hanselmann
def AcquireInstance(_cfg=None):
466 cec9845c Michael Hanselmann
  """Returns an instance which isn't in use.
467 cec9845c Michael Hanselmann

468 cec9845c Michael Hanselmann
  """
469 6a654276 Michael Hanselmann
  if _cfg is None:
470 6a654276 Michael Hanselmann
    cfg = GetConfig()
471 6a654276 Michael Hanselmann
  else:
472 6a654276 Michael Hanselmann
    cfg = _cfg
473 6a654276 Michael Hanselmann
474 cec9845c Michael Hanselmann
  # Filter out unwanted instances
475 6a654276 Michael Hanselmann
  instances = filter(lambda inst: not inst.used, cfg["instances"])
476 cec9845c Michael Hanselmann
477 6a654276 Michael Hanselmann
  if not instances:
478 cec9845c Michael Hanselmann
    raise qa_error.OutOfInstancesError("No instances left")
479 cec9845c Michael Hanselmann
480 cec9845c Michael Hanselmann
  inst = instances[0]
481 6a654276 Michael Hanselmann
482 6a654276 Michael Hanselmann
  assert not inst.used
483 6a654276 Michael Hanselmann
  assert inst.disk_template is None
484 6a654276 Michael Hanselmann
485 6a654276 Michael Hanselmann
  inst.used = True
486 6a654276 Michael Hanselmann
487 cec9845c Michael Hanselmann
  return inst
488 cec9845c Michael Hanselmann
489 cec9845c Michael Hanselmann
490 906a0346 Bernardo Dal Seno
def GetInstanceTemplate(inst):
491 906a0346 Bernardo Dal Seno
  """Return the disk template of an instance.
492 906a0346 Bernardo Dal Seno

493 906a0346 Bernardo Dal Seno
  """
494 6a654276 Michael Hanselmann
  templ = inst.disk_template
495 906a0346 Bernardo Dal Seno
  assert templ is not None
496 906a0346 Bernardo Dal Seno
  return templ
497 906a0346 Bernardo Dal Seno
498 906a0346 Bernardo Dal Seno
499 906a0346 Bernardo Dal Seno
def SetInstanceTemplate(inst, template):
500 906a0346 Bernardo Dal Seno
  """Set the disk template for an instance.
501 906a0346 Bernardo Dal Seno

502 906a0346 Bernardo Dal Seno
  """
503 6a654276 Michael Hanselmann
  inst.disk_template = template
504 906a0346 Bernardo Dal Seno
505 906a0346 Bernardo Dal Seno
506 6a0f22e1 Bernardo Dal Seno
def SetExclusiveStorage(value):
507 a08e181f Michael Hanselmann
  """Wrapper for L{_QaConfig.SetExclusiveStorage}.
508 6a0f22e1 Bernardo Dal Seno

509 6a0f22e1 Bernardo Dal Seno
  """
510 a08e181f Michael Hanselmann
  return GetConfig().SetExclusiveStorage(value)
511 6a0f22e1 Bernardo Dal Seno
512 6a0f22e1 Bernardo Dal Seno
513 6a0f22e1 Bernardo Dal Seno
def GetExclusiveStorage():
514 a08e181f Michael Hanselmann
  """Wrapper for L{_QaConfig.GetExclusiveStorage}.
515 6a0f22e1 Bernardo Dal Seno

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

523 27eba428 Bernardo Dal Seno
  """
524 a08e181f Michael Hanselmann
  return GetConfig().IsTemplateSupported(templ)
525 27eba428 Bernardo Dal Seno
526 27eba428 Bernardo Dal Seno
527 dbdb0594 Michael Hanselmann
def AcquireNode(exclude=None, _cfg=None):
528 cec9845c Michael Hanselmann
  """Returns the least used node.
529 cec9845c Michael Hanselmann

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

568 7d4f1b45 Bernardo Dal Seno
  @type num: int
569 7d4f1b45 Bernardo Dal Seno
  @param num: Number of nodes; can be 0.
570 7d4f1b45 Bernardo Dal Seno
  @type exclude: list of nodes or C{None}
571 7d4f1b45 Bernardo Dal Seno
  @param exclude: nodes to be excluded from the choice
572 7d4f1b45 Bernardo Dal Seno
  @rtype: list of nodes
573 7d4f1b45 Bernardo Dal Seno
  @return: C{num} different nodes
574 7d4f1b45 Bernardo Dal Seno

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