Statistics
| Branch: | Tag: | Revision:

root / qa / qa_config.py @ f9329a6c

History | View | Annotate | Download (7.8 kB)

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

24 cec9845c Michael Hanselmann
"""
25 cec9845c Michael Hanselmann
26 c9e05005 Michael Hanselmann
import os
27 cec9845c Michael Hanselmann
28 e7b6183b Michael Hanselmann
from ganeti import constants
29 a705dc05 Michael Hanselmann
from ganeti import utils
30 a705dc05 Michael Hanselmann
from ganeti import serializer
31 7d88f255 Iustin Pop
from ganeti import compat
32 cec9845c Michael Hanselmann
33 cec9845c Michael Hanselmann
import qa_error
34 cec9845c Michael Hanselmann
35 cec9845c Michael Hanselmann
36 c9e05005 Michael Hanselmann
_INSTANCE_CHECK_KEY = "instance-check"
37 e7b6183b Michael Hanselmann
_ENABLED_HV_KEY = "enabled-hypervisors"
38 f9329a6c Michael Hanselmann
39 f9329a6c Michael Hanselmann
#: Cluster-wide run-time value of the exclusive storage flag
40 f9329a6c Michael Hanselmann
_exclusive_storage = None
41 c9e05005 Michael Hanselmann
42 c9e05005 Michael Hanselmann
43 cf632f3e Bernardo Dal Seno
cfg = {}
44 cec9845c Michael Hanselmann
45 cec9845c Michael Hanselmann
46 cec9845c Michael Hanselmann
def Load(path):
47 cec9845c Michael Hanselmann
  """Loads the passed configuration file.
48 cec9845c Michael Hanselmann

49 cec9845c Michael Hanselmann
  """
50 b459a848 Andrea Spadaccini
  global cfg # pylint: disable=W0603
51 cec9845c Michael Hanselmann
52 a705dc05 Michael Hanselmann
  cfg = serializer.LoadJson(utils.ReadFile(path))
53 cec9845c Michael Hanselmann
54 cec9845c Michael Hanselmann
  Validate()
55 cec9845c Michael Hanselmann
56 cec9845c Michael Hanselmann
57 cec9845c Michael Hanselmann
def Validate():
58 d0c8c01d Iustin Pop
  if len(cfg["nodes"]) < 1:
59 cec9845c Michael Hanselmann
    raise qa_error.Error("Need at least one node")
60 d0c8c01d Iustin Pop
  if len(cfg["instances"]) < 1:
61 cec9845c Michael Hanselmann
    raise qa_error.Error("Need at least one instance")
62 1d693311 Michael Hanselmann
  if len(cfg["disk"]) != len(cfg["disk-growth"]):
63 1d693311 Michael Hanselmann
    raise qa_error.Error("Config options 'disk' and 'disk-growth' must have"
64 1d693311 Michael Hanselmann
                         " the same number of items")
65 cec9845c Michael Hanselmann
66 c9e05005 Michael Hanselmann
  check = GetInstanceCheckScript()
67 c9e05005 Michael Hanselmann
  if check:
68 c9e05005 Michael Hanselmann
    try:
69 c9e05005 Michael Hanselmann
      os.stat(check)
70 c9e05005 Michael Hanselmann
    except EnvironmentError, err:
71 c9e05005 Michael Hanselmann
      raise qa_error.Error("Can't find instance check script '%s': %s" %
72 c9e05005 Michael Hanselmann
                           (check, err))
73 c9e05005 Michael Hanselmann
74 e7b6183b Michael Hanselmann
  enabled_hv = frozenset(GetEnabledHypervisors())
75 e7b6183b Michael Hanselmann
  if not enabled_hv:
76 e7b6183b Michael Hanselmann
    raise qa_error.Error("No hypervisor is enabled")
77 e7b6183b Michael Hanselmann
78 e7b6183b Michael Hanselmann
  difference = enabled_hv - constants.HYPER_TYPES
79 e7b6183b Michael Hanselmann
  if difference:
80 e7b6183b Michael Hanselmann
    raise qa_error.Error("Unknown hypervisor(s) enabled: %s" %
81 e7b6183b Michael Hanselmann
                         utils.CommaJoin(difference))
82 e7b6183b Michael Hanselmann
83 cec9845c Michael Hanselmann
84 cec9845c Michael Hanselmann
def get(name, default=None):
85 cf632f3e Bernardo Dal Seno
  return cfg.get(name, default)
86 cec9845c Michael Hanselmann
87 cec9845c Michael Hanselmann
88 a0c3e726 Michael Hanselmann
class Either:
89 a0c3e726 Michael Hanselmann
  def __init__(self, tests):
90 a0c3e726 Michael Hanselmann
    """Initializes this class.
91 a0c3e726 Michael Hanselmann

92 a0c3e726 Michael Hanselmann
    @type tests: list or string
93 a0c3e726 Michael Hanselmann
    @param tests: List of test names
94 a0c3e726 Michael Hanselmann
    @see: L{TestEnabled} for details
95 a0c3e726 Michael Hanselmann

96 a0c3e726 Michael Hanselmann
    """
97 a0c3e726 Michael Hanselmann
    self.tests = tests
98 a0c3e726 Michael Hanselmann
99 a0c3e726 Michael Hanselmann
100 a0c3e726 Michael Hanselmann
def _MakeSequence(value):
101 a0c3e726 Michael Hanselmann
  """Make sequence of single argument.
102 a0c3e726 Michael Hanselmann

103 a0c3e726 Michael Hanselmann
  If the single argument is not already a list or tuple, a list with the
104 a0c3e726 Michael Hanselmann
  argument as a single item is returned.
105 a0c3e726 Michael Hanselmann

106 a0c3e726 Michael Hanselmann
  """
107 a0c3e726 Michael Hanselmann
  if isinstance(value, (list, tuple)):
108 a0c3e726 Michael Hanselmann
    return value
109 a0c3e726 Michael Hanselmann
  else:
110 a0c3e726 Michael Hanselmann
    return [value]
111 a0c3e726 Michael Hanselmann
112 a0c3e726 Michael Hanselmann
113 a0c3e726 Michael Hanselmann
def _TestEnabledInner(check_fn, names, fn):
114 a0c3e726 Michael Hanselmann
  """Evaluate test conditions.
115 a0c3e726 Michael Hanselmann

116 a0c3e726 Michael Hanselmann
  @type check_fn: callable
117 a0c3e726 Michael Hanselmann
  @param check_fn: Callback to check whether a test is enabled
118 a0c3e726 Michael Hanselmann
  @type names: sequence or string
119 a0c3e726 Michael Hanselmann
  @param names: Test name(s)
120 a0c3e726 Michael Hanselmann
  @type fn: callable
121 a0c3e726 Michael Hanselmann
  @param fn: Aggregation function
122 a0c3e726 Michael Hanselmann
  @rtype: bool
123 a0c3e726 Michael Hanselmann
  @return: Whether test is enabled
124 a0c3e726 Michael Hanselmann

125 a0c3e726 Michael Hanselmann
  """
126 a0c3e726 Michael Hanselmann
  names = _MakeSequence(names)
127 a0c3e726 Michael Hanselmann
128 a0c3e726 Michael Hanselmann
  result = []
129 a0c3e726 Michael Hanselmann
130 a0c3e726 Michael Hanselmann
  for name in names:
131 a0c3e726 Michael Hanselmann
    if isinstance(name, Either):
132 a0c3e726 Michael Hanselmann
      value = _TestEnabledInner(check_fn, name.tests, compat.any)
133 a0c3e726 Michael Hanselmann
    elif isinstance(name, (list, tuple)):
134 a0c3e726 Michael Hanselmann
      value = _TestEnabledInner(check_fn, name, compat.all)
135 a0c3e726 Michael Hanselmann
    else:
136 a0c3e726 Michael Hanselmann
      value = check_fn(name)
137 a0c3e726 Michael Hanselmann
138 a0c3e726 Michael Hanselmann
    result.append(value)
139 a0c3e726 Michael Hanselmann
140 a0c3e726 Michael Hanselmann
  return fn(result)
141 a0c3e726 Michael Hanselmann
142 a0c3e726 Michael Hanselmann
143 a0c3e726 Michael Hanselmann
def TestEnabled(tests, _cfg=None):
144 7d88f255 Iustin Pop
  """Returns True if the given tests are enabled.
145 7d88f255 Iustin Pop

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

149 1010ec70 Michael Hanselmann
  """
150 a0c3e726 Michael Hanselmann
  if _cfg is None:
151 a0c3e726 Michael Hanselmann
    _cfg = cfg
152 59a8fe48 Michael Hanselmann
153 59a8fe48 Michael Hanselmann
  # Get settings for all tests
154 cf632f3e Bernardo Dal Seno
  cfg_tests = _cfg.get("tests", {})
155 59a8fe48 Michael Hanselmann
156 59a8fe48 Michael Hanselmann
  # Get default setting
157 a0c3e726 Michael Hanselmann
  default = cfg_tests.get("default", True)
158 59a8fe48 Michael Hanselmann
159 a0c3e726 Michael Hanselmann
  return _TestEnabledInner(lambda name: cfg_tests.get(name, default),
160 a0c3e726 Michael Hanselmann
                           tests, compat.all)
161 cec9845c Michael Hanselmann
162 cec9845c Michael Hanselmann
163 c9e05005 Michael Hanselmann
def GetInstanceCheckScript():
164 c9e05005 Michael Hanselmann
  """Returns path to instance check script or C{None}.
165 c9e05005 Michael Hanselmann

166 c9e05005 Michael Hanselmann
  """
167 cf632f3e Bernardo Dal Seno
  return cfg.get(_INSTANCE_CHECK_KEY, None)
168 c9e05005 Michael Hanselmann
169 c9e05005 Michael Hanselmann
170 e7b6183b Michael Hanselmann
def GetEnabledHypervisors():
171 e7b6183b Michael Hanselmann
  """Returns list of enabled hypervisors.
172 e7b6183b Michael Hanselmann

173 e7b6183b Michael Hanselmann
  @rtype: list
174 e7b6183b Michael Hanselmann

175 e7b6183b Michael Hanselmann
  """
176 e7b6183b Michael Hanselmann
  try:
177 e7b6183b Michael Hanselmann
    value = cfg[_ENABLED_HV_KEY]
178 e7b6183b Michael Hanselmann
  except KeyError:
179 e7b6183b Michael Hanselmann
    return [constants.DEFAULT_ENABLED_HYPERVISOR]
180 e7b6183b Michael Hanselmann
  else:
181 e7b6183b Michael Hanselmann
    if isinstance(value, basestring):
182 e7b6183b Michael Hanselmann
      # The configuration key ("enabled-hypervisors") implies there can be
183 e7b6183b Michael Hanselmann
      # multiple values. Multiple hypervisors are comma-separated on the
184 e7b6183b Michael Hanselmann
      # command line option to "gnt-cluster init", so we need to handle them
185 e7b6183b Michael Hanselmann
      # equally here.
186 e7b6183b Michael Hanselmann
      return value.split(",")
187 e7b6183b Michael Hanselmann
    else:
188 e7b6183b Michael Hanselmann
      return value
189 e7b6183b Michael Hanselmann
190 e7b6183b Michael Hanselmann
191 e7b6183b Michael Hanselmann
def GetDefaultHypervisor():
192 e7b6183b Michael Hanselmann
  """Returns the default hypervisor to be used.
193 e7b6183b Michael Hanselmann

194 e7b6183b Michael Hanselmann
  """
195 e7b6183b Michael Hanselmann
  return GetEnabledHypervisors()[0]
196 e7b6183b Michael Hanselmann
197 e7b6183b Michael Hanselmann
198 f346a7d9 Michael Hanselmann
def GetInstanceNicMac(inst, default=None):
199 f346a7d9 Michael Hanselmann
  """Returns MAC address for instance's network interface.
200 f346a7d9 Michael Hanselmann

201 f346a7d9 Michael Hanselmann
  """
202 f346a7d9 Michael Hanselmann
  return inst.get("nic.mac/0", default)
203 f346a7d9 Michael Hanselmann
204 f346a7d9 Michael Hanselmann
205 cec9845c Michael Hanselmann
def GetMasterNode():
206 d0c8c01d Iustin Pop
  return cfg["nodes"][0]
207 cec9845c Michael Hanselmann
208 cec9845c Michael Hanselmann
209 cec9845c Michael Hanselmann
def AcquireInstance():
210 cec9845c Michael Hanselmann
  """Returns an instance which isn't in use.
211 cec9845c Michael Hanselmann

212 cec9845c Michael Hanselmann
  """
213 cec9845c Michael Hanselmann
  # Filter out unwanted instances
214 d0c8c01d Iustin Pop
  tmp_flt = lambda inst: not inst.get("_used", False)
215 d0c8c01d Iustin Pop
  instances = filter(tmp_flt, cfg["instances"])
216 cec9845c Michael Hanselmann
  del tmp_flt
217 cec9845c Michael Hanselmann
218 cec9845c Michael Hanselmann
  if len(instances) == 0:
219 cec9845c Michael Hanselmann
    raise qa_error.OutOfInstancesError("No instances left")
220 cec9845c Michael Hanselmann
221 cec9845c Michael Hanselmann
  inst = instances[0]
222 d0c8c01d Iustin Pop
  inst["_used"] = True
223 906a0346 Bernardo Dal Seno
  inst["_template"] = None
224 cec9845c Michael Hanselmann
  return inst
225 cec9845c Michael Hanselmann
226 cec9845c Michael Hanselmann
227 cec9845c Michael Hanselmann
def ReleaseInstance(inst):
228 d0c8c01d Iustin Pop
  inst["_used"] = False
229 cec9845c Michael Hanselmann
230 cec9845c Michael Hanselmann
231 906a0346 Bernardo Dal Seno
def GetInstanceTemplate(inst):
232 906a0346 Bernardo Dal Seno
  """Return the disk template of an instance.
233 906a0346 Bernardo Dal Seno

234 906a0346 Bernardo Dal Seno
  """
235 906a0346 Bernardo Dal Seno
  templ = inst["_template"]
236 906a0346 Bernardo Dal Seno
  assert templ is not None
237 906a0346 Bernardo Dal Seno
  return templ
238 906a0346 Bernardo Dal Seno
239 906a0346 Bernardo Dal Seno
240 906a0346 Bernardo Dal Seno
def SetInstanceTemplate(inst, template):
241 906a0346 Bernardo Dal Seno
  """Set the disk template for an instance.
242 906a0346 Bernardo Dal Seno

243 906a0346 Bernardo Dal Seno
  """
244 906a0346 Bernardo Dal Seno
  inst["_template"] = template
245 906a0346 Bernardo Dal Seno
246 906a0346 Bernardo Dal Seno
247 6a0f22e1 Bernardo Dal Seno
def SetExclusiveStorage(value):
248 6a0f22e1 Bernardo Dal Seno
  """Set the expected value of the exclusive_storage flag for the cluster.
249 6a0f22e1 Bernardo Dal Seno

250 6a0f22e1 Bernardo Dal Seno
  """
251 f9329a6c Michael Hanselmann
  global _exclusive_storage # pylint: disable=W0603
252 f9329a6c Michael Hanselmann
253 f9329a6c Michael Hanselmann
  _exclusive_storage = bool(value)
254 6a0f22e1 Bernardo Dal Seno
255 6a0f22e1 Bernardo Dal Seno
256 6a0f22e1 Bernardo Dal Seno
def GetExclusiveStorage():
257 6a0f22e1 Bernardo Dal Seno
  """Get the expected value of the exclusive_storage flag for the cluster.
258 6a0f22e1 Bernardo Dal Seno

259 6a0f22e1 Bernardo Dal Seno
  """
260 f9329a6c Michael Hanselmann
  val = _exclusive_storage
261 6a0f22e1 Bernardo Dal Seno
  assert val is not None
262 6a0f22e1 Bernardo Dal Seno
  return val
263 6a0f22e1 Bernardo Dal Seno
264 6a0f22e1 Bernardo Dal Seno
265 27eba428 Bernardo Dal Seno
def IsTemplateSupported(templ):
266 27eba428 Bernardo Dal Seno
  """Is the given templated supported by the current configuration?
267 27eba428 Bernardo Dal Seno

268 27eba428 Bernardo Dal Seno
  """
269 27eba428 Bernardo Dal Seno
  if GetExclusiveStorage():
270 27eba428 Bernardo Dal Seno
    return templ in constants.DTS_EXCL_STORAGE
271 27eba428 Bernardo Dal Seno
  else:
272 27eba428 Bernardo Dal Seno
    return True
273 27eba428 Bernardo Dal Seno
274 27eba428 Bernardo Dal Seno
275 cec9845c Michael Hanselmann
def AcquireNode(exclude=None):
276 cec9845c Michael Hanselmann
  """Returns the least used node.
277 cec9845c Michael Hanselmann

278 cec9845c Michael Hanselmann
  """
279 cec9845c Michael Hanselmann
  master = GetMasterNode()
280 cec9845c Michael Hanselmann
281 cec9845c Michael Hanselmann
  # Filter out unwanted nodes
282 cec9845c Michael Hanselmann
  # TODO: Maybe combine filters
283 cec9845c Michael Hanselmann
  if exclude is None:
284 d0c8c01d Iustin Pop
    nodes = cfg["nodes"][:]
285 4b62db14 Michael Hanselmann
  elif isinstance(exclude, (list, tuple)):
286 d0c8c01d Iustin Pop
    nodes = filter(lambda node: node not in exclude, cfg["nodes"])
287 cec9845c Michael Hanselmann
  else:
288 d0c8c01d Iustin Pop
    nodes = filter(lambda node: node != exclude, cfg["nodes"])
289 cec9845c Michael Hanselmann
290 d0c8c01d Iustin Pop
  tmp_flt = lambda node: node.get("_added", False) or node == master
291 cec9845c Michael Hanselmann
  nodes = filter(tmp_flt, nodes)
292 cec9845c Michael Hanselmann
  del tmp_flt
293 cec9845c Michael Hanselmann
294 cec9845c Michael Hanselmann
  if len(nodes) == 0:
295 cec9845c Michael Hanselmann
    raise qa_error.OutOfNodesError("No nodes left")
296 cec9845c Michael Hanselmann
297 cec9845c Michael Hanselmann
  # Get node with least number of uses
298 cec9845c Michael Hanselmann
  def compare(a, b):
299 d0c8c01d Iustin Pop
    result = cmp(a.get("_count", 0), b.get("_count", 0))
300 cec9845c Michael Hanselmann
    if result == 0:
301 d0c8c01d Iustin Pop
      result = cmp(a["primary"], b["primary"])
302 cec9845c Michael Hanselmann
    return result
303 cec9845c Michael Hanselmann
304 cec9845c Michael Hanselmann
  nodes.sort(cmp=compare)
305 cec9845c Michael Hanselmann
306 cec9845c Michael Hanselmann
  node = nodes[0]
307 d0c8c01d Iustin Pop
  node["_count"] = node.get("_count", 0) + 1
308 cec9845c Michael Hanselmann
  return node
309 cec9845c Michael Hanselmann
310 cec9845c Michael Hanselmann
311 7d4f1b45 Bernardo Dal Seno
def AcquireManyNodes(num, exclude=None):
312 7d4f1b45 Bernardo Dal Seno
  """Return the least used nodes.
313 7d4f1b45 Bernardo Dal Seno

314 7d4f1b45 Bernardo Dal Seno
  @type num: int
315 7d4f1b45 Bernardo Dal Seno
  @param num: Number of nodes; can be 0.
316 7d4f1b45 Bernardo Dal Seno
  @type exclude: list of nodes or C{None}
317 7d4f1b45 Bernardo Dal Seno
  @param exclude: nodes to be excluded from the choice
318 7d4f1b45 Bernardo Dal Seno
  @rtype: list of nodes
319 7d4f1b45 Bernardo Dal Seno
  @return: C{num} different nodes
320 7d4f1b45 Bernardo Dal Seno

321 7d4f1b45 Bernardo Dal Seno
  """
322 7d4f1b45 Bernardo Dal Seno
  nodes = []
323 7d4f1b45 Bernardo Dal Seno
  if exclude is None:
324 7d4f1b45 Bernardo Dal Seno
    exclude = []
325 7d4f1b45 Bernardo Dal Seno
  elif isinstance(exclude, (list, tuple)):
326 7d4f1b45 Bernardo Dal Seno
    # Don't modify the incoming argument
327 7d4f1b45 Bernardo Dal Seno
    exclude = list(exclude)
328 7d4f1b45 Bernardo Dal Seno
  else:
329 7d4f1b45 Bernardo Dal Seno
    exclude = [exclude]
330 7d4f1b45 Bernardo Dal Seno
331 7d4f1b45 Bernardo Dal Seno
  try:
332 7d4f1b45 Bernardo Dal Seno
    for _ in range(0, num):
333 7d4f1b45 Bernardo Dal Seno
      n = AcquireNode(exclude=exclude)
334 7d4f1b45 Bernardo Dal Seno
      nodes.append(n)
335 7d4f1b45 Bernardo Dal Seno
      exclude.append(n)
336 7d4f1b45 Bernardo Dal Seno
  except qa_error.OutOfNodesError:
337 7d4f1b45 Bernardo Dal Seno
    ReleaseManyNodes(nodes)
338 7d4f1b45 Bernardo Dal Seno
    raise
339 7d4f1b45 Bernardo Dal Seno
  return nodes
340 7d4f1b45 Bernardo Dal Seno
341 7d4f1b45 Bernardo Dal Seno
342 cec9845c Michael Hanselmann
def ReleaseNode(node):
343 d0c8c01d Iustin Pop
  node["_count"] = node.get("_count", 0) - 1
344 7d4f1b45 Bernardo Dal Seno
345 7d4f1b45 Bernardo Dal Seno
346 7d4f1b45 Bernardo Dal Seno
def ReleaseManyNodes(nodes):
347 7d4f1b45 Bernardo Dal Seno
  for n in nodes:
348 7d4f1b45 Bernardo Dal Seno
    ReleaseNode(n)