Statistics
| Branch: | Tag: | Revision:

root / qa / qa_config.py @ e8b919a1

History | View | Annotate | Download (6.2 kB)

1 c68d1f43 Michael Hanselmann
#
2 c68d1f43 Michael Hanselmann
#
3 c68d1f43 Michael Hanselmann
4 f346a7d9 Michael Hanselmann
# Copyright (C) 2007, 2011, 2012 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 c9e05005 Michael Hanselmann
39 c9e05005 Michael Hanselmann
40 cec9845c Michael Hanselmann
cfg = None
41 cec9845c Michael Hanselmann
options = None
42 cec9845c Michael Hanselmann
43 cec9845c Michael Hanselmann
44 cec9845c Michael Hanselmann
def Load(path):
45 cec9845c Michael Hanselmann
  """Loads the passed configuration file.
46 cec9845c Michael Hanselmann

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

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

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

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

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

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

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

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

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

164 c9e05005 Michael Hanselmann
  """
165 8ad0da1e Iustin Pop
  return cfg.get(_INSTANCE_CHECK_KEY, None) # pylint: disable=E1103
166 c9e05005 Michael Hanselmann
167 c9e05005 Michael Hanselmann
168 e7b6183b Michael Hanselmann
def GetEnabledHypervisors():
169 e7b6183b Michael Hanselmann
  """Returns list of enabled hypervisors.
170 e7b6183b Michael Hanselmann

171 e7b6183b Michael Hanselmann
  @rtype: list
172 e7b6183b Michael Hanselmann

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

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

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

210 cec9845c Michael Hanselmann
  """
211 cec9845c Michael Hanselmann
  # Filter out unwanted instances
212 d0c8c01d Iustin Pop
  tmp_flt = lambda inst: not inst.get("_used", False)
213 d0c8c01d Iustin Pop
  instances = filter(tmp_flt, cfg["instances"])
214 cec9845c Michael Hanselmann
  del tmp_flt
215 cec9845c Michael Hanselmann
216 cec9845c Michael Hanselmann
  if len(instances) == 0:
217 cec9845c Michael Hanselmann
    raise qa_error.OutOfInstancesError("No instances left")
218 cec9845c Michael Hanselmann
219 cec9845c Michael Hanselmann
  inst = instances[0]
220 d0c8c01d Iustin Pop
  inst["_used"] = True
221 cec9845c Michael Hanselmann
  return inst
222 cec9845c Michael Hanselmann
223 cec9845c Michael Hanselmann
224 cec9845c Michael Hanselmann
def ReleaseInstance(inst):
225 d0c8c01d Iustin Pop
  inst["_used"] = False
226 cec9845c Michael Hanselmann
227 cec9845c Michael Hanselmann
228 cec9845c Michael Hanselmann
def AcquireNode(exclude=None):
229 cec9845c Michael Hanselmann
  """Returns the least used node.
230 cec9845c Michael Hanselmann

231 cec9845c Michael Hanselmann
  """
232 cec9845c Michael Hanselmann
  master = GetMasterNode()
233 cec9845c Michael Hanselmann
234 cec9845c Michael Hanselmann
  # Filter out unwanted nodes
235 cec9845c Michael Hanselmann
  # TODO: Maybe combine filters
236 cec9845c Michael Hanselmann
  if exclude is None:
237 d0c8c01d Iustin Pop
    nodes = cfg["nodes"][:]
238 4b62db14 Michael Hanselmann
  elif isinstance(exclude, (list, tuple)):
239 d0c8c01d Iustin Pop
    nodes = filter(lambda node: node not in exclude, cfg["nodes"])
240 cec9845c Michael Hanselmann
  else:
241 d0c8c01d Iustin Pop
    nodes = filter(lambda node: node != exclude, cfg["nodes"])
242 cec9845c Michael Hanselmann
243 d0c8c01d Iustin Pop
  tmp_flt = lambda node: node.get("_added", False) or node == master
244 cec9845c Michael Hanselmann
  nodes = filter(tmp_flt, nodes)
245 cec9845c Michael Hanselmann
  del tmp_flt
246 cec9845c Michael Hanselmann
247 cec9845c Michael Hanselmann
  if len(nodes) == 0:
248 cec9845c Michael Hanselmann
    raise qa_error.OutOfNodesError("No nodes left")
249 cec9845c Michael Hanselmann
250 cec9845c Michael Hanselmann
  # Get node with least number of uses
251 cec9845c Michael Hanselmann
  def compare(a, b):
252 d0c8c01d Iustin Pop
    result = cmp(a.get("_count", 0), b.get("_count", 0))
253 cec9845c Michael Hanselmann
    if result == 0:
254 d0c8c01d Iustin Pop
      result = cmp(a["primary"], b["primary"])
255 cec9845c Michael Hanselmann
    return result
256 cec9845c Michael Hanselmann
257 cec9845c Michael Hanselmann
  nodes.sort(cmp=compare)
258 cec9845c Michael Hanselmann
259 cec9845c Michael Hanselmann
  node = nodes[0]
260 d0c8c01d Iustin Pop
  node["_count"] = node.get("_count", 0) + 1
261 cec9845c Michael Hanselmann
  return node
262 cec9845c Michael Hanselmann
263 cec9845c Michael Hanselmann
264 cec9845c Michael Hanselmann
def ReleaseNode(node):
265 d0c8c01d Iustin Pop
  node["_count"] = node.get("_count", 0) - 1