Statistics
| Branch: | Tag: | Revision:

root / qa / qa_config.py @ a07ae57f

History | View | Annotate | Download (20.9 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 2dae8d64 Helga Velroyen
_ENABLED_DISK_TEMPLATES_KEY = "enabled-disk-templates"
42 f9329a6c Michael Hanselmann
43 e5398c3a Petr Pudlak
# The path of an optional JSON Patch file (as per RFC6902) that modifies QA's
44 e5398c3a Petr Pudlak
# configuration.
45 e5398c3a Petr Pudlak
_PATCH_JSON = os.path.join(os.path.dirname(__file__), "qa-patch.json")
46 e5398c3a Petr Pudlak
47 8a96c5a6 Michael Hanselmann
#: QA configuration (L{_QaConfig})
48 8a96c5a6 Michael Hanselmann
_config = None
49 cec9845c Michael Hanselmann
50 cec9845c Michael Hanselmann
51 6a654276 Michael Hanselmann
class _QaInstance(object):
52 6a654276 Michael Hanselmann
  __slots__ = [
53 6a654276 Michael Hanselmann
    "name",
54 6a654276 Michael Hanselmann
    "nicmac",
55 2176724e Michael Hanselmann
    "_used",
56 02a5fe0e Michael Hanselmann
    "_disk_template",
57 6a654276 Michael Hanselmann
    ]
58 6a654276 Michael Hanselmann
59 6a654276 Michael Hanselmann
  def __init__(self, name, nicmac):
60 6a654276 Michael Hanselmann
    """Initializes instances of this class.
61 6a654276 Michael Hanselmann

62 6a654276 Michael Hanselmann
    """
63 6a654276 Michael Hanselmann
    self.name = name
64 6a654276 Michael Hanselmann
    self.nicmac = nicmac
65 2176724e Michael Hanselmann
    self._used = None
66 02a5fe0e Michael Hanselmann
    self._disk_template = None
67 6a654276 Michael Hanselmann
68 6a654276 Michael Hanselmann
  @classmethod
69 6a654276 Michael Hanselmann
  def FromDict(cls, data):
70 6a654276 Michael Hanselmann
    """Creates instance object from JSON dictionary.
71 6a654276 Michael Hanselmann

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

95 2176724e Michael Hanselmann
    """
96 2176724e Michael Hanselmann
    assert not self._used
97 2176724e Michael Hanselmann
    assert self._disk_template is None
98 2176724e Michael Hanselmann
99 2176724e Michael Hanselmann
    self._used = True
100 2176724e Michael Hanselmann
101 6f88e076 Michael Hanselmann
  def Release(self):
102 6f88e076 Michael Hanselmann
    """Releases instance and makes it available again.
103 6f88e076 Michael Hanselmann

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

115 6a654276 Michael Hanselmann
    @type idx: int
116 6a654276 Michael Hanselmann
    @param idx: NIC index
117 6a654276 Michael Hanselmann
    @param default: Default value
118 6a654276 Michael Hanselmann

119 6a654276 Michael Hanselmann
    """
120 6a654276 Michael Hanselmann
    if len(self.nicmac) > idx:
121 6a654276 Michael Hanselmann
      return self.nicmac[idx]
122 6a654276 Michael Hanselmann
    else:
123 6a654276 Michael Hanselmann
      return default
124 6a654276 Michael Hanselmann
125 02a5fe0e Michael Hanselmann
  def SetDiskTemplate(self, template):
126 02a5fe0e Michael Hanselmann
    """Set the disk template.
127 02a5fe0e Michael Hanselmann

128 02a5fe0e Michael Hanselmann
    """
129 02a5fe0e Michael Hanselmann
    assert template in constants.DISK_TEMPLATES
130 02a5fe0e Michael Hanselmann
131 02a5fe0e Michael Hanselmann
    self._disk_template = template
132 02a5fe0e Michael Hanselmann
133 02a5fe0e Michael Hanselmann
  @property
134 2176724e Michael Hanselmann
  def used(self):
135 2176724e Michael Hanselmann
    """Returns boolean denoting whether instance is in use.
136 2176724e Michael Hanselmann

137 2176724e Michael Hanselmann
    """
138 2176724e Michael Hanselmann
    return self._used
139 2176724e Michael Hanselmann
140 2176724e Michael Hanselmann
  @property
141 02a5fe0e Michael Hanselmann
  def disk_template(self):
142 02a5fe0e Michael Hanselmann
    """Returns the current disk template.
143 02a5fe0e Michael Hanselmann

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

159 dbdb0594 Michael Hanselmann
    """
160 dbdb0594 Michael Hanselmann
    self.primary = primary
161 dbdb0594 Michael Hanselmann
    self.secondary = secondary
162 dbdb0594 Michael Hanselmann
    self._added = False
163 565cb4bf Michael Hanselmann
    self._use_count = 0
164 dbdb0594 Michael Hanselmann
165 dbdb0594 Michael Hanselmann
  @classmethod
166 dbdb0594 Michael Hanselmann
  def FromDict(cls, data):
167 dbdb0594 Michael Hanselmann
    """Creates node object from JSON dictionary.
168 dbdb0594 Michael Hanselmann

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

186 dbdb0594 Michael Hanselmann
    """
187 565cb4bf Michael Hanselmann
    assert self._use_count >= 0
188 dbdb0594 Michael Hanselmann
189 565cb4bf Michael Hanselmann
    self._use_count += 1
190 dbdb0594 Michael Hanselmann
191 dbdb0594 Michael Hanselmann
    return self
192 dbdb0594 Michael Hanselmann
193 565cb4bf Michael Hanselmann
  def Release(self):
194 565cb4bf Michael Hanselmann
    """Release a node (opposite of L{Use}).
195 565cb4bf Michael Hanselmann

196 565cb4bf Michael Hanselmann
    """
197 565cb4bf Michael Hanselmann
    assert self.use_count > 0
198 565cb4bf Michael Hanselmann
199 565cb4bf Michael Hanselmann
    self._use_count -= 1
200 565cb4bf Michael Hanselmann
201 dbdb0594 Michael Hanselmann
  def MarkAdded(self):
202 dbdb0594 Michael Hanselmann
    """Marks node as having been added to a cluster.
203 dbdb0594 Michael Hanselmann

204 dbdb0594 Michael Hanselmann
    """
205 dbdb0594 Michael Hanselmann
    assert not self._added
206 dbdb0594 Michael Hanselmann
    self._added = True
207 dbdb0594 Michael Hanselmann
208 dbdb0594 Michael Hanselmann
  def MarkRemoved(self):
209 dbdb0594 Michael Hanselmann
    """Marks node as having been removed from a cluster.
210 dbdb0594 Michael Hanselmann

211 dbdb0594 Michael Hanselmann
    """
212 dbdb0594 Michael Hanselmann
    assert self._added
213 dbdb0594 Michael Hanselmann
    self._added = False
214 dbdb0594 Michael Hanselmann
215 dbdb0594 Michael Hanselmann
  @property
216 dbdb0594 Michael Hanselmann
  def added(self):
217 dbdb0594 Michael Hanselmann
    """Returns whether a node is part of a cluster.
218 dbdb0594 Michael Hanselmann

219 dbdb0594 Michael Hanselmann
    """
220 dbdb0594 Michael Hanselmann
    return self._added
221 dbdb0594 Michael Hanselmann
222 565cb4bf Michael Hanselmann
  @property
223 565cb4bf Michael Hanselmann
  def use_count(self):
224 565cb4bf Michael Hanselmann
    """Returns number of current uses (controlled by L{Use} and L{Release}).
225 565cb4bf Michael Hanselmann

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

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

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

261 8a96c5a6 Michael Hanselmann
    @type filename: string
262 8a96c5a6 Michael Hanselmann
    @param filename: Path to configuration file
263 8a96c5a6 Michael Hanselmann
    @rtype: L{_QaConfig}
264 8a96c5a6 Michael Hanselmann

265 8a96c5a6 Michael Hanselmann
    """
266 8a96c5a6 Michael Hanselmann
    data = serializer.LoadJson(utils.ReadFile(filename))
267 8a96c5a6 Michael Hanselmann
268 e5398c3a Petr Pudlak
    # Patch the document using JSON Patch (RFC6902) in file _PATCH_JSON, if
269 e5398c3a Petr Pudlak
    # available
270 e5398c3a Petr Pudlak
    try:
271 e5398c3a Petr Pudlak
      patch = serializer.LoadJson(utils.ReadFile(_PATCH_JSON))
272 e5398c3a Petr Pudlak
      if patch:
273 e5398c3a Petr Pudlak
        mod = __import__("jsonpatch", fromlist=[])
274 e5398c3a Petr Pudlak
        data = mod.apply_patch(data, patch)
275 e5398c3a Petr Pudlak
    except IOError:
276 e5398c3a Petr Pudlak
      pass
277 e5398c3a Petr Pudlak
    except ImportError:
278 e5398c3a Petr Pudlak
      raise qa_error.Error("If you want to use the QA JSON patching feature,"
279 e5398c3a Petr Pudlak
                           " you need to install Python modules"
280 e5398c3a Petr Pudlak
                           " 'jsonpatch' and 'jsonpointer'.")
281 e5398c3a Petr Pudlak
282 6a654276 Michael Hanselmann
    result = cls(dict(map(_ConvertResources,
283 6a654276 Michael Hanselmann
                          data.items()))) # pylint: disable=E1103
284 8a96c5a6 Michael Hanselmann
    result.Validate()
285 8a96c5a6 Michael Hanselmann
286 8a96c5a6 Michael Hanselmann
    return result
287 8a96c5a6 Michael Hanselmann
288 8a96c5a6 Michael Hanselmann
  def Validate(self):
289 8a96c5a6 Michael Hanselmann
    """Validates loaded configuration data.
290 8a96c5a6 Michael Hanselmann

291 8a96c5a6 Michael Hanselmann
    """
292 47aa6ec9 Michael Hanselmann
    if not self.get("name"):
293 47aa6ec9 Michael Hanselmann
      raise qa_error.Error("Cluster name is required")
294 47aa6ec9 Michael Hanselmann
295 8a96c5a6 Michael Hanselmann
    if not self.get("nodes"):
296 8a96c5a6 Michael Hanselmann
      raise qa_error.Error("Need at least one node")
297 8a96c5a6 Michael Hanselmann
298 8a96c5a6 Michael Hanselmann
    if not self.get("instances"):
299 8a96c5a6 Michael Hanselmann
      raise qa_error.Error("Need at least one instance")
300 8a96c5a6 Michael Hanselmann
301 090128b6 Christos Stavrakakis
    disks = self.GetDiskOptions()
302 090128b6 Christos Stavrakakis
    if disks is None:
303 090128b6 Christos Stavrakakis
      raise qa_error.Error("Config option 'disks' must exist")
304 090128b6 Christos Stavrakakis
    else:
305 090128b6 Christos Stavrakakis
      for d in disks:
306 090128b6 Christos Stavrakakis
        if d.get("size") is None or d.get("growth") is None:
307 090128b6 Christos Stavrakakis
          raise qa_error.Error("Config options `size` and `growth` must exist"
308 090128b6 Christos Stavrakakis
                               " for all `disks` items")
309 8a96c5a6 Michael Hanselmann
    check = self.GetInstanceCheckScript()
310 8a96c5a6 Michael Hanselmann
    if check:
311 8a96c5a6 Michael Hanselmann
      try:
312 8a96c5a6 Michael Hanselmann
        os.stat(check)
313 8a96c5a6 Michael Hanselmann
      except EnvironmentError, err:
314 8a96c5a6 Michael Hanselmann
        raise qa_error.Error("Can't find instance check script '%s': %s" %
315 8a96c5a6 Michael Hanselmann
                             (check, err))
316 8a96c5a6 Michael Hanselmann
317 8a96c5a6 Michael Hanselmann
    enabled_hv = frozenset(self.GetEnabledHypervisors())
318 8a96c5a6 Michael Hanselmann
    if not enabled_hv:
319 8a96c5a6 Michael Hanselmann
      raise qa_error.Error("No hypervisor is enabled")
320 8a96c5a6 Michael Hanselmann
321 8a96c5a6 Michael Hanselmann
    difference = enabled_hv - constants.HYPER_TYPES
322 8a96c5a6 Michael Hanselmann
    if difference:
323 8a96c5a6 Michael Hanselmann
      raise qa_error.Error("Unknown hypervisor(s) enabled: %s" %
324 8a96c5a6 Michael Hanselmann
                           utils.CommaJoin(difference))
325 8a96c5a6 Michael Hanselmann
326 76fda900 Michael Hanselmann
    (vc_master, vc_basedir) = self.GetVclusterSettings()
327 76fda900 Michael Hanselmann
    if bool(vc_master) != bool(vc_basedir):
328 76fda900 Michael Hanselmann
      raise qa_error.Error("All or none of the config options '%s' and '%s'"
329 76fda900 Michael Hanselmann
                           " must be set" %
330 76fda900 Michael Hanselmann
                           (_VCLUSTER_MASTER_KEY, _VCLUSTER_BASEDIR_KEY))
331 76fda900 Michael Hanselmann
332 76fda900 Michael Hanselmann
    if vc_basedir and not utils.IsNormAbsPath(vc_basedir):
333 76fda900 Michael Hanselmann
      raise qa_error.Error("Path given in option '%s' must be absolute and"
334 76fda900 Michael Hanselmann
                           " normalized" % _VCLUSTER_BASEDIR_KEY)
335 76fda900 Michael Hanselmann
336 8a96c5a6 Michael Hanselmann
  def __getitem__(self, name):
337 8a96c5a6 Michael Hanselmann
    """Returns configuration value.
338 8a96c5a6 Michael Hanselmann

339 8a96c5a6 Michael Hanselmann
    @type name: string
340 8a96c5a6 Michael Hanselmann
    @param name: Name of configuration entry
341 8a96c5a6 Michael Hanselmann

342 8a96c5a6 Michael Hanselmann
    """
343 8a96c5a6 Michael Hanselmann
    return self._data[name]
344 8a96c5a6 Michael Hanselmann
345 aac832d2 Michele Tartara
  def __setitem__(self, key, value):
346 aac832d2 Michele Tartara
    """Sets a configuration value.
347 aac832d2 Michele Tartara

348 aac832d2 Michele Tartara
    """
349 aac832d2 Michele Tartara
    self._data[key] = value
350 aac832d2 Michele Tartara
351 aac832d2 Michele Tartara
  def __delitem__(self, key):
352 aac832d2 Michele Tartara
    """Deletes a value from the configuration.
353 aac832d2 Michele Tartara

354 aac832d2 Michele Tartara
    """
355 aac832d2 Michele Tartara
    del(self._data[key])
356 aac832d2 Michele Tartara
357 aac832d2 Michele Tartara
  def __len__(self):
358 aac832d2 Michele Tartara
    """Return the number of configuration items.
359 aac832d2 Michele Tartara

360 aac832d2 Michele Tartara
    """
361 aac832d2 Michele Tartara
    return len(self._data)
362 aac832d2 Michele Tartara
363 8a96c5a6 Michael Hanselmann
  def get(self, name, default=None):
364 8a96c5a6 Michael Hanselmann
    """Returns configuration value.
365 8a96c5a6 Michael Hanselmann

366 8a96c5a6 Michael Hanselmann
    @type name: string
367 8a96c5a6 Michael Hanselmann
    @param name: Name of configuration entry
368 8a96c5a6 Michael Hanselmann
    @param default: Default value
369 8a96c5a6 Michael Hanselmann

370 8a96c5a6 Michael Hanselmann
    """
371 8a96c5a6 Michael Hanselmann
    return self._data.get(name, default)
372 cec9845c Michael Hanselmann
373 8a96c5a6 Michael Hanselmann
  def GetMasterNode(self):
374 8a96c5a6 Michael Hanselmann
    """Returns the default master node for the cluster.
375 cec9845c Michael Hanselmann

376 8a96c5a6 Michael Hanselmann
    """
377 8a96c5a6 Michael Hanselmann
    return self["nodes"][0]
378 8a96c5a6 Michael Hanselmann
379 8a96c5a6 Michael Hanselmann
  def GetInstanceCheckScript(self):
380 8a96c5a6 Michael Hanselmann
    """Returns path to instance check script or C{None}.
381 8a96c5a6 Michael Hanselmann

382 8a96c5a6 Michael Hanselmann
    """
383 8a96c5a6 Michael Hanselmann
    return self._data.get(_INSTANCE_CHECK_KEY, None)
384 cec9845c Michael Hanselmann
385 8a96c5a6 Michael Hanselmann
  def GetEnabledHypervisors(self):
386 8a96c5a6 Michael Hanselmann
    """Returns list of enabled hypervisors.
387 cec9845c Michael Hanselmann

388 8a96c5a6 Michael Hanselmann
    @rtype: list
389 cec9845c Michael Hanselmann

390 8a96c5a6 Michael Hanselmann
    """
391 dacd8ba4 Helga Velroyen
    return self._GetStringListParameter(
392 dacd8ba4 Helga Velroyen
      _ENABLED_HV_KEY,
393 dacd8ba4 Helga Velroyen
      [constants.DEFAULT_ENABLED_HYPERVISOR])
394 dacd8ba4 Helga Velroyen
395 dacd8ba4 Helga Velroyen
  def GetDefaultHypervisor(self):
396 dacd8ba4 Helga Velroyen
    """Returns the default hypervisor to be used.
397 dacd8ba4 Helga Velroyen

398 dacd8ba4 Helga Velroyen
    """
399 dacd8ba4 Helga Velroyen
    return self.GetEnabledHypervisors()[0]
400 dacd8ba4 Helga Velroyen
401 2dae8d64 Helga Velroyen
  def GetEnabledDiskTemplates(self):
402 2dae8d64 Helga Velroyen
    """Returns the list of enabled disk templates.
403 dacd8ba4 Helga Velroyen

404 dacd8ba4 Helga Velroyen
    @rtype: list
405 dacd8ba4 Helga Velroyen

406 dacd8ba4 Helga Velroyen
    """
407 dacd8ba4 Helga Velroyen
    return self._GetStringListParameter(
408 2dae8d64 Helga Velroyen
      _ENABLED_DISK_TEMPLATES_KEY,
409 decf86f9 Helga Velroyen
      constants.DEFAULT_ENABLED_DISK_TEMPLATES)
410 dacd8ba4 Helga Velroyen
411 5949c31c Helga Velroyen
  def GetEnabledStorageTypes(self):
412 5949c31c Helga Velroyen
    """Returns the list of enabled storage types.
413 5949c31c Helga Velroyen

414 5949c31c Helga Velroyen
    @rtype: list
415 5949c31c Helga Velroyen
    @returns: the list of storage types enabled for QA
416 5949c31c Helga Velroyen

417 5949c31c Helga Velroyen
    """
418 5949c31c Helga Velroyen
    enabled_disk_templates = self.GetEnabledDiskTemplates()
419 615551b2 Helga Velroyen
    enabled_storage_types = list(
420 615551b2 Helga Velroyen
        set([constants.MAP_DISK_TEMPLATE_STORAGE_TYPE[dt]
421 615551b2 Helga Velroyen
             for dt in enabled_disk_templates]))
422 5949c31c Helga Velroyen
    # Storage type 'lvm-pv' cannot be activated via a disk template,
423 5949c31c Helga Velroyen
    # therefore we add it if 'lvm-vg' is present.
424 5949c31c Helga Velroyen
    if constants.ST_LVM_VG in enabled_storage_types:
425 5949c31c Helga Velroyen
      enabled_storage_types.append(constants.ST_LVM_PV)
426 5949c31c Helga Velroyen
    return enabled_storage_types
427 5949c31c Helga Velroyen
428 2dae8d64 Helga Velroyen
  def GetDefaultDiskTemplate(self):
429 2dae8d64 Helga Velroyen
    """Returns the default disk template to be used.
430 dacd8ba4 Helga Velroyen

431 dacd8ba4 Helga Velroyen
    """
432 2dae8d64 Helga Velroyen
    return self.GetEnabledDiskTemplates()[0]
433 dacd8ba4 Helga Velroyen
434 dacd8ba4 Helga Velroyen
  def _GetStringListParameter(self, key, default_values):
435 dacd8ba4 Helga Velroyen
    """Retrieves a parameter's value that is supposed to be a list of strings.
436 dacd8ba4 Helga Velroyen

437 dacd8ba4 Helga Velroyen
    @rtype: list
438 dacd8ba4 Helga Velroyen

439 dacd8ba4 Helga Velroyen
    """
440 c9e05005 Michael Hanselmann
    try:
441 dacd8ba4 Helga Velroyen
      value = self._data[key]
442 8a96c5a6 Michael Hanselmann
    except KeyError:
443 dacd8ba4 Helga Velroyen
      return default_values
444 8a96c5a6 Michael Hanselmann
    else:
445 8a96c5a6 Michael Hanselmann
      if value is None:
446 8a96c5a6 Michael Hanselmann
        return []
447 8a96c5a6 Michael Hanselmann
      elif isinstance(value, basestring):
448 8a96c5a6 Michael Hanselmann
        return value.split(",")
449 8a96c5a6 Michael Hanselmann
      else:
450 8a96c5a6 Michael Hanselmann
        return value
451 8a96c5a6 Michael Hanselmann
452 a08e181f Michael Hanselmann
  def SetExclusiveStorage(self, value):
453 a08e181f Michael Hanselmann
    """Set the expected value of the C{exclusive_storage} flag for the cluster.
454 a08e181f Michael Hanselmann

455 a08e181f Michael Hanselmann
    """
456 a08e181f Michael Hanselmann
    self._exclusive_storage = bool(value)
457 a08e181f Michael Hanselmann
458 a08e181f Michael Hanselmann
  def GetExclusiveStorage(self):
459 a08e181f Michael Hanselmann
    """Get the expected value of the C{exclusive_storage} flag for the cluster.
460 a08e181f Michael Hanselmann

461 a08e181f Michael Hanselmann
    """
462 a08e181f Michael Hanselmann
    value = self._exclusive_storage
463 a08e181f Michael Hanselmann
    assert value is not None
464 a08e181f Michael Hanselmann
    return value
465 a08e181f Michael Hanselmann
466 a08e181f Michael Hanselmann
  def IsTemplateSupported(self, templ):
467 a08e181f Michael Hanselmann
    """Is the given disk template supported by the current configuration?
468 a08e181f Michael Hanselmann

469 a08e181f Michael Hanselmann
    """
470 02cff8aa Bernardo Dal Seno
    enabled = templ in self.GetEnabledDiskTemplates()
471 02cff8aa Bernardo Dal Seno
    return enabled and (not self.GetExclusiveStorage() or
472 02cff8aa Bernardo Dal Seno
                        templ in constants.DTS_EXCL_STORAGE)
473 a08e181f Michael Hanselmann
474 bab4f56a Helga Velroyen
  def IsStorageTypeSupported(self, storage_type):
475 bab4f56a Helga Velroyen
    """Is the given storage type supported by the current configuration?
476 bab4f56a Helga Velroyen

477 bab4f56a Helga Velroyen
    This is determined by looking if at least one of the disk templates
478 bab4f56a Helga Velroyen
    which is associated with the storage type is enabled in the configuration.
479 bab4f56a Helga Velroyen

480 bab4f56a Helga Velroyen
    """
481 bab4f56a Helga Velroyen
    enabled_disk_templates = self.GetEnabledDiskTemplates()
482 bab4f56a Helga Velroyen
    if storage_type == constants.ST_LVM_PV:
483 5a904197 Santi Raffa
      disk_templates = utils.GetDiskTemplatesOfStorageTypes(constants.ST_LVM_VG)
484 bab4f56a Helga Velroyen
    else:
485 5a904197 Santi Raffa
      disk_templates = utils.GetDiskTemplatesOfStorageTypes(storage_type)
486 bab4f56a Helga Velroyen
    return bool(set(enabled_disk_templates).intersection(set(disk_templates)))
487 bab4f56a Helga Velroyen
488 345d395d Bernardo Dal Seno
  def AreSpindlesSupported(self):
489 345d395d Bernardo Dal Seno
    """Are spindles supported by the current configuration?
490 345d395d Bernardo Dal Seno

491 345d395d Bernardo Dal Seno
    """
492 345d395d Bernardo Dal Seno
    return self.GetExclusiveStorage()
493 345d395d Bernardo Dal Seno
494 76fda900 Michael Hanselmann
  def GetVclusterSettings(self):
495 76fda900 Michael Hanselmann
    """Returns settings for virtual cluster.
496 76fda900 Michael Hanselmann

497 76fda900 Michael Hanselmann
    """
498 76fda900 Michael Hanselmann
    master = self.get(_VCLUSTER_MASTER_KEY)
499 76fda900 Michael Hanselmann
    basedir = self.get(_VCLUSTER_BASEDIR_KEY)
500 76fda900 Michael Hanselmann
501 76fda900 Michael Hanselmann
    return (master, basedir)
502 76fda900 Michael Hanselmann
503 090128b6 Christos Stavrakakis
  def GetDiskOptions(self):
504 090128b6 Christos Stavrakakis
    """Return options for the disks of the instances.
505 090128b6 Christos Stavrakakis

506 090128b6 Christos Stavrakakis
    Get 'disks' parameter from the configuration data. If 'disks' is missing,
507 090128b6 Christos Stavrakakis
    try to create it from the legacy 'disk' and 'disk-growth' parameters.
508 090128b6 Christos Stavrakakis

509 090128b6 Christos Stavrakakis
    """
510 090128b6 Christos Stavrakakis
    try:
511 090128b6 Christos Stavrakakis
      return self._data["disks"]
512 090128b6 Christos Stavrakakis
    except KeyError:
513 090128b6 Christos Stavrakakis
      pass
514 090128b6 Christos Stavrakakis
515 090128b6 Christos Stavrakakis
    # Legacy interface
516 090128b6 Christos Stavrakakis
    sizes = self._data.get("disk")
517 090128b6 Christos Stavrakakis
    growths = self._data.get("disk-growth")
518 090128b6 Christos Stavrakakis
    if sizes or growths:
519 090128b6 Christos Stavrakakis
      if (sizes is None or growths is None or len(sizes) != len(growths)):
520 090128b6 Christos Stavrakakis
        raise qa_error.Error("Config options 'disk' and 'disk-growth' must"
521 090128b6 Christos Stavrakakis
                             " exist and have the same number of items")
522 090128b6 Christos Stavrakakis
      disks = []
523 090128b6 Christos Stavrakakis
      for (size, growth) in zip(sizes, growths):
524 090128b6 Christos Stavrakakis
        disks.append({"size": size, "growth": growth})
525 090128b6 Christos Stavrakakis
      return disks
526 090128b6 Christos Stavrakakis
    else:
527 090128b6 Christos Stavrakakis
      return None
528 090128b6 Christos Stavrakakis
529 8a96c5a6 Michael Hanselmann
530 8a96c5a6 Michael Hanselmann
def Load(path):
531 8a96c5a6 Michael Hanselmann
  """Loads the passed configuration file.
532 8a96c5a6 Michael Hanselmann

533 8a96c5a6 Michael Hanselmann
  """
534 8a96c5a6 Michael Hanselmann
  global _config # pylint: disable=W0603
535 8a96c5a6 Michael Hanselmann
536 8a96c5a6 Michael Hanselmann
  _config = _QaConfig.Load(path)
537 c9e05005 Michael Hanselmann
538 e7b6183b Michael Hanselmann
539 8a96c5a6 Michael Hanselmann
def GetConfig():
540 8a96c5a6 Michael Hanselmann
  """Returns the configuration object.
541 8a96c5a6 Michael Hanselmann

542 8a96c5a6 Michael Hanselmann
  """
543 8a96c5a6 Michael Hanselmann
  if _config is None:
544 8a96c5a6 Michael Hanselmann
    raise RuntimeError("Configuration not yet loaded")
545 8a96c5a6 Michael Hanselmann
546 8a96c5a6 Michael Hanselmann
  return _config
547 e7b6183b Michael Hanselmann
548 cec9845c Michael Hanselmann
549 cec9845c Michael Hanselmann
def get(name, default=None):
550 8a96c5a6 Michael Hanselmann
  """Wrapper for L{_QaConfig.get}.
551 8a96c5a6 Michael Hanselmann

552 8a96c5a6 Michael Hanselmann
  """
553 8a96c5a6 Michael Hanselmann
  return GetConfig().get(name, default=default)
554 cec9845c Michael Hanselmann
555 cec9845c Michael Hanselmann
556 a0c3e726 Michael Hanselmann
class Either:
557 a0c3e726 Michael Hanselmann
  def __init__(self, tests):
558 a0c3e726 Michael Hanselmann
    """Initializes this class.
559 a0c3e726 Michael Hanselmann

560 a0c3e726 Michael Hanselmann
    @type tests: list or string
561 a0c3e726 Michael Hanselmann
    @param tests: List of test names
562 a0c3e726 Michael Hanselmann
    @see: L{TestEnabled} for details
563 a0c3e726 Michael Hanselmann

564 a0c3e726 Michael Hanselmann
    """
565 a0c3e726 Michael Hanselmann
    self.tests = tests
566 a0c3e726 Michael Hanselmann
567 a0c3e726 Michael Hanselmann
568 a0c3e726 Michael Hanselmann
def _MakeSequence(value):
569 a0c3e726 Michael Hanselmann
  """Make sequence of single argument.
570 a0c3e726 Michael Hanselmann

571 a0c3e726 Michael Hanselmann
  If the single argument is not already a list or tuple, a list with the
572 a0c3e726 Michael Hanselmann
  argument as a single item is returned.
573 a0c3e726 Michael Hanselmann

574 a0c3e726 Michael Hanselmann
  """
575 a0c3e726 Michael Hanselmann
  if isinstance(value, (list, tuple)):
576 a0c3e726 Michael Hanselmann
    return value
577 a0c3e726 Michael Hanselmann
  else:
578 a0c3e726 Michael Hanselmann
    return [value]
579 a0c3e726 Michael Hanselmann
580 a0c3e726 Michael Hanselmann
581 a0c3e726 Michael Hanselmann
def _TestEnabledInner(check_fn, names, fn):
582 a0c3e726 Michael Hanselmann
  """Evaluate test conditions.
583 a0c3e726 Michael Hanselmann

584 a0c3e726 Michael Hanselmann
  @type check_fn: callable
585 a0c3e726 Michael Hanselmann
  @param check_fn: Callback to check whether a test is enabled
586 a0c3e726 Michael Hanselmann
  @type names: sequence or string
587 a0c3e726 Michael Hanselmann
  @param names: Test name(s)
588 a0c3e726 Michael Hanselmann
  @type fn: callable
589 a0c3e726 Michael Hanselmann
  @param fn: Aggregation function
590 a0c3e726 Michael Hanselmann
  @rtype: bool
591 a0c3e726 Michael Hanselmann
  @return: Whether test is enabled
592 a0c3e726 Michael Hanselmann

593 a0c3e726 Michael Hanselmann
  """
594 a0c3e726 Michael Hanselmann
  names = _MakeSequence(names)
595 a0c3e726 Michael Hanselmann
596 a0c3e726 Michael Hanselmann
  result = []
597 a0c3e726 Michael Hanselmann
598 a0c3e726 Michael Hanselmann
  for name in names:
599 a0c3e726 Michael Hanselmann
    if isinstance(name, Either):
600 a0c3e726 Michael Hanselmann
      value = _TestEnabledInner(check_fn, name.tests, compat.any)
601 a0c3e726 Michael Hanselmann
    elif isinstance(name, (list, tuple)):
602 a0c3e726 Michael Hanselmann
      value = _TestEnabledInner(check_fn, name, compat.all)
603 c072e788 Michael Hanselmann
    elif callable(name):
604 c072e788 Michael Hanselmann
      value = name()
605 a0c3e726 Michael Hanselmann
    else:
606 a0c3e726 Michael Hanselmann
      value = check_fn(name)
607 a0c3e726 Michael Hanselmann
608 a0c3e726 Michael Hanselmann
    result.append(value)
609 a0c3e726 Michael Hanselmann
610 a0c3e726 Michael Hanselmann
  return fn(result)
611 a0c3e726 Michael Hanselmann
612 a0c3e726 Michael Hanselmann
613 a0c3e726 Michael Hanselmann
def TestEnabled(tests, _cfg=None):
614 7d88f255 Iustin Pop
  """Returns True if the given tests are enabled.
615 7d88f255 Iustin Pop

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

619 1010ec70 Michael Hanselmann
  """
620 a0c3e726 Michael Hanselmann
  if _cfg is None:
621 8a96c5a6 Michael Hanselmann
    cfg = GetConfig()
622 8a96c5a6 Michael Hanselmann
  else:
623 8a96c5a6 Michael Hanselmann
    cfg = _cfg
624 59a8fe48 Michael Hanselmann
625 59a8fe48 Michael Hanselmann
  # Get settings for all tests
626 8a96c5a6 Michael Hanselmann
  cfg_tests = cfg.get("tests", {})
627 59a8fe48 Michael Hanselmann
628 59a8fe48 Michael Hanselmann
  # Get default setting
629 a0c3e726 Michael Hanselmann
  default = cfg_tests.get("default", True)
630 59a8fe48 Michael Hanselmann
631 a0c3e726 Michael Hanselmann
  return _TestEnabledInner(lambda name: cfg_tests.get(name, default),
632 a0c3e726 Michael Hanselmann
                           tests, compat.all)
633 cec9845c Michael Hanselmann
634 cec9845c Michael Hanselmann
635 8a96c5a6 Michael Hanselmann
def GetInstanceCheckScript(*args):
636 8a96c5a6 Michael Hanselmann
  """Wrapper for L{_QaConfig.GetInstanceCheckScript}.
637 c9e05005 Michael Hanselmann

638 c9e05005 Michael Hanselmann
  """
639 8a96c5a6 Michael Hanselmann
  return GetConfig().GetInstanceCheckScript(*args)
640 c9e05005 Michael Hanselmann
641 e7b6183b Michael Hanselmann
642 8a96c5a6 Michael Hanselmann
def GetEnabledHypervisors(*args):
643 8a96c5a6 Michael Hanselmann
  """Wrapper for L{_QaConfig.GetEnabledHypervisors}.
644 e7b6183b Michael Hanselmann

645 e7b6183b Michael Hanselmann
  """
646 8a96c5a6 Michael Hanselmann
  return GetConfig().GetEnabledHypervisors(*args)
647 e7b6183b Michael Hanselmann
648 e7b6183b Michael Hanselmann
649 8a96c5a6 Michael Hanselmann
def GetDefaultHypervisor(*args):
650 8a96c5a6 Michael Hanselmann
  """Wrapper for L{_QaConfig.GetDefaultHypervisor}.
651 e7b6183b Michael Hanselmann

652 e7b6183b Michael Hanselmann
  """
653 8a96c5a6 Michael Hanselmann
  return GetConfig().GetDefaultHypervisor(*args)
654 dacd8ba4 Helga Velroyen
655 dacd8ba4 Helga Velroyen
656 2dae8d64 Helga Velroyen
def GetEnabledDiskTemplates(*args):
657 2dae8d64 Helga Velroyen
  """Wrapper for L{_QaConfig.GetEnabledDiskTemplates}.
658 dacd8ba4 Helga Velroyen

659 dacd8ba4 Helga Velroyen
  """
660 2dae8d64 Helga Velroyen
  return GetConfig().GetEnabledDiskTemplates(*args)
661 dacd8ba4 Helga Velroyen
662 dacd8ba4 Helga Velroyen
663 5949c31c Helga Velroyen
def GetEnabledStorageTypes(*args):
664 5949c31c Helga Velroyen
  """Wrapper for L{_QaConfig.GetEnabledStorageTypes}.
665 5949c31c Helga Velroyen

666 5949c31c Helga Velroyen
  """
667 5949c31c Helga Velroyen
  return GetConfig().GetEnabledStorageTypes(*args)
668 5949c31c Helga Velroyen
669 5949c31c Helga Velroyen
670 2dae8d64 Helga Velroyen
def GetDefaultDiskTemplate(*args):
671 2dae8d64 Helga Velroyen
  """Wrapper for L{_QaConfig.GetDefaultDiskTemplate}.
672 dacd8ba4 Helga Velroyen

673 dacd8ba4 Helga Velroyen
  """
674 2dae8d64 Helga Velroyen
  return GetConfig().GetDefaultDiskTemplate(*args)
675 e7b6183b Michael Hanselmann
676 e7b6183b Michael Hanselmann
677 cec9845c Michael Hanselmann
def GetMasterNode():
678 8a96c5a6 Michael Hanselmann
  """Wrapper for L{_QaConfig.GetMasterNode}.
679 8a96c5a6 Michael Hanselmann

680 8a96c5a6 Michael Hanselmann
  """
681 8a96c5a6 Michael Hanselmann
  return GetConfig().GetMasterNode()
682 cec9845c Michael Hanselmann
683 cec9845c Michael Hanselmann
684 6a654276 Michael Hanselmann
def AcquireInstance(_cfg=None):
685 cec9845c Michael Hanselmann
  """Returns an instance which isn't in use.
686 cec9845c Michael Hanselmann

687 cec9845c Michael Hanselmann
  """
688 6a654276 Michael Hanselmann
  if _cfg is None:
689 6a654276 Michael Hanselmann
    cfg = GetConfig()
690 6a654276 Michael Hanselmann
  else:
691 6a654276 Michael Hanselmann
    cfg = _cfg
692 6a654276 Michael Hanselmann
693 cec9845c Michael Hanselmann
  # Filter out unwanted instances
694 6a654276 Michael Hanselmann
  instances = filter(lambda inst: not inst.used, cfg["instances"])
695 cec9845c Michael Hanselmann
696 6a654276 Michael Hanselmann
  if not instances:
697 cec9845c Michael Hanselmann
    raise qa_error.OutOfInstancesError("No instances left")
698 cec9845c Michael Hanselmann
699 2176724e Michael Hanselmann
  instance = instances[0]
700 2176724e Michael Hanselmann
  instance.Use()
701 6a654276 Michael Hanselmann
702 2176724e Michael Hanselmann
  return instance
703 cec9845c Michael Hanselmann
704 cec9845c Michael Hanselmann
705 c2e22e7b Hrvoje Ribicic
def AcquireManyInstances(num, _cfg=None):
706 c2e22e7b Hrvoje Ribicic
  """Return instances that are not in use.
707 c2e22e7b Hrvoje Ribicic

708 c2e22e7b Hrvoje Ribicic
  @type num: int
709 c2e22e7b Hrvoje Ribicic
  @param num: Number of instances; can be 0.
710 c2e22e7b Hrvoje Ribicic
  @rtype: list of instances
711 c2e22e7b Hrvoje Ribicic
  @return: C{num} different instances
712 c2e22e7b Hrvoje Ribicic

713 c2e22e7b Hrvoje Ribicic
  """
714 c2e22e7b Hrvoje Ribicic
715 c2e22e7b Hrvoje Ribicic
  if _cfg is None:
716 c2e22e7b Hrvoje Ribicic
    cfg = GetConfig()
717 c2e22e7b Hrvoje Ribicic
  else:
718 c2e22e7b Hrvoje Ribicic
    cfg = _cfg
719 c2e22e7b Hrvoje Ribicic
720 c2e22e7b Hrvoje Ribicic
  # Filter out unwanted instances
721 c2e22e7b Hrvoje Ribicic
  instances = filter(lambda inst: not inst.used, cfg["instances"])
722 c2e22e7b Hrvoje Ribicic
723 c2e22e7b Hrvoje Ribicic
  if len(instances) < num:
724 c2e22e7b Hrvoje Ribicic
    raise qa_error.OutOfInstancesError(
725 c2e22e7b Hrvoje Ribicic
      "Not enough instances left (%d needed, %d remaining)" %
726 c2e22e7b Hrvoje Ribicic
      (num, len(instances))
727 c2e22e7b Hrvoje Ribicic
    )
728 c2e22e7b Hrvoje Ribicic
729 c2e22e7b Hrvoje Ribicic
  instances = []
730 c2e22e7b Hrvoje Ribicic
731 c2e22e7b Hrvoje Ribicic
  try:
732 c2e22e7b Hrvoje Ribicic
    for _ in range(0, num):
733 c2e22e7b Hrvoje Ribicic
      n = AcquireInstance(_cfg=cfg)
734 c2e22e7b Hrvoje Ribicic
      instances.append(n)
735 c2e22e7b Hrvoje Ribicic
  except qa_error.OutOfInstancesError:
736 c2e22e7b Hrvoje Ribicic
    ReleaseManyInstances(instances)
737 c2e22e7b Hrvoje Ribicic
    raise
738 c2e22e7b Hrvoje Ribicic
739 c2e22e7b Hrvoje Ribicic
  return instances
740 c2e22e7b Hrvoje Ribicic
741 c2e22e7b Hrvoje Ribicic
742 c2e22e7b Hrvoje Ribicic
def ReleaseManyInstances(instances):
743 c2e22e7b Hrvoje Ribicic
  for instance in instances:
744 c2e22e7b Hrvoje Ribicic
    instance.Release()
745 c2e22e7b Hrvoje Ribicic
746 c2e22e7b Hrvoje Ribicic
747 6a0f22e1 Bernardo Dal Seno
def SetExclusiveStorage(value):
748 a08e181f Michael Hanselmann
  """Wrapper for L{_QaConfig.SetExclusiveStorage}.
749 6a0f22e1 Bernardo Dal Seno

750 6a0f22e1 Bernardo Dal Seno
  """
751 a08e181f Michael Hanselmann
  return GetConfig().SetExclusiveStorage(value)
752 6a0f22e1 Bernardo Dal Seno
753 6a0f22e1 Bernardo Dal Seno
754 6a0f22e1 Bernardo Dal Seno
def GetExclusiveStorage():
755 a08e181f Michael Hanselmann
  """Wrapper for L{_QaConfig.GetExclusiveStorage}.
756 6a0f22e1 Bernardo Dal Seno

757 6a0f22e1 Bernardo Dal Seno
  """
758 a08e181f Michael Hanselmann
  return GetConfig().GetExclusiveStorage()
759 6a0f22e1 Bernardo Dal Seno
760 6a0f22e1 Bernardo Dal Seno
761 27eba428 Bernardo Dal Seno
def IsTemplateSupported(templ):
762 02cff8aa Bernardo Dal Seno
  """Wrapper for L{_QaConfig.IsTemplateSupported}.
763 27eba428 Bernardo Dal Seno

764 27eba428 Bernardo Dal Seno
  """
765 a08e181f Michael Hanselmann
  return GetConfig().IsTemplateSupported(templ)
766 27eba428 Bernardo Dal Seno
767 27eba428 Bernardo Dal Seno
768 bab4f56a Helga Velroyen
def IsStorageTypeSupported(storage_type):
769 bab4f56a Helga Velroyen
  """Wrapper for L{_QaConfig.IsTemplateSupported}.
770 bab4f56a Helga Velroyen

771 bab4f56a Helga Velroyen
  """
772 bab4f56a Helga Velroyen
  return GetConfig().IsStorageTypeSupported(storage_type)
773 bab4f56a Helga Velroyen
774 bab4f56a Helga Velroyen
775 345d395d Bernardo Dal Seno
def AreSpindlesSupported():
776 345d395d Bernardo Dal Seno
  """Wrapper for L{_QaConfig.AreSpindlesSupported}.
777 345d395d Bernardo Dal Seno

778 345d395d Bernardo Dal Seno
  """
779 345d395d Bernardo Dal Seno
  return GetConfig().AreSpindlesSupported()
780 345d395d Bernardo Dal Seno
781 345d395d Bernardo Dal Seno
782 41be279f Michael Hanselmann
def _NodeSortKey(node):
783 41be279f Michael Hanselmann
  """Returns sort key for a node.
784 41be279f Michael Hanselmann

785 41be279f Michael Hanselmann
  @type node: L{_QaNode}
786 41be279f Michael Hanselmann

787 41be279f Michael Hanselmann
  """
788 41be279f Michael Hanselmann
  return (node.use_count, utils.NiceSortKey(node.primary))
789 41be279f Michael Hanselmann
790 41be279f Michael Hanselmann
791 dbdb0594 Michael Hanselmann
def AcquireNode(exclude=None, _cfg=None):
792 cec9845c Michael Hanselmann
  """Returns the least used node.
793 cec9845c Michael Hanselmann

794 cec9845c Michael Hanselmann
  """
795 dbdb0594 Michael Hanselmann
  if _cfg is None:
796 dbdb0594 Michael Hanselmann
    cfg = GetConfig()
797 dbdb0594 Michael Hanselmann
  else:
798 dbdb0594 Michael Hanselmann
    cfg = _cfg
799 dbdb0594 Michael Hanselmann
800 dbdb0594 Michael Hanselmann
  master = cfg.GetMasterNode()
801 cec9845c Michael Hanselmann
802 cec9845c Michael Hanselmann
  # Filter out unwanted nodes
803 cec9845c Michael Hanselmann
  # TODO: Maybe combine filters
804 cec9845c Michael Hanselmann
  if exclude is None:
805 d0c8c01d Iustin Pop
    nodes = cfg["nodes"][:]
806 4b62db14 Michael Hanselmann
  elif isinstance(exclude, (list, tuple)):
807 d0c8c01d Iustin Pop
    nodes = filter(lambda node: node not in exclude, cfg["nodes"])
808 cec9845c Michael Hanselmann
  else:
809 d0c8c01d Iustin Pop
    nodes = filter(lambda node: node != exclude, cfg["nodes"])
810 cec9845c Michael Hanselmann
811 dbdb0594 Michael Hanselmann
  nodes = filter(lambda node: node.added or node == master, nodes)
812 cec9845c Michael Hanselmann
813 dbdb0594 Michael Hanselmann
  if not nodes:
814 cec9845c Michael Hanselmann
    raise qa_error.OutOfNodesError("No nodes left")
815 cec9845c Michael Hanselmann
816 41be279f Michael Hanselmann
  # Return node with least number of uses
817 41be279f Michael Hanselmann
  return sorted(nodes, key=_NodeSortKey)[0].Use()
818 cec9845c Michael Hanselmann
819 cec9845c Michael Hanselmann
820 e44b72bb Petr Pudlak
class AcquireManyNodesCtx(object):
821 e44b72bb Petr Pudlak
  """Returns the least used nodes for use with a `with` block
822 e44b72bb Petr Pudlak

823 e44b72bb Petr Pudlak
  """
824 e44b72bb Petr Pudlak
  def __init__(self, num, exclude=None, cfg=None):
825 e44b72bb Petr Pudlak
    self._num = num
826 e44b72bb Petr Pudlak
    self._exclude = exclude
827 e44b72bb Petr Pudlak
    self._cfg = cfg
828 e44b72bb Petr Pudlak
829 e44b72bb Petr Pudlak
  def __enter__(self):
830 e44b72bb Petr Pudlak
    self._nodes = AcquireManyNodes(self._num, exclude=self._exclude,
831 e44b72bb Petr Pudlak
                                   cfg=self._cfg)
832 e44b72bb Petr Pudlak
    return self._nodes
833 e44b72bb Petr Pudlak
834 e44b72bb Petr Pudlak
  def __exit__(self, exc_type, exc_value, exc_tb):
835 e44b72bb Petr Pudlak
    ReleaseManyNodes(self._nodes)
836 e44b72bb Petr Pudlak
837 e44b72bb Petr Pudlak
838 e44b72bb Petr Pudlak
def AcquireManyNodes(num, exclude=None, cfg=None):
839 7d4f1b45 Bernardo Dal Seno
  """Return the least used nodes.
840 7d4f1b45 Bernardo Dal Seno

841 7d4f1b45 Bernardo Dal Seno
  @type num: int
842 7d4f1b45 Bernardo Dal Seno
  @param num: Number of nodes; can be 0.
843 7d4f1b45 Bernardo Dal Seno
  @type exclude: list of nodes or C{None}
844 7d4f1b45 Bernardo Dal Seno
  @param exclude: nodes to be excluded from the choice
845 7d4f1b45 Bernardo Dal Seno
  @rtype: list of nodes
846 7d4f1b45 Bernardo Dal Seno
  @return: C{num} different nodes
847 7d4f1b45 Bernardo Dal Seno

848 7d4f1b45 Bernardo Dal Seno
  """
849 7d4f1b45 Bernardo Dal Seno
  nodes = []
850 7d4f1b45 Bernardo Dal Seno
  if exclude is None:
851 7d4f1b45 Bernardo Dal Seno
    exclude = []
852 7d4f1b45 Bernardo Dal Seno
  elif isinstance(exclude, (list, tuple)):
853 7d4f1b45 Bernardo Dal Seno
    # Don't modify the incoming argument
854 7d4f1b45 Bernardo Dal Seno
    exclude = list(exclude)
855 7d4f1b45 Bernardo Dal Seno
  else:
856 7d4f1b45 Bernardo Dal Seno
    exclude = [exclude]
857 7d4f1b45 Bernardo Dal Seno
858 7d4f1b45 Bernardo Dal Seno
  try:
859 7d4f1b45 Bernardo Dal Seno
    for _ in range(0, num):
860 e44b72bb Petr Pudlak
      n = AcquireNode(exclude=exclude, _cfg=cfg)
861 7d4f1b45 Bernardo Dal Seno
      nodes.append(n)
862 7d4f1b45 Bernardo Dal Seno
      exclude.append(n)
863 7d4f1b45 Bernardo Dal Seno
  except qa_error.OutOfNodesError:
864 7d4f1b45 Bernardo Dal Seno
    ReleaseManyNodes(nodes)
865 7d4f1b45 Bernardo Dal Seno
    raise
866 7d4f1b45 Bernardo Dal Seno
  return nodes
867 7d4f1b45 Bernardo Dal Seno
868 7d4f1b45 Bernardo Dal Seno
869 7d4f1b45 Bernardo Dal Seno
def ReleaseManyNodes(nodes):
870 565cb4bf Michael Hanselmann
  for node in nodes:
871 565cb4bf Michael Hanselmann
    node.Release()
872 76fda900 Michael Hanselmann
873 76fda900 Michael Hanselmann
874 76fda900 Michael Hanselmann
def GetVclusterSettings():
875 76fda900 Michael Hanselmann
  """Wrapper for L{_QaConfig.GetVclusterSettings}.
876 76fda900 Michael Hanselmann

877 76fda900 Michael Hanselmann
  """
878 76fda900 Michael Hanselmann
  return GetConfig().GetVclusterSettings()
879 76fda900 Michael Hanselmann
880 76fda900 Michael Hanselmann
881 76fda900 Michael Hanselmann
def UseVirtualCluster(_cfg=None):
882 76fda900 Michael Hanselmann
  """Returns whether a virtual cluster is used.
883 76fda900 Michael Hanselmann

884 76fda900 Michael Hanselmann
  @rtype: bool
885 76fda900 Michael Hanselmann

886 76fda900 Michael Hanselmann
  """
887 76fda900 Michael Hanselmann
  if _cfg is None:
888 76fda900 Michael Hanselmann
    cfg = GetConfig()
889 76fda900 Michael Hanselmann
  else:
890 76fda900 Michael Hanselmann
    cfg = _cfg
891 76fda900 Michael Hanselmann
892 76fda900 Michael Hanselmann
  (master, _) = cfg.GetVclusterSettings()
893 76fda900 Michael Hanselmann
894 76fda900 Michael Hanselmann
  return bool(master)
895 76fda900 Michael Hanselmann
896 76fda900 Michael Hanselmann
897 76fda900 Michael Hanselmann
@ht.WithDesc("No virtual cluster")
898 76fda900 Michael Hanselmann
def NoVirtualCluster():
899 76fda900 Michael Hanselmann
  """Used to disable tests for virtual clusters.
900 76fda900 Michael Hanselmann

901 76fda900 Michael Hanselmann
  """
902 76fda900 Michael Hanselmann
  return not UseVirtualCluster()
903 090128b6 Christos Stavrakakis
904 090128b6 Christos Stavrakakis
905 090128b6 Christos Stavrakakis
def GetDiskOptions():
906 090128b6 Christos Stavrakakis
  """Wrapper for L{_QaConfig.GetDiskOptions}.
907 090128b6 Christos Stavrakakis

908 090128b6 Christos Stavrakakis
  """
909 090128b6 Christos Stavrakakis
  return GetConfig().GetDiskOptions()