Statistics
| Branch: | Tag: | Revision:

root / qa / qa_config.py @ 25e9c2ce

History | View | Annotate | Download (23.6 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 7488cf4b Hrvoje Ribicic
import qa_logging
36 cec9845c Michael Hanselmann
37 cec9845c Michael Hanselmann
38 c9e05005 Michael Hanselmann
_INSTANCE_CHECK_KEY = "instance-check"
39 e7b6183b Michael Hanselmann
_ENABLED_HV_KEY = "enabled-hypervisors"
40 76fda900 Michael Hanselmann
_VCLUSTER_MASTER_KEY = "vcluster-master"
41 76fda900 Michael Hanselmann
_VCLUSTER_BASEDIR_KEY = "vcluster-basedir"
42 2dae8d64 Helga Velroyen
_ENABLED_DISK_TEMPLATES_KEY = "enabled-disk-templates"
43 f9329a6c Michael Hanselmann
44 a60fc78e Hrvoje Ribicic
# The constants related to JSON patching (as per RFC6902) that modifies QA's
45 b7630577 Petr Pudlak
# configuration.
46 c8bf5cf4 Hrvoje Ribicic
_QA_BASE_PATH = os.path.dirname(__file__)
47 c8bf5cf4 Hrvoje Ribicic
_QA_DEFAULT_PATCH = "qa-patch.json"
48 a60fc78e Hrvoje Ribicic
_QA_PATCH_DIR = "patch"
49 7441bb96 Hrvoje Ribicic
_QA_PATCH_ORDER_FILE = "order"
50 b7630577 Petr Pudlak
51 8a96c5a6 Michael Hanselmann
#: QA configuration (L{_QaConfig})
52 8a96c5a6 Michael Hanselmann
_config = None
53 cec9845c Michael Hanselmann
54 cec9845c Michael Hanselmann
55 6a654276 Michael Hanselmann
class _QaInstance(object):
56 6a654276 Michael Hanselmann
  __slots__ = [
57 6a654276 Michael Hanselmann
    "name",
58 6a654276 Michael Hanselmann
    "nicmac",
59 2176724e Michael Hanselmann
    "_used",
60 02a5fe0e Michael Hanselmann
    "_disk_template",
61 6a654276 Michael Hanselmann
    ]
62 6a654276 Michael Hanselmann
63 6a654276 Michael Hanselmann
  def __init__(self, name, nicmac):
64 6a654276 Michael Hanselmann
    """Initializes instances of this class.
65 6a654276 Michael Hanselmann

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

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

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

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

119 6a654276 Michael Hanselmann
    @type idx: int
120 6a654276 Michael Hanselmann
    @param idx: NIC index
121 6a654276 Michael Hanselmann
    @param default: Default value
122 6a654276 Michael Hanselmann

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

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

141 2176724e Michael Hanselmann
    """
142 2176724e Michael Hanselmann
    return self._used
143 2176724e Michael Hanselmann
144 2176724e Michael Hanselmann
  @property
145 02a5fe0e Michael Hanselmann
  def disk_template(self):
146 02a5fe0e Michael Hanselmann
    """Returns the current disk template.
147 02a5fe0e Michael Hanselmann

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

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

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

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

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

208 dbdb0594 Michael Hanselmann
    """
209 dbdb0594 Michael Hanselmann
    assert not self._added
210 dbdb0594 Michael Hanselmann
    self._added = True
211 dbdb0594 Michael Hanselmann
212 dbdb0594 Michael Hanselmann
  def MarkRemoved(self):
213 dbdb0594 Michael Hanselmann
    """Marks node as having been removed from a cluster.
214 dbdb0594 Michael Hanselmann

215 dbdb0594 Michael Hanselmann
    """
216 dbdb0594 Michael Hanselmann
    assert self._added
217 dbdb0594 Michael Hanselmann
    self._added = False
218 dbdb0594 Michael Hanselmann
219 dbdb0594 Michael Hanselmann
  @property
220 dbdb0594 Michael Hanselmann
  def added(self):
221 dbdb0594 Michael Hanselmann
    """Returns whether a node is part of a cluster.
222 dbdb0594 Michael Hanselmann

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

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

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

255 8a96c5a6 Michael Hanselmann
    """
256 8a96c5a6 Michael Hanselmann
    self._data = data
257 8a96c5a6 Michael Hanselmann
258 a08e181f Michael Hanselmann
    #: Cluster-wide run-time value of the exclusive storage flag
259 a08e181f Michael Hanselmann
    self._exclusive_storage = None
260 a08e181f Michael Hanselmann
261 c8bf5cf4 Hrvoje Ribicic
  @staticmethod
262 c8bf5cf4 Hrvoje Ribicic
  def LoadPatch(patch_dict, rel_path):
263 c8bf5cf4 Hrvoje Ribicic
    """ Loads a single patch.
264 c8bf5cf4 Hrvoje Ribicic

265 c8bf5cf4 Hrvoje Ribicic
    @type patch_dict: dict of string to dict
266 c8bf5cf4 Hrvoje Ribicic
    @param patch_dict: A dictionary storing patches by relative path.
267 c8bf5cf4 Hrvoje Ribicic
    @type rel_path: string
268 c8bf5cf4 Hrvoje Ribicic
    @param rel_path: The relative path to the patch, might or might not exist.
269 c8bf5cf4 Hrvoje Ribicic

270 c8bf5cf4 Hrvoje Ribicic
    """
271 c8bf5cf4 Hrvoje Ribicic
    try:
272 c8bf5cf4 Hrvoje Ribicic
      full_path = os.path.join(_QA_BASE_PATH, rel_path)
273 c8bf5cf4 Hrvoje Ribicic
      patch = serializer.LoadJson(utils.ReadFile(full_path))
274 7488cf4b Hrvoje Ribicic
      patch_dict[rel_path] = patch
275 c8bf5cf4 Hrvoje Ribicic
    except IOError:
276 c8bf5cf4 Hrvoje Ribicic
      pass
277 c8bf5cf4 Hrvoje Ribicic
278 c8bf5cf4 Hrvoje Ribicic
  @staticmethod
279 c8bf5cf4 Hrvoje Ribicic
  def LoadPatches():
280 7488cf4b Hrvoje Ribicic
    """ Finds and loads all patches supported by the QA.
281 c8bf5cf4 Hrvoje Ribicic

282 c8bf5cf4 Hrvoje Ribicic
    @rtype: dict of string to dict
283 7488cf4b Hrvoje Ribicic
    @return: A dictionary of relative path to patch content.
284 c8bf5cf4 Hrvoje Ribicic

285 c8bf5cf4 Hrvoje Ribicic
    """
286 c8bf5cf4 Hrvoje Ribicic
    patches = {}
287 c8bf5cf4 Hrvoje Ribicic
    _QaConfig.LoadPatch(patches, _QA_DEFAULT_PATCH)
288 a60fc78e Hrvoje Ribicic
    patch_dir_path = os.path.join(_QA_BASE_PATH, _QA_PATCH_DIR)
289 a60fc78e Hrvoje Ribicic
    if os.path.exists(patch_dir_path):
290 a60fc78e Hrvoje Ribicic
      for filename in os.listdir(patch_dir_path):
291 a60fc78e Hrvoje Ribicic
        if filename.endswith(".json"):
292 a60fc78e Hrvoje Ribicic
          _QaConfig.LoadPatch(patches, os.path.join(_QA_PATCH_DIR, filename))
293 c8bf5cf4 Hrvoje Ribicic
    return patches
294 c8bf5cf4 Hrvoje Ribicic
295 a60fc78e Hrvoje Ribicic
  @staticmethod
296 7488cf4b Hrvoje Ribicic
  def ApplyPatch(data, patch_module, patches, patch_path):
297 7488cf4b Hrvoje Ribicic
    """Applies a single patch.
298 7488cf4b Hrvoje Ribicic

299 7488cf4b Hrvoje Ribicic
    @type data: dict (deserialized json)
300 7488cf4b Hrvoje Ribicic
    @param data: The QA configuration
301 7488cf4b Hrvoje Ribicic
    @type patch_module: module
302 7488cf4b Hrvoje Ribicic
    @param patch_module: The json patch module, loaded dynamically
303 7488cf4b Hrvoje Ribicic
    @type patches: dict of string to dict
304 7488cf4b Hrvoje Ribicic
    @param patches: The dictionary of patch path to content
305 7488cf4b Hrvoje Ribicic
    @type patch_path: string
306 7488cf4b Hrvoje Ribicic
    @param patch_path: The path to the patch, relative to the QA directory
307 7488cf4b Hrvoje Ribicic

308 7488cf4b Hrvoje Ribicic
    @return: The modified configuration data.
309 7488cf4b Hrvoje Ribicic

310 7488cf4b Hrvoje Ribicic
    """
311 7488cf4b Hrvoje Ribicic
    patch_content = patches[patch_path]
312 7488cf4b Hrvoje Ribicic
    print qa_logging.FormatInfo("Applying patch %s" % patch_path)
313 7488cf4b Hrvoje Ribicic
    if not patch_content and patch_path != _QA_DEFAULT_PATCH:
314 7488cf4b Hrvoje Ribicic
      print qa_logging.FormatWarning("The patch %s added by the user is empty" %
315 7488cf4b Hrvoje Ribicic
                                     patch_path)
316 7488cf4b Hrvoje Ribicic
    data = patch_module.apply_patch(data, patch_content)
317 7488cf4b Hrvoje Ribicic
318 7488cf4b Hrvoje Ribicic
  @staticmethod
319 a60fc78e Hrvoje Ribicic
  def ApplyPatches(data, patch_module, patches):
320 a60fc78e Hrvoje Ribicic
    """Applies any patches present, and returns the modified QA configuration.
321 a60fc78e Hrvoje Ribicic

322 7441bb96 Hrvoje Ribicic
    First, patches from the patch directory are applied. They are ordered
323 7441bb96 Hrvoje Ribicic
    alphabetically, unless there is an ``order`` file present - any patches
324 7441bb96 Hrvoje Ribicic
    listed within are applied in that order, and any remaining ones in
325 7441bb96 Hrvoje Ribicic
    alphabetical order again. Finally, the default patch residing in the
326 7441bb96 Hrvoje Ribicic
    top-level QA directory is applied.
327 a60fc78e Hrvoje Ribicic

328 a60fc78e Hrvoje Ribicic
    @type data: dict (deserialized json)
329 a60fc78e Hrvoje Ribicic
    @param data: The QA configuration
330 a60fc78e Hrvoje Ribicic
    @type patch_module: module
331 a60fc78e Hrvoje Ribicic
    @param patch_module: The json patch module, loaded dynamically
332 a60fc78e Hrvoje Ribicic
    @type patches: dict of string to dict
333 a60fc78e Hrvoje Ribicic
    @param patches: The dictionary of patch path to content
334 a60fc78e Hrvoje Ribicic

335 a60fc78e Hrvoje Ribicic
    @return: The modified configuration data.
336 a60fc78e Hrvoje Ribicic

337 a60fc78e Hrvoje Ribicic
    """
338 7441bb96 Hrvoje Ribicic
    ordered_patches = []
339 7441bb96 Hrvoje Ribicic
    order_path = os.path.join(_QA_BASE_PATH, _QA_PATCH_DIR,
340 7441bb96 Hrvoje Ribicic
                              _QA_PATCH_ORDER_FILE)
341 7441bb96 Hrvoje Ribicic
    if os.path.exists(order_path):
342 7441bb96 Hrvoje Ribicic
      order_file = open(order_path, 'r')
343 7441bb96 Hrvoje Ribicic
      ordered_patches = order_file.read().splitlines()
344 7441bb96 Hrvoje Ribicic
      # Removes empty lines
345 7441bb96 Hrvoje Ribicic
      ordered_patches = filter(None, ordered_patches)
346 7441bb96 Hrvoje Ribicic
347 7441bb96 Hrvoje Ribicic
    # Add the patch dir
348 7441bb96 Hrvoje Ribicic
    ordered_patches = map(lambda x: os.path.join(_QA_PATCH_DIR, x),
349 7441bb96 Hrvoje Ribicic
                          ordered_patches)
350 7441bb96 Hrvoje Ribicic
351 7441bb96 Hrvoje Ribicic
    # First the ordered patches
352 7441bb96 Hrvoje Ribicic
    for patch in ordered_patches:
353 7441bb96 Hrvoje Ribicic
      if patch not in patches:
354 7441bb96 Hrvoje Ribicic
        raise qa_error.Error("Patch %s specified in the ordering file does not "
355 7441bb96 Hrvoje Ribicic
                             "exist" % patch)
356 7488cf4b Hrvoje Ribicic
      _QaConfig.ApplyPatch(data, patch_module, patches, patch)
357 7441bb96 Hrvoje Ribicic
358 7441bb96 Hrvoje Ribicic
    # Then the other non-default ones
359 a60fc78e Hrvoje Ribicic
    for patch in sorted(patches):
360 7441bb96 Hrvoje Ribicic
      if patch != _QA_DEFAULT_PATCH and patch not in ordered_patches:
361 7488cf4b Hrvoje Ribicic
        _QaConfig.ApplyPatch(data, patch_module, patches, patch)
362 a60fc78e Hrvoje Ribicic
363 7441bb96 Hrvoje Ribicic
    # Finally the default one
364 a60fc78e Hrvoje Ribicic
    if _QA_DEFAULT_PATCH in patches:
365 7488cf4b Hrvoje Ribicic
      _QaConfig.ApplyPatch(data, patch_module, patches, _QA_DEFAULT_PATCH)
366 a60fc78e Hrvoje Ribicic
367 a60fc78e Hrvoje Ribicic
    return data
368 a60fc78e Hrvoje Ribicic
369 8a96c5a6 Michael Hanselmann
  @classmethod
370 8a96c5a6 Michael Hanselmann
  def Load(cls, filename):
371 8a96c5a6 Michael Hanselmann
    """Loads a configuration file and produces a configuration object.
372 8a96c5a6 Michael Hanselmann

373 8a96c5a6 Michael Hanselmann
    @type filename: string
374 8a96c5a6 Michael Hanselmann
    @param filename: Path to configuration file
375 8a96c5a6 Michael Hanselmann
    @rtype: L{_QaConfig}
376 8a96c5a6 Michael Hanselmann

377 8a96c5a6 Michael Hanselmann
    """
378 8a96c5a6 Michael Hanselmann
    data = serializer.LoadJson(utils.ReadFile(filename))
379 8a96c5a6 Michael Hanselmann
380 b7630577 Petr Pudlak
    # Patch the document using JSON Patch (RFC6902) in file _PATCH_JSON, if
381 b7630577 Petr Pudlak
    # available
382 b7630577 Petr Pudlak
    try:
383 c8bf5cf4 Hrvoje Ribicic
      patches = _QaConfig.LoadPatches()
384 7488cf4b Hrvoje Ribicic
      # Try to use the module only if there is a non-empty patch present
385 7488cf4b Hrvoje Ribicic
      if any(patches.values()):
386 b7630577 Petr Pudlak
        mod = __import__("jsonpatch", fromlist=[])
387 a60fc78e Hrvoje Ribicic
        data = _QaConfig.ApplyPatches(data, mod, patches)
388 b7630577 Petr Pudlak
    except IOError:
389 b7630577 Petr Pudlak
      pass
390 b7630577 Petr Pudlak
    except ImportError:
391 c8bf5cf4 Hrvoje Ribicic
      raise qa_error.Error("For the QA JSON patching feature to work, you "
392 c8bf5cf4 Hrvoje Ribicic
                           "need to install Python modules 'jsonpatch' and "
393 c8bf5cf4 Hrvoje Ribicic
                           "'jsonpointer'.")
394 b7630577 Petr Pudlak
395 6a654276 Michael Hanselmann
    result = cls(dict(map(_ConvertResources,
396 6a654276 Michael Hanselmann
                          data.items()))) # pylint: disable=E1103
397 8a96c5a6 Michael Hanselmann
    result.Validate()
398 8a96c5a6 Michael Hanselmann
399 8a96c5a6 Michael Hanselmann
    return result
400 8a96c5a6 Michael Hanselmann
401 8a96c5a6 Michael Hanselmann
  def Validate(self):
402 8a96c5a6 Michael Hanselmann
    """Validates loaded configuration data.
403 8a96c5a6 Michael Hanselmann

404 8a96c5a6 Michael Hanselmann
    """
405 47aa6ec9 Michael Hanselmann
    if not self.get("name"):
406 47aa6ec9 Michael Hanselmann
      raise qa_error.Error("Cluster name is required")
407 47aa6ec9 Michael Hanselmann
408 8a96c5a6 Michael Hanselmann
    if not self.get("nodes"):
409 8a96c5a6 Michael Hanselmann
      raise qa_error.Error("Need at least one node")
410 8a96c5a6 Michael Hanselmann
411 8a96c5a6 Michael Hanselmann
    if not self.get("instances"):
412 8a96c5a6 Michael Hanselmann
      raise qa_error.Error("Need at least one instance")
413 8a96c5a6 Michael Hanselmann
414 090128b6 Christos Stavrakakis
    disks = self.GetDiskOptions()
415 090128b6 Christos Stavrakakis
    if disks is None:
416 090128b6 Christos Stavrakakis
      raise qa_error.Error("Config option 'disks' must exist")
417 090128b6 Christos Stavrakakis
    else:
418 090128b6 Christos Stavrakakis
      for d in disks:
419 090128b6 Christos Stavrakakis
        if d.get("size") is None or d.get("growth") is None:
420 090128b6 Christos Stavrakakis
          raise qa_error.Error("Config options `size` and `growth` must exist"
421 090128b6 Christos Stavrakakis
                               " for all `disks` items")
422 8a96c5a6 Michael Hanselmann
    check = self.GetInstanceCheckScript()
423 8a96c5a6 Michael Hanselmann
    if check:
424 8a96c5a6 Michael Hanselmann
      try:
425 8a96c5a6 Michael Hanselmann
        os.stat(check)
426 8a96c5a6 Michael Hanselmann
      except EnvironmentError, err:
427 8a96c5a6 Michael Hanselmann
        raise qa_error.Error("Can't find instance check script '%s': %s" %
428 8a96c5a6 Michael Hanselmann
                             (check, err))
429 8a96c5a6 Michael Hanselmann
430 8a96c5a6 Michael Hanselmann
    enabled_hv = frozenset(self.GetEnabledHypervisors())
431 8a96c5a6 Michael Hanselmann
    if not enabled_hv:
432 8a96c5a6 Michael Hanselmann
      raise qa_error.Error("No hypervisor is enabled")
433 8a96c5a6 Michael Hanselmann
434 8a96c5a6 Michael Hanselmann
    difference = enabled_hv - constants.HYPER_TYPES
435 8a96c5a6 Michael Hanselmann
    if difference:
436 8a96c5a6 Michael Hanselmann
      raise qa_error.Error("Unknown hypervisor(s) enabled: %s" %
437 8a96c5a6 Michael Hanselmann
                           utils.CommaJoin(difference))
438 8a96c5a6 Michael Hanselmann
439 76fda900 Michael Hanselmann
    (vc_master, vc_basedir) = self.GetVclusterSettings()
440 76fda900 Michael Hanselmann
    if bool(vc_master) != bool(vc_basedir):
441 76fda900 Michael Hanselmann
      raise qa_error.Error("All or none of the config options '%s' and '%s'"
442 76fda900 Michael Hanselmann
                           " must be set" %
443 76fda900 Michael Hanselmann
                           (_VCLUSTER_MASTER_KEY, _VCLUSTER_BASEDIR_KEY))
444 76fda900 Michael Hanselmann
445 76fda900 Michael Hanselmann
    if vc_basedir and not utils.IsNormAbsPath(vc_basedir):
446 76fda900 Michael Hanselmann
      raise qa_error.Error("Path given in option '%s' must be absolute and"
447 76fda900 Michael Hanselmann
                           " normalized" % _VCLUSTER_BASEDIR_KEY)
448 76fda900 Michael Hanselmann
449 8a96c5a6 Michael Hanselmann
  def __getitem__(self, name):
450 8a96c5a6 Michael Hanselmann
    """Returns configuration value.
451 8a96c5a6 Michael Hanselmann

452 8a96c5a6 Michael Hanselmann
    @type name: string
453 8a96c5a6 Michael Hanselmann
    @param name: Name of configuration entry
454 8a96c5a6 Michael Hanselmann

455 8a96c5a6 Michael Hanselmann
    """
456 8a96c5a6 Michael Hanselmann
    return self._data[name]
457 8a96c5a6 Michael Hanselmann
458 aac832d2 Michele Tartara
  def __setitem__(self, key, value):
459 aac832d2 Michele Tartara
    """Sets a configuration value.
460 aac832d2 Michele Tartara

461 aac832d2 Michele Tartara
    """
462 aac832d2 Michele Tartara
    self._data[key] = value
463 aac832d2 Michele Tartara
464 aac832d2 Michele Tartara
  def __delitem__(self, key):
465 aac832d2 Michele Tartara
    """Deletes a value from the configuration.
466 aac832d2 Michele Tartara

467 aac832d2 Michele Tartara
    """
468 aac832d2 Michele Tartara
    del(self._data[key])
469 aac832d2 Michele Tartara
470 aac832d2 Michele Tartara
  def __len__(self):
471 aac832d2 Michele Tartara
    """Return the number of configuration items.
472 aac832d2 Michele Tartara

473 aac832d2 Michele Tartara
    """
474 aac832d2 Michele Tartara
    return len(self._data)
475 aac832d2 Michele Tartara
476 8a96c5a6 Michael Hanselmann
  def get(self, name, default=None):
477 8a96c5a6 Michael Hanselmann
    """Returns configuration value.
478 8a96c5a6 Michael Hanselmann

479 8a96c5a6 Michael Hanselmann
    @type name: string
480 8a96c5a6 Michael Hanselmann
    @param name: Name of configuration entry
481 8a96c5a6 Michael Hanselmann
    @param default: Default value
482 8a96c5a6 Michael Hanselmann

483 8a96c5a6 Michael Hanselmann
    """
484 8a96c5a6 Michael Hanselmann
    return self._data.get(name, default)
485 cec9845c Michael Hanselmann
486 8a96c5a6 Michael Hanselmann
  def GetMasterNode(self):
487 8a96c5a6 Michael Hanselmann
    """Returns the default master node for the cluster.
488 cec9845c Michael Hanselmann

489 8a96c5a6 Michael Hanselmann
    """
490 8a96c5a6 Michael Hanselmann
    return self["nodes"][0]
491 8a96c5a6 Michael Hanselmann
492 8a96c5a6 Michael Hanselmann
  def GetInstanceCheckScript(self):
493 8a96c5a6 Michael Hanselmann
    """Returns path to instance check script or C{None}.
494 8a96c5a6 Michael Hanselmann

495 8a96c5a6 Michael Hanselmann
    """
496 8a96c5a6 Michael Hanselmann
    return self._data.get(_INSTANCE_CHECK_KEY, None)
497 cec9845c Michael Hanselmann
498 8a96c5a6 Michael Hanselmann
  def GetEnabledHypervisors(self):
499 8a96c5a6 Michael Hanselmann
    """Returns list of enabled hypervisors.
500 cec9845c Michael Hanselmann

501 8a96c5a6 Michael Hanselmann
    @rtype: list
502 cec9845c Michael Hanselmann

503 8a96c5a6 Michael Hanselmann
    """
504 dacd8ba4 Helga Velroyen
    return self._GetStringListParameter(
505 dacd8ba4 Helga Velroyen
      _ENABLED_HV_KEY,
506 dacd8ba4 Helga Velroyen
      [constants.DEFAULT_ENABLED_HYPERVISOR])
507 dacd8ba4 Helga Velroyen
508 dacd8ba4 Helga Velroyen
  def GetDefaultHypervisor(self):
509 dacd8ba4 Helga Velroyen
    """Returns the default hypervisor to be used.
510 dacd8ba4 Helga Velroyen

511 dacd8ba4 Helga Velroyen
    """
512 dacd8ba4 Helga Velroyen
    return self.GetEnabledHypervisors()[0]
513 dacd8ba4 Helga Velroyen
514 2dae8d64 Helga Velroyen
  def GetEnabledDiskTemplates(self):
515 2dae8d64 Helga Velroyen
    """Returns the list of enabled disk templates.
516 dacd8ba4 Helga Velroyen

517 dacd8ba4 Helga Velroyen
    @rtype: list
518 dacd8ba4 Helga Velroyen

519 dacd8ba4 Helga Velroyen
    """
520 dacd8ba4 Helga Velroyen
    return self._GetStringListParameter(
521 2dae8d64 Helga Velroyen
      _ENABLED_DISK_TEMPLATES_KEY,
522 decf86f9 Helga Velroyen
      constants.DEFAULT_ENABLED_DISK_TEMPLATES)
523 dacd8ba4 Helga Velroyen
524 5949c31c Helga Velroyen
  def GetEnabledStorageTypes(self):
525 5949c31c Helga Velroyen
    """Returns the list of enabled storage types.
526 5949c31c Helga Velroyen

527 5949c31c Helga Velroyen
    @rtype: list
528 5949c31c Helga Velroyen
    @returns: the list of storage types enabled for QA
529 5949c31c Helga Velroyen

530 5949c31c Helga Velroyen
    """
531 5949c31c Helga Velroyen
    enabled_disk_templates = self.GetEnabledDiskTemplates()
532 615551b2 Helga Velroyen
    enabled_storage_types = list(
533 615551b2 Helga Velroyen
        set([constants.MAP_DISK_TEMPLATE_STORAGE_TYPE[dt]
534 615551b2 Helga Velroyen
             for dt in enabled_disk_templates]))
535 5949c31c Helga Velroyen
    # Storage type 'lvm-pv' cannot be activated via a disk template,
536 5949c31c Helga Velroyen
    # therefore we add it if 'lvm-vg' is present.
537 5949c31c Helga Velroyen
    if constants.ST_LVM_VG in enabled_storage_types:
538 5949c31c Helga Velroyen
      enabled_storage_types.append(constants.ST_LVM_PV)
539 5949c31c Helga Velroyen
    return enabled_storage_types
540 5949c31c Helga Velroyen
541 2dae8d64 Helga Velroyen
  def GetDefaultDiskTemplate(self):
542 2dae8d64 Helga Velroyen
    """Returns the default disk template to be used.
543 dacd8ba4 Helga Velroyen

544 dacd8ba4 Helga Velroyen
    """
545 2dae8d64 Helga Velroyen
    return self.GetEnabledDiskTemplates()[0]
546 dacd8ba4 Helga Velroyen
547 dacd8ba4 Helga Velroyen
  def _GetStringListParameter(self, key, default_values):
548 dacd8ba4 Helga Velroyen
    """Retrieves a parameter's value that is supposed to be a list of strings.
549 dacd8ba4 Helga Velroyen

550 dacd8ba4 Helga Velroyen
    @rtype: list
551 dacd8ba4 Helga Velroyen

552 dacd8ba4 Helga Velroyen
    """
553 c9e05005 Michael Hanselmann
    try:
554 dacd8ba4 Helga Velroyen
      value = self._data[key]
555 8a96c5a6 Michael Hanselmann
    except KeyError:
556 dacd8ba4 Helga Velroyen
      return default_values
557 8a96c5a6 Michael Hanselmann
    else:
558 8a96c5a6 Michael Hanselmann
      if value is None:
559 8a96c5a6 Michael Hanselmann
        return []
560 8a96c5a6 Michael Hanselmann
      elif isinstance(value, basestring):
561 8a96c5a6 Michael Hanselmann
        return value.split(",")
562 8a96c5a6 Michael Hanselmann
      else:
563 8a96c5a6 Michael Hanselmann
        return value
564 8a96c5a6 Michael Hanselmann
565 a08e181f Michael Hanselmann
  def SetExclusiveStorage(self, value):
566 a08e181f Michael Hanselmann
    """Set the expected value of the C{exclusive_storage} flag for the cluster.
567 a08e181f Michael Hanselmann

568 a08e181f Michael Hanselmann
    """
569 a08e181f Michael Hanselmann
    self._exclusive_storage = bool(value)
570 a08e181f Michael Hanselmann
571 a08e181f Michael Hanselmann
  def GetExclusiveStorage(self):
572 a08e181f Michael Hanselmann
    """Get the expected value of the C{exclusive_storage} flag for the cluster.
573 a08e181f Michael Hanselmann

574 a08e181f Michael Hanselmann
    """
575 a08e181f Michael Hanselmann
    value = self._exclusive_storage
576 a08e181f Michael Hanselmann
    assert value is not None
577 a08e181f Michael Hanselmann
    return value
578 a08e181f Michael Hanselmann
579 a08e181f Michael Hanselmann
  def IsTemplateSupported(self, templ):
580 a08e181f Michael Hanselmann
    """Is the given disk template supported by the current configuration?
581 a08e181f Michael Hanselmann

582 a08e181f Michael Hanselmann
    """
583 02cff8aa Bernardo Dal Seno
    enabled = templ in self.GetEnabledDiskTemplates()
584 02cff8aa Bernardo Dal Seno
    return enabled and (not self.GetExclusiveStorage() or
585 02cff8aa Bernardo Dal Seno
                        templ in constants.DTS_EXCL_STORAGE)
586 a08e181f Michael Hanselmann
587 bab4f56a Helga Velroyen
  def IsStorageTypeSupported(self, storage_type):
588 bab4f56a Helga Velroyen
    """Is the given storage type supported by the current configuration?
589 bab4f56a Helga Velroyen

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

593 bab4f56a Helga Velroyen
    """
594 bab4f56a Helga Velroyen
    enabled_disk_templates = self.GetEnabledDiskTemplates()
595 bab4f56a Helga Velroyen
    if storage_type == constants.ST_LVM_PV:
596 bab4f56a Helga Velroyen
      disk_templates = utils.GetDiskTemplatesOfStorageType(constants.ST_LVM_VG)
597 bab4f56a Helga Velroyen
    else:
598 bab4f56a Helga Velroyen
      disk_templates = utils.GetDiskTemplatesOfStorageType(storage_type)
599 bab4f56a Helga Velroyen
    return bool(set(enabled_disk_templates).intersection(set(disk_templates)))
600 bab4f56a Helga Velroyen
601 345d395d Bernardo Dal Seno
  def AreSpindlesSupported(self):
602 345d395d Bernardo Dal Seno
    """Are spindles supported by the current configuration?
603 345d395d Bernardo Dal Seno

604 345d395d Bernardo Dal Seno
    """
605 345d395d Bernardo Dal Seno
    return self.GetExclusiveStorage()
606 345d395d Bernardo Dal Seno
607 76fda900 Michael Hanselmann
  def GetVclusterSettings(self):
608 76fda900 Michael Hanselmann
    """Returns settings for virtual cluster.
609 76fda900 Michael Hanselmann

610 76fda900 Michael Hanselmann
    """
611 76fda900 Michael Hanselmann
    master = self.get(_VCLUSTER_MASTER_KEY)
612 76fda900 Michael Hanselmann
    basedir = self.get(_VCLUSTER_BASEDIR_KEY)
613 76fda900 Michael Hanselmann
614 76fda900 Michael Hanselmann
    return (master, basedir)
615 76fda900 Michael Hanselmann
616 090128b6 Christos Stavrakakis
  def GetDiskOptions(self):
617 090128b6 Christos Stavrakakis
    """Return options for the disks of the instances.
618 090128b6 Christos Stavrakakis

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

622 090128b6 Christos Stavrakakis
    """
623 090128b6 Christos Stavrakakis
    try:
624 090128b6 Christos Stavrakakis
      return self._data["disks"]
625 090128b6 Christos Stavrakakis
    except KeyError:
626 090128b6 Christos Stavrakakis
      pass
627 090128b6 Christos Stavrakakis
628 090128b6 Christos Stavrakakis
    # Legacy interface
629 090128b6 Christos Stavrakakis
    sizes = self._data.get("disk")
630 090128b6 Christos Stavrakakis
    growths = self._data.get("disk-growth")
631 090128b6 Christos Stavrakakis
    if sizes or growths:
632 090128b6 Christos Stavrakakis
      if (sizes is None or growths is None or len(sizes) != len(growths)):
633 090128b6 Christos Stavrakakis
        raise qa_error.Error("Config options 'disk' and 'disk-growth' must"
634 090128b6 Christos Stavrakakis
                             " exist and have the same number of items")
635 090128b6 Christos Stavrakakis
      disks = []
636 090128b6 Christos Stavrakakis
      for (size, growth) in zip(sizes, growths):
637 090128b6 Christos Stavrakakis
        disks.append({"size": size, "growth": growth})
638 090128b6 Christos Stavrakakis
      return disks
639 090128b6 Christos Stavrakakis
    else:
640 090128b6 Christos Stavrakakis
      return None
641 090128b6 Christos Stavrakakis
642 8a96c5a6 Michael Hanselmann
643 8a96c5a6 Michael Hanselmann
def Load(path):
644 8a96c5a6 Michael Hanselmann
  """Loads the passed configuration file.
645 8a96c5a6 Michael Hanselmann

646 8a96c5a6 Michael Hanselmann
  """
647 8a96c5a6 Michael Hanselmann
  global _config # pylint: disable=W0603
648 8a96c5a6 Michael Hanselmann
649 8a96c5a6 Michael Hanselmann
  _config = _QaConfig.Load(path)
650 c9e05005 Michael Hanselmann
651 e7b6183b Michael Hanselmann
652 8a96c5a6 Michael Hanselmann
def GetConfig():
653 8a96c5a6 Michael Hanselmann
  """Returns the configuration object.
654 8a96c5a6 Michael Hanselmann

655 8a96c5a6 Michael Hanselmann
  """
656 8a96c5a6 Michael Hanselmann
  if _config is None:
657 8a96c5a6 Michael Hanselmann
    raise RuntimeError("Configuration not yet loaded")
658 8a96c5a6 Michael Hanselmann
659 8a96c5a6 Michael Hanselmann
  return _config
660 e7b6183b Michael Hanselmann
661 cec9845c Michael Hanselmann
662 cec9845c Michael Hanselmann
def get(name, default=None):
663 8a96c5a6 Michael Hanselmann
  """Wrapper for L{_QaConfig.get}.
664 8a96c5a6 Michael Hanselmann

665 8a96c5a6 Michael Hanselmann
  """
666 8a96c5a6 Michael Hanselmann
  return GetConfig().get(name, default=default)
667 cec9845c Michael Hanselmann
668 cec9845c Michael Hanselmann
669 a0c3e726 Michael Hanselmann
class Either:
670 a0c3e726 Michael Hanselmann
  def __init__(self, tests):
671 a0c3e726 Michael Hanselmann
    """Initializes this class.
672 a0c3e726 Michael Hanselmann

673 a0c3e726 Michael Hanselmann
    @type tests: list or string
674 a0c3e726 Michael Hanselmann
    @param tests: List of test names
675 a0c3e726 Michael Hanselmann
    @see: L{TestEnabled} for details
676 a0c3e726 Michael Hanselmann

677 a0c3e726 Michael Hanselmann
    """
678 a0c3e726 Michael Hanselmann
    self.tests = tests
679 a0c3e726 Michael Hanselmann
680 a0c3e726 Michael Hanselmann
681 a0c3e726 Michael Hanselmann
def _MakeSequence(value):
682 a0c3e726 Michael Hanselmann
  """Make sequence of single argument.
683 a0c3e726 Michael Hanselmann

684 a0c3e726 Michael Hanselmann
  If the single argument is not already a list or tuple, a list with the
685 a0c3e726 Michael Hanselmann
  argument as a single item is returned.
686 a0c3e726 Michael Hanselmann

687 a0c3e726 Michael Hanselmann
  """
688 a0c3e726 Michael Hanselmann
  if isinstance(value, (list, tuple)):
689 a0c3e726 Michael Hanselmann
    return value
690 a0c3e726 Michael Hanselmann
  else:
691 a0c3e726 Michael Hanselmann
    return [value]
692 a0c3e726 Michael Hanselmann
693 a0c3e726 Michael Hanselmann
694 a0c3e726 Michael Hanselmann
def _TestEnabledInner(check_fn, names, fn):
695 a0c3e726 Michael Hanselmann
  """Evaluate test conditions.
696 a0c3e726 Michael Hanselmann

697 a0c3e726 Michael Hanselmann
  @type check_fn: callable
698 a0c3e726 Michael Hanselmann
  @param check_fn: Callback to check whether a test is enabled
699 a0c3e726 Michael Hanselmann
  @type names: sequence or string
700 a0c3e726 Michael Hanselmann
  @param names: Test name(s)
701 a0c3e726 Michael Hanselmann
  @type fn: callable
702 a0c3e726 Michael Hanselmann
  @param fn: Aggregation function
703 a0c3e726 Michael Hanselmann
  @rtype: bool
704 a0c3e726 Michael Hanselmann
  @return: Whether test is enabled
705 a0c3e726 Michael Hanselmann

706 a0c3e726 Michael Hanselmann
  """
707 a0c3e726 Michael Hanselmann
  names = _MakeSequence(names)
708 a0c3e726 Michael Hanselmann
709 a0c3e726 Michael Hanselmann
  result = []
710 a0c3e726 Michael Hanselmann
711 a0c3e726 Michael Hanselmann
  for name in names:
712 a0c3e726 Michael Hanselmann
    if isinstance(name, Either):
713 a0c3e726 Michael Hanselmann
      value = _TestEnabledInner(check_fn, name.tests, compat.any)
714 a0c3e726 Michael Hanselmann
    elif isinstance(name, (list, tuple)):
715 a0c3e726 Michael Hanselmann
      value = _TestEnabledInner(check_fn, name, compat.all)
716 c072e788 Michael Hanselmann
    elif callable(name):
717 c072e788 Michael Hanselmann
      value = name()
718 a0c3e726 Michael Hanselmann
    else:
719 a0c3e726 Michael Hanselmann
      value = check_fn(name)
720 a0c3e726 Michael Hanselmann
721 a0c3e726 Michael Hanselmann
    result.append(value)
722 a0c3e726 Michael Hanselmann
723 a0c3e726 Michael Hanselmann
  return fn(result)
724 a0c3e726 Michael Hanselmann
725 a0c3e726 Michael Hanselmann
726 a0c3e726 Michael Hanselmann
def TestEnabled(tests, _cfg=None):
727 7d88f255 Iustin Pop
  """Returns True if the given tests are enabled.
728 7d88f255 Iustin Pop

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

732 1010ec70 Michael Hanselmann
  """
733 a0c3e726 Michael Hanselmann
  if _cfg is None:
734 8a96c5a6 Michael Hanselmann
    cfg = GetConfig()
735 8a96c5a6 Michael Hanselmann
  else:
736 8a96c5a6 Michael Hanselmann
    cfg = _cfg
737 59a8fe48 Michael Hanselmann
738 59a8fe48 Michael Hanselmann
  # Get settings for all tests
739 8a96c5a6 Michael Hanselmann
  cfg_tests = cfg.get("tests", {})
740 59a8fe48 Michael Hanselmann
741 59a8fe48 Michael Hanselmann
  # Get default setting
742 a0c3e726 Michael Hanselmann
  default = cfg_tests.get("default", True)
743 59a8fe48 Michael Hanselmann
744 a0c3e726 Michael Hanselmann
  return _TestEnabledInner(lambda name: cfg_tests.get(name, default),
745 a0c3e726 Michael Hanselmann
                           tests, compat.all)
746 cec9845c Michael Hanselmann
747 cec9845c Michael Hanselmann
748 8a96c5a6 Michael Hanselmann
def GetInstanceCheckScript(*args):
749 8a96c5a6 Michael Hanselmann
  """Wrapper for L{_QaConfig.GetInstanceCheckScript}.
750 c9e05005 Michael Hanselmann

751 c9e05005 Michael Hanselmann
  """
752 8a96c5a6 Michael Hanselmann
  return GetConfig().GetInstanceCheckScript(*args)
753 c9e05005 Michael Hanselmann
754 e7b6183b Michael Hanselmann
755 8a96c5a6 Michael Hanselmann
def GetEnabledHypervisors(*args):
756 8a96c5a6 Michael Hanselmann
  """Wrapper for L{_QaConfig.GetEnabledHypervisors}.
757 e7b6183b Michael Hanselmann

758 e7b6183b Michael Hanselmann
  """
759 8a96c5a6 Michael Hanselmann
  return GetConfig().GetEnabledHypervisors(*args)
760 e7b6183b Michael Hanselmann
761 e7b6183b Michael Hanselmann
762 8a96c5a6 Michael Hanselmann
def GetDefaultHypervisor(*args):
763 8a96c5a6 Michael Hanselmann
  """Wrapper for L{_QaConfig.GetDefaultHypervisor}.
764 e7b6183b Michael Hanselmann

765 e7b6183b Michael Hanselmann
  """
766 8a96c5a6 Michael Hanselmann
  return GetConfig().GetDefaultHypervisor(*args)
767 dacd8ba4 Helga Velroyen
768 dacd8ba4 Helga Velroyen
769 2dae8d64 Helga Velroyen
def GetEnabledDiskTemplates(*args):
770 2dae8d64 Helga Velroyen
  """Wrapper for L{_QaConfig.GetEnabledDiskTemplates}.
771 dacd8ba4 Helga Velroyen

772 dacd8ba4 Helga Velroyen
  """
773 2dae8d64 Helga Velroyen
  return GetConfig().GetEnabledDiskTemplates(*args)
774 dacd8ba4 Helga Velroyen
775 dacd8ba4 Helga Velroyen
776 5949c31c Helga Velroyen
def GetEnabledStorageTypes(*args):
777 5949c31c Helga Velroyen
  """Wrapper for L{_QaConfig.GetEnabledStorageTypes}.
778 5949c31c Helga Velroyen

779 5949c31c Helga Velroyen
  """
780 5949c31c Helga Velroyen
  return GetConfig().GetEnabledStorageTypes(*args)
781 5949c31c Helga Velroyen
782 5949c31c Helga Velroyen
783 2dae8d64 Helga Velroyen
def GetDefaultDiskTemplate(*args):
784 2dae8d64 Helga Velroyen
  """Wrapper for L{_QaConfig.GetDefaultDiskTemplate}.
785 dacd8ba4 Helga Velroyen

786 dacd8ba4 Helga Velroyen
  """
787 2dae8d64 Helga Velroyen
  return GetConfig().GetDefaultDiskTemplate(*args)
788 e7b6183b Michael Hanselmann
789 e7b6183b Michael Hanselmann
790 cec9845c Michael Hanselmann
def GetMasterNode():
791 8a96c5a6 Michael Hanselmann
  """Wrapper for L{_QaConfig.GetMasterNode}.
792 8a96c5a6 Michael Hanselmann

793 8a96c5a6 Michael Hanselmann
  """
794 8a96c5a6 Michael Hanselmann
  return GetConfig().GetMasterNode()
795 cec9845c Michael Hanselmann
796 cec9845c Michael Hanselmann
797 6a654276 Michael Hanselmann
def AcquireInstance(_cfg=None):
798 cec9845c Michael Hanselmann
  """Returns an instance which isn't in use.
799 cec9845c Michael Hanselmann

800 cec9845c Michael Hanselmann
  """
801 6a654276 Michael Hanselmann
  if _cfg is None:
802 6a654276 Michael Hanselmann
    cfg = GetConfig()
803 6a654276 Michael Hanselmann
  else:
804 6a654276 Michael Hanselmann
    cfg = _cfg
805 6a654276 Michael Hanselmann
806 cec9845c Michael Hanselmann
  # Filter out unwanted instances
807 6a654276 Michael Hanselmann
  instances = filter(lambda inst: not inst.used, cfg["instances"])
808 cec9845c Michael Hanselmann
809 6a654276 Michael Hanselmann
  if not instances:
810 cec9845c Michael Hanselmann
    raise qa_error.OutOfInstancesError("No instances left")
811 cec9845c Michael Hanselmann
812 2176724e Michael Hanselmann
  instance = instances[0]
813 2176724e Michael Hanselmann
  instance.Use()
814 6a654276 Michael Hanselmann
815 2176724e Michael Hanselmann
  return instance
816 cec9845c Michael Hanselmann
817 cec9845c Michael Hanselmann
818 6a0f22e1 Bernardo Dal Seno
def SetExclusiveStorage(value):
819 a08e181f Michael Hanselmann
  """Wrapper for L{_QaConfig.SetExclusiveStorage}.
820 6a0f22e1 Bernardo Dal Seno

821 6a0f22e1 Bernardo Dal Seno
  """
822 a08e181f Michael Hanselmann
  return GetConfig().SetExclusiveStorage(value)
823 6a0f22e1 Bernardo Dal Seno
824 6a0f22e1 Bernardo Dal Seno
825 6a0f22e1 Bernardo Dal Seno
def GetExclusiveStorage():
826 a08e181f Michael Hanselmann
  """Wrapper for L{_QaConfig.GetExclusiveStorage}.
827 6a0f22e1 Bernardo Dal Seno

828 6a0f22e1 Bernardo Dal Seno
  """
829 a08e181f Michael Hanselmann
  return GetConfig().GetExclusiveStorage()
830 6a0f22e1 Bernardo Dal Seno
831 6a0f22e1 Bernardo Dal Seno
832 27eba428 Bernardo Dal Seno
def IsTemplateSupported(templ):
833 02cff8aa Bernardo Dal Seno
  """Wrapper for L{_QaConfig.IsTemplateSupported}.
834 27eba428 Bernardo Dal Seno

835 27eba428 Bernardo Dal Seno
  """
836 a08e181f Michael Hanselmann
  return GetConfig().IsTemplateSupported(templ)
837 27eba428 Bernardo Dal Seno
838 27eba428 Bernardo Dal Seno
839 bab4f56a Helga Velroyen
def IsStorageTypeSupported(storage_type):
840 bab4f56a Helga Velroyen
  """Wrapper for L{_QaConfig.IsTemplateSupported}.
841 bab4f56a Helga Velroyen

842 bab4f56a Helga Velroyen
  """
843 bab4f56a Helga Velroyen
  return GetConfig().IsStorageTypeSupported(storage_type)
844 bab4f56a Helga Velroyen
845 bab4f56a Helga Velroyen
846 345d395d Bernardo Dal Seno
def AreSpindlesSupported():
847 345d395d Bernardo Dal Seno
  """Wrapper for L{_QaConfig.AreSpindlesSupported}.
848 345d395d Bernardo Dal Seno

849 345d395d Bernardo Dal Seno
  """
850 345d395d Bernardo Dal Seno
  return GetConfig().AreSpindlesSupported()
851 345d395d Bernardo Dal Seno
852 345d395d Bernardo Dal Seno
853 41be279f Michael Hanselmann
def _NodeSortKey(node):
854 41be279f Michael Hanselmann
  """Returns sort key for a node.
855 41be279f Michael Hanselmann

856 41be279f Michael Hanselmann
  @type node: L{_QaNode}
857 41be279f Michael Hanselmann

858 41be279f Michael Hanselmann
  """
859 41be279f Michael Hanselmann
  return (node.use_count, utils.NiceSortKey(node.primary))
860 41be279f Michael Hanselmann
861 41be279f Michael Hanselmann
862 dbdb0594 Michael Hanselmann
def AcquireNode(exclude=None, _cfg=None):
863 cec9845c Michael Hanselmann
  """Returns the least used node.
864 cec9845c Michael Hanselmann

865 cec9845c Michael Hanselmann
  """
866 dbdb0594 Michael Hanselmann
  if _cfg is None:
867 dbdb0594 Michael Hanselmann
    cfg = GetConfig()
868 dbdb0594 Michael Hanselmann
  else:
869 dbdb0594 Michael Hanselmann
    cfg = _cfg
870 dbdb0594 Michael Hanselmann
871 dbdb0594 Michael Hanselmann
  master = cfg.GetMasterNode()
872 cec9845c Michael Hanselmann
873 cec9845c Michael Hanselmann
  # Filter out unwanted nodes
874 cec9845c Michael Hanselmann
  # TODO: Maybe combine filters
875 cec9845c Michael Hanselmann
  if exclude is None:
876 d0c8c01d Iustin Pop
    nodes = cfg["nodes"][:]
877 4b62db14 Michael Hanselmann
  elif isinstance(exclude, (list, tuple)):
878 d0c8c01d Iustin Pop
    nodes = filter(lambda node: node not in exclude, cfg["nodes"])
879 cec9845c Michael Hanselmann
  else:
880 d0c8c01d Iustin Pop
    nodes = filter(lambda node: node != exclude, cfg["nodes"])
881 cec9845c Michael Hanselmann
882 dbdb0594 Michael Hanselmann
  nodes = filter(lambda node: node.added or node == master, nodes)
883 cec9845c Michael Hanselmann
884 dbdb0594 Michael Hanselmann
  if not nodes:
885 cec9845c Michael Hanselmann
    raise qa_error.OutOfNodesError("No nodes left")
886 cec9845c Michael Hanselmann
887 41be279f Michael Hanselmann
  # Return node with least number of uses
888 41be279f Michael Hanselmann
  return sorted(nodes, key=_NodeSortKey)[0].Use()
889 cec9845c Michael Hanselmann
890 cec9845c Michael Hanselmann
891 7d4f1b45 Bernardo Dal Seno
def AcquireManyNodes(num, exclude=None):
892 7d4f1b45 Bernardo Dal Seno
  """Return the least used nodes.
893 7d4f1b45 Bernardo Dal Seno

894 7d4f1b45 Bernardo Dal Seno
  @type num: int
895 7d4f1b45 Bernardo Dal Seno
  @param num: Number of nodes; can be 0.
896 7d4f1b45 Bernardo Dal Seno
  @type exclude: list of nodes or C{None}
897 7d4f1b45 Bernardo Dal Seno
  @param exclude: nodes to be excluded from the choice
898 7d4f1b45 Bernardo Dal Seno
  @rtype: list of nodes
899 7d4f1b45 Bernardo Dal Seno
  @return: C{num} different nodes
900 7d4f1b45 Bernardo Dal Seno

901 7d4f1b45 Bernardo Dal Seno
  """
902 7d4f1b45 Bernardo Dal Seno
  nodes = []
903 7d4f1b45 Bernardo Dal Seno
  if exclude is None:
904 7d4f1b45 Bernardo Dal Seno
    exclude = []
905 7d4f1b45 Bernardo Dal Seno
  elif isinstance(exclude, (list, tuple)):
906 7d4f1b45 Bernardo Dal Seno
    # Don't modify the incoming argument
907 7d4f1b45 Bernardo Dal Seno
    exclude = list(exclude)
908 7d4f1b45 Bernardo Dal Seno
  else:
909 7d4f1b45 Bernardo Dal Seno
    exclude = [exclude]
910 7d4f1b45 Bernardo Dal Seno
911 7d4f1b45 Bernardo Dal Seno
  try:
912 7d4f1b45 Bernardo Dal Seno
    for _ in range(0, num):
913 7d4f1b45 Bernardo Dal Seno
      n = AcquireNode(exclude=exclude)
914 7d4f1b45 Bernardo Dal Seno
      nodes.append(n)
915 7d4f1b45 Bernardo Dal Seno
      exclude.append(n)
916 7d4f1b45 Bernardo Dal Seno
  except qa_error.OutOfNodesError:
917 7d4f1b45 Bernardo Dal Seno
    ReleaseManyNodes(nodes)
918 7d4f1b45 Bernardo Dal Seno
    raise
919 7d4f1b45 Bernardo Dal Seno
  return nodes
920 7d4f1b45 Bernardo Dal Seno
921 7d4f1b45 Bernardo Dal Seno
922 7d4f1b45 Bernardo Dal Seno
def ReleaseManyNodes(nodes):
923 565cb4bf Michael Hanselmann
  for node in nodes:
924 565cb4bf Michael Hanselmann
    node.Release()
925 76fda900 Michael Hanselmann
926 76fda900 Michael Hanselmann
927 76fda900 Michael Hanselmann
def GetVclusterSettings():
928 76fda900 Michael Hanselmann
  """Wrapper for L{_QaConfig.GetVclusterSettings}.
929 76fda900 Michael Hanselmann

930 76fda900 Michael Hanselmann
  """
931 76fda900 Michael Hanselmann
  return GetConfig().GetVclusterSettings()
932 76fda900 Michael Hanselmann
933 76fda900 Michael Hanselmann
934 76fda900 Michael Hanselmann
def UseVirtualCluster(_cfg=None):
935 76fda900 Michael Hanselmann
  """Returns whether a virtual cluster is used.
936 76fda900 Michael Hanselmann

937 76fda900 Michael Hanselmann
  @rtype: bool
938 76fda900 Michael Hanselmann

939 76fda900 Michael Hanselmann
  """
940 76fda900 Michael Hanselmann
  if _cfg is None:
941 76fda900 Michael Hanselmann
    cfg = GetConfig()
942 76fda900 Michael Hanselmann
  else:
943 76fda900 Michael Hanselmann
    cfg = _cfg
944 76fda900 Michael Hanselmann
945 76fda900 Michael Hanselmann
  (master, _) = cfg.GetVclusterSettings()
946 76fda900 Michael Hanselmann
947 76fda900 Michael Hanselmann
  return bool(master)
948 76fda900 Michael Hanselmann
949 76fda900 Michael Hanselmann
950 76fda900 Michael Hanselmann
@ht.WithDesc("No virtual cluster")
951 76fda900 Michael Hanselmann
def NoVirtualCluster():
952 76fda900 Michael Hanselmann
  """Used to disable tests for virtual clusters.
953 76fda900 Michael Hanselmann

954 76fda900 Michael Hanselmann
  """
955 76fda900 Michael Hanselmann
  return not UseVirtualCluster()
956 090128b6 Christos Stavrakakis
957 090128b6 Christos Stavrakakis
958 090128b6 Christos Stavrakakis
def GetDiskOptions():
959 090128b6 Christos Stavrakakis
  """Wrapper for L{_QaConfig.GetDiskOptions}.
960 090128b6 Christos Stavrakakis

961 090128b6 Christos Stavrakakis
  """
962 090128b6 Christos Stavrakakis
  return GetConfig().GetDiskOptions()