Statistics
| Branch: | Tag: | Revision:

root / qa / qa_utils.py @ 33c730a2

History | View | Annotate | Download (20.8 kB)

1 c68d1f43 Michael Hanselmann
#
2 c68d1f43 Michael Hanselmann
#
3 c68d1f43 Michael Hanselmann
4 587f8ff6 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
"""Utilities for QA tests.
23 cec9845c Michael Hanselmann

24 cec9845c Michael Hanselmann
"""
25 cec9845c Michael Hanselmann
26 cec9845c Michael Hanselmann
import os
27 e6ce18ac René Nussbaumer
import re
28 23269c5b Michael Hanselmann
import sys
29 cec9845c Michael Hanselmann
import subprocess
30 288d6440 Michael Hanselmann
import random
31 f7e6f3c8 Iustin Pop
import tempfile
32 6998aefe Michael Hanselmann
import operator
33 cec9845c Michael Hanselmann
34 c9e05005 Michael Hanselmann
try:
35 c9e05005 Michael Hanselmann
  import functools
36 c9e05005 Michael Hanselmann
except ImportError, err:
37 c9e05005 Michael Hanselmann
  raise ImportError("Python 2.5 or higher is required: %s" % err)
38 c9e05005 Michael Hanselmann
39 cec9845c Michael Hanselmann
from ganeti import utils
40 288d6440 Michael Hanselmann
from ganeti import compat
41 2214cf14 Michael Hanselmann
from ganeti import constants
42 c9e05005 Michael Hanselmann
from ganeti import ht
43 48967eb0 Michael Hanselmann
from ganeti import pathutils
44 50eaa5da Michael Hanselmann
from ganeti import vcluster
45 cec9845c Michael Hanselmann
46 cec9845c Michael Hanselmann
import qa_config
47 cec9845c Michael Hanselmann
import qa_error
48 cec9845c Michael Hanselmann
49 cec9845c Michael Hanselmann
50 23269c5b Michael Hanselmann
_INFO_SEQ = None
51 23269c5b Michael Hanselmann
_WARNING_SEQ = None
52 23269c5b Michael Hanselmann
_ERROR_SEQ = None
53 23269c5b Michael Hanselmann
_RESET_SEQ = None
54 23269c5b Michael Hanselmann
55 f7e6f3c8 Iustin Pop
_MULTIPLEXERS = {}
56 f7e6f3c8 Iustin Pop
57 c9e05005 Michael Hanselmann
#: Unique ID per QA run
58 c9e05005 Michael Hanselmann
_RUN_UUID = utils.NewUUID()
59 c9e05005 Michael Hanselmann
60 afd5ca04 Iustin Pop
#: Path to the QA query output log file
61 afd5ca04 Iustin Pop
_QA_OUTPUT = pathutils.GetLogFilename("qa-output")
62 afd5ca04 Iustin Pop
63 c9e05005 Michael Hanselmann
64 c9e05005 Michael Hanselmann
(INST_DOWN,
65 c9e05005 Michael Hanselmann
 INST_UP) = range(500, 502)
66 c9e05005 Michael Hanselmann
67 c9e05005 Michael Hanselmann
(FIRST_ARG,
68 c9e05005 Michael Hanselmann
 RETURN_VALUE) = range(1000, 1002)
69 c9e05005 Michael Hanselmann
70 23269c5b Michael Hanselmann
71 23269c5b Michael Hanselmann
def _SetupColours():
72 23269c5b Michael Hanselmann
  """Initializes the colour constants.
73 23269c5b Michael Hanselmann

74 23269c5b Michael Hanselmann
  """
75 b459a848 Andrea Spadaccini
  # pylint: disable=W0603
76 3582eef6 Iustin Pop
  # due to global usage
77 23269c5b Michael Hanselmann
  global _INFO_SEQ, _WARNING_SEQ, _ERROR_SEQ, _RESET_SEQ
78 23269c5b Michael Hanselmann
79 dfe11bad Michael Hanselmann
  # Don't use colours if stdout isn't a terminal
80 dfe11bad Michael Hanselmann
  if not sys.stdout.isatty():
81 dfe11bad Michael Hanselmann
    return
82 dfe11bad Michael Hanselmann
83 23269c5b Michael Hanselmann
  try:
84 23269c5b Michael Hanselmann
    import curses
85 23269c5b Michael Hanselmann
  except ImportError:
86 23269c5b Michael Hanselmann
    # Don't use colours if curses module can't be imported
87 23269c5b Michael Hanselmann
    return
88 23269c5b Michael Hanselmann
89 23269c5b Michael Hanselmann
  curses.setupterm()
90 23269c5b Michael Hanselmann
91 23269c5b Michael Hanselmann
  _RESET_SEQ = curses.tigetstr("op")
92 23269c5b Michael Hanselmann
93 23269c5b Michael Hanselmann
  setaf = curses.tigetstr("setaf")
94 23269c5b Michael Hanselmann
  _INFO_SEQ = curses.tparm(setaf, curses.COLOR_GREEN)
95 23269c5b Michael Hanselmann
  _WARNING_SEQ = curses.tparm(setaf, curses.COLOR_YELLOW)
96 23269c5b Michael Hanselmann
  _ERROR_SEQ = curses.tparm(setaf, curses.COLOR_RED)
97 23269c5b Michael Hanselmann
98 23269c5b Michael Hanselmann
99 23269c5b Michael Hanselmann
_SetupColours()
100 23269c5b Michael Hanselmann
101 23269c5b Michael Hanselmann
102 eaef8a05 Michael Hanselmann
def AssertIn(item, sequence):
103 eaef8a05 Michael Hanselmann
  """Raises an error when item is not in sequence.
104 eaef8a05 Michael Hanselmann

105 eaef8a05 Michael Hanselmann
  """
106 eaef8a05 Michael Hanselmann
  if item not in sequence:
107 d0c8c01d Iustin Pop
    raise qa_error.Error("%r not in %r" % (item, sequence))
108 eaef8a05 Michael Hanselmann
109 eaef8a05 Michael Hanselmann
110 79eac09b Michael Hanselmann
def AssertNotIn(item, sequence):
111 79eac09b Michael Hanselmann
  """Raises an error when item is in sequence.
112 79eac09b Michael Hanselmann

113 79eac09b Michael Hanselmann
  """
114 79eac09b Michael Hanselmann
  if item in sequence:
115 d0c8c01d Iustin Pop
    raise qa_error.Error("%r in %r" % (item, sequence))
116 79eac09b Michael Hanselmann
117 79eac09b Michael Hanselmann
118 e8ae0c20 Michael Hanselmann
def AssertEqual(first, second):
119 cec9845c Michael Hanselmann
  """Raises an error when values aren't equal.
120 cec9845c Michael Hanselmann

121 cec9845c Michael Hanselmann
  """
122 cec9845c Michael Hanselmann
  if not first == second:
123 d0c8c01d Iustin Pop
    raise qa_error.Error("%r == %r" % (first, second))
124 e8ae0c20 Michael Hanselmann
125 e8ae0c20 Michael Hanselmann
126 e6ce18ac René Nussbaumer
def AssertMatch(string, pattern):
127 e6ce18ac René Nussbaumer
  """Raises an error when string doesn't match regexp pattern.
128 e6ce18ac René Nussbaumer

129 e6ce18ac René Nussbaumer
  """
130 e6ce18ac René Nussbaumer
  if not re.match(pattern, string):
131 e6ce18ac René Nussbaumer
    raise qa_error.Error("%r doesn't match /%r/" % (string, pattern))
132 e6ce18ac René Nussbaumer
133 e6ce18ac René Nussbaumer
134 6998aefe Michael Hanselmann
def _GetName(entity, fn):
135 889bed16 Michael Hanselmann
  """Tries to get name of an entity.
136 889bed16 Michael Hanselmann

137 889bed16 Michael Hanselmann
  @type entity: string or dict
138 6998aefe Michael Hanselmann
  @param fn: Function retrieving name from entity
139 889bed16 Michael Hanselmann

140 889bed16 Michael Hanselmann
  """
141 889bed16 Michael Hanselmann
  if isinstance(entity, basestring):
142 889bed16 Michael Hanselmann
    result = entity
143 889bed16 Michael Hanselmann
  else:
144 6998aefe Michael Hanselmann
    result = fn(entity)
145 889bed16 Michael Hanselmann
146 889bed16 Michael Hanselmann
  if not ht.TNonEmptyString(result):
147 889bed16 Michael Hanselmann
    raise Exception("Invalid name '%s'" % result)
148 889bed16 Michael Hanselmann
149 889bed16 Michael Hanselmann
  return result
150 889bed16 Michael Hanselmann
151 889bed16 Michael Hanselmann
152 587f8ff6 Bernardo Dal Seno
def _AssertRetCode(rcode, fail, cmdstr, nodename):
153 587f8ff6 Bernardo Dal Seno
  """Check the return value from a command and possibly raise an exception.
154 587f8ff6 Bernardo Dal Seno

155 587f8ff6 Bernardo Dal Seno
  """
156 587f8ff6 Bernardo Dal Seno
  if fail and rcode == 0:
157 587f8ff6 Bernardo Dal Seno
    raise qa_error.Error("Command '%s' on node %s was expected to fail but"
158 587f8ff6 Bernardo Dal Seno
                         " didn't" % (cmdstr, nodename))
159 587f8ff6 Bernardo Dal Seno
  elif not fail and rcode != 0:
160 587f8ff6 Bernardo Dal Seno
    raise qa_error.Error("Command '%s' on node %s failed, exit code %s" %
161 587f8ff6 Bernardo Dal Seno
                         (cmdstr, nodename, rcode))
162 587f8ff6 Bernardo Dal Seno
163 587f8ff6 Bernardo Dal Seno
164 56b9f2db Iustin Pop
def AssertCommand(cmd, fail=False, node=None, log_cmd=True):
165 2f4b4f78 Iustin Pop
  """Checks that a remote command succeeds.
166 2f4b4f78 Iustin Pop

167 2f4b4f78 Iustin Pop
  @param cmd: either a string (the command to execute) or a list (to
168 2f4b4f78 Iustin Pop
      be converted using L{utils.ShellQuoteArgs} into a string)
169 2f4b4f78 Iustin Pop
  @type fail: boolean
170 2f4b4f78 Iustin Pop
  @param fail: if the command is expected to fail instead of succeeding
171 2f4b4f78 Iustin Pop
  @param node: if passed, it should be the node on which the command
172 2f4b4f78 Iustin Pop
      should be executed, instead of the master node (can be either a
173 2f4b4f78 Iustin Pop
      dict or a string)
174 56b9f2db Iustin Pop
  @param log_cmd: if False, the command won't be logged (simply passed to
175 56b9f2db Iustin Pop
      StartSSH)
176 05325a35 Bernardo Dal Seno
  @return: the return code of the command
177 05325a35 Bernardo Dal Seno
  @raise qa_error.Error: if the command fails when it shouldn't or vice versa
178 2f4b4f78 Iustin Pop

179 2f4b4f78 Iustin Pop
  """
180 2f4b4f78 Iustin Pop
  if node is None:
181 2f4b4f78 Iustin Pop
    node = qa_config.GetMasterNode()
182 2f4b4f78 Iustin Pop
183 6998aefe Michael Hanselmann
  nodename = _GetName(node, operator.attrgetter("primary"))
184 2f4b4f78 Iustin Pop
185 2f4b4f78 Iustin Pop
  if isinstance(cmd, basestring):
186 2f4b4f78 Iustin Pop
    cmdstr = cmd
187 2f4b4f78 Iustin Pop
  else:
188 2f4b4f78 Iustin Pop
    cmdstr = utils.ShellQuoteArgs(cmd)
189 2f4b4f78 Iustin Pop
190 56b9f2db Iustin Pop
  rcode = StartSSH(nodename, cmdstr, log_cmd=log_cmd).wait()
191 587f8ff6 Bernardo Dal Seno
  _AssertRetCode(rcode, fail, cmdstr, nodename)
192 2f4b4f78 Iustin Pop
193 2214cf14 Michael Hanselmann
  return rcode
194 2214cf14 Michael Hanselmann
195 2f4b4f78 Iustin Pop
196 afd5ca04 Iustin Pop
def AssertRedirectedCommand(cmd, fail=False, node=None, log_cmd=True):
197 afd5ca04 Iustin Pop
  """Executes a command with redirected output.
198 afd5ca04 Iustin Pop

199 afd5ca04 Iustin Pop
  The log will go to the qa-output log file in the ganeti log
200 afd5ca04 Iustin Pop
  directory on the node where the command is executed. The fail and
201 afd5ca04 Iustin Pop
  node parameters are passed unchanged to AssertCommand.
202 afd5ca04 Iustin Pop

203 afd5ca04 Iustin Pop
  @param cmd: the command to be executed, as a list; a string is not
204 afd5ca04 Iustin Pop
      supported
205 afd5ca04 Iustin Pop

206 afd5ca04 Iustin Pop
  """
207 afd5ca04 Iustin Pop
  if not isinstance(cmd, list):
208 afd5ca04 Iustin Pop
    raise qa_error.Error("Non-list passed to AssertRedirectedCommand")
209 afd5ca04 Iustin Pop
  ofile = utils.ShellQuote(_QA_OUTPUT)
210 afd5ca04 Iustin Pop
  cmdstr = utils.ShellQuoteArgs(cmd)
211 afd5ca04 Iustin Pop
  AssertCommand("echo ---- $(date) %s ---- >> %s" % (cmdstr, ofile),
212 afd5ca04 Iustin Pop
                fail=False, node=node, log_cmd=False)
213 afd5ca04 Iustin Pop
  return AssertCommand(cmdstr + " >> %s" % ofile,
214 afd5ca04 Iustin Pop
                       fail=fail, node=node, log_cmd=log_cmd)
215 afd5ca04 Iustin Pop
216 afd5ca04 Iustin Pop
217 f14a8b15 Iustin Pop
def GetSSHCommand(node, cmd, strict=True, opts=None, tty=None):
218 cec9845c Michael Hanselmann
  """Builds SSH command to be executed.
219 cec9845c Michael Hanselmann

220 0a05f959 Adeodato Simo
  @type node: string
221 0a05f959 Adeodato Simo
  @param node: node the command should run on
222 0a05f959 Adeodato Simo
  @type cmd: string
223 f7e6f3c8 Iustin Pop
  @param cmd: command to be executed in the node; if None or empty
224 f7e6f3c8 Iustin Pop
      string, no command will be executed
225 0a05f959 Adeodato Simo
  @type strict: boolean
226 0a05f959 Adeodato Simo
  @param strict: whether to enable strict host key checking
227 f7e6f3c8 Iustin Pop
  @type opts: list
228 f7e6f3c8 Iustin Pop
  @param opts: list of additional options
229 f14a8b15 Iustin Pop
  @type tty: boolean or None
230 f14a8b15 Iustin Pop
  @param tty: if we should use tty; if None, will be auto-detected
231 c68d1f43 Michael Hanselmann

232 cec9845c Michael Hanselmann
  """
233 710bc88c Iustin Pop
  args = ["ssh", "-oEscapeChar=none", "-oBatchMode=yes", "-lroot"]
234 50265802 René Nussbaumer
235 f14a8b15 Iustin Pop
  if tty is None:
236 f14a8b15 Iustin Pop
    tty = sys.stdout.isatty()
237 f14a8b15 Iustin Pop
238 50265802 René Nussbaumer
  if tty:
239 50265802 René Nussbaumer
    args.append("-t")
240 cec9845c Michael Hanselmann
241 cec9845c Michael Hanselmann
  if strict:
242 d0c8c01d Iustin Pop
    tmp = "yes"
243 cec9845c Michael Hanselmann
  else:
244 d0c8c01d Iustin Pop
    tmp = "no"
245 d0c8c01d Iustin Pop
  args.append("-oStrictHostKeyChecking=%s" % tmp)
246 d0c8c01d Iustin Pop
  args.append("-oClearAllForwardings=yes")
247 d0c8c01d Iustin Pop
  args.append("-oForwardAgent=yes")
248 f7e6f3c8 Iustin Pop
  if opts:
249 f7e6f3c8 Iustin Pop
    args.extend(opts)
250 f7e6f3c8 Iustin Pop
  if node in _MULTIPLEXERS:
251 f7e6f3c8 Iustin Pop
    spath = _MULTIPLEXERS[node][0]
252 d0c8c01d Iustin Pop
    args.append("-oControlPath=%s" % spath)
253 d0c8c01d Iustin Pop
    args.append("-oControlMaster=no")
254 50eaa5da Michael Hanselmann
255 50eaa5da Michael Hanselmann
  (vcluster_master, vcluster_basedir) = \
256 50eaa5da Michael Hanselmann
    qa_config.GetVclusterSettings()
257 50eaa5da Michael Hanselmann
258 50eaa5da Michael Hanselmann
  if vcluster_master:
259 50eaa5da Michael Hanselmann
    args.append(vcluster_master)
260 50eaa5da Michael Hanselmann
    args.append("%s/%s/cmd" % (vcluster_basedir, node))
261 50eaa5da Michael Hanselmann
262 50eaa5da Michael Hanselmann
    if cmd:
263 50eaa5da Michael Hanselmann
      # For virtual clusters the whole command must be wrapped using the "cmd"
264 50eaa5da Michael Hanselmann
      # script, as that script sets a number of environment variables. If the
265 50eaa5da Michael Hanselmann
      # command contains shell meta characters the whole command needs to be
266 50eaa5da Michael Hanselmann
      # quoted.
267 50eaa5da Michael Hanselmann
      args.append(utils.ShellQuote(cmd))
268 50eaa5da Michael Hanselmann
  else:
269 50eaa5da Michael Hanselmann
    args.append(node)
270 50eaa5da Michael Hanselmann
271 50eaa5da Michael Hanselmann
    if cmd:
272 50eaa5da Michael Hanselmann
      args.append(cmd)
273 cec9845c Michael Hanselmann
274 cec9845c Michael Hanselmann
  return args
275 cec9845c Michael Hanselmann
276 cec9845c Michael Hanselmann
277 56b9f2db Iustin Pop
def StartLocalCommand(cmd, _nolog_opts=False, log_cmd=True, **kwargs):
278 5d831182 Michael Hanselmann
  """Starts a local command.
279 5d831182 Michael Hanselmann

280 5d831182 Michael Hanselmann
  """
281 56b9f2db Iustin Pop
  if log_cmd:
282 56b9f2db Iustin Pop
    if _nolog_opts:
283 56b9f2db Iustin Pop
      pcmd = [i for i in cmd if not i.startswith("-")]
284 56b9f2db Iustin Pop
    else:
285 56b9f2db Iustin Pop
      pcmd = cmd
286 56b9f2db Iustin Pop
    print "Command: %s" % utils.ShellQuoteArgs(pcmd)
287 5d831182 Michael Hanselmann
  return subprocess.Popen(cmd, shell=False, **kwargs)
288 5d831182 Michael Hanselmann
289 5d831182 Michael Hanselmann
290 56b9f2db Iustin Pop
def StartSSH(node, cmd, strict=True, log_cmd=True):
291 cec9845c Michael Hanselmann
  """Starts SSH.
292 cec9845c Michael Hanselmann

293 cec9845c Michael Hanselmann
  """
294 710bc88c Iustin Pop
  return StartLocalCommand(GetSSHCommand(node, cmd, strict=strict),
295 56b9f2db Iustin Pop
                           _nolog_opts=True, log_cmd=log_cmd)
296 4b62db14 Michael Hanselmann
297 4b62db14 Michael Hanselmann
298 f7e6f3c8 Iustin Pop
def StartMultiplexer(node):
299 f7e6f3c8 Iustin Pop
  """Starts a multiplexer command.
300 f7e6f3c8 Iustin Pop

301 f7e6f3c8 Iustin Pop
  @param node: the node for which to open the multiplexer
302 f7e6f3c8 Iustin Pop

303 f7e6f3c8 Iustin Pop
  """
304 f7e6f3c8 Iustin Pop
  if node in _MULTIPLEXERS:
305 f7e6f3c8 Iustin Pop
    return
306 f7e6f3c8 Iustin Pop
307 f7e6f3c8 Iustin Pop
  # Note: yes, we only need mktemp, since we'll remove the file anyway
308 f7e6f3c8 Iustin Pop
  sname = tempfile.mktemp(prefix="ganeti-qa-multiplexer.")
309 f7e6f3c8 Iustin Pop
  utils.RemoveFile(sname)
310 f7e6f3c8 Iustin Pop
  opts = ["-N", "-oControlPath=%s" % sname, "-oControlMaster=yes"]
311 f7e6f3c8 Iustin Pop
  print "Created socket at %s" % sname
312 f7e6f3c8 Iustin Pop
  child = StartLocalCommand(GetSSHCommand(node, None, opts=opts))
313 f7e6f3c8 Iustin Pop
  _MULTIPLEXERS[node] = (sname, child)
314 f7e6f3c8 Iustin Pop
315 f7e6f3c8 Iustin Pop
316 f7e6f3c8 Iustin Pop
def CloseMultiplexers():
317 f7e6f3c8 Iustin Pop
  """Closes all current multiplexers and cleans up.
318 f7e6f3c8 Iustin Pop

319 f7e6f3c8 Iustin Pop
  """
320 f7e6f3c8 Iustin Pop
  for node in _MULTIPLEXERS.keys():
321 f7e6f3c8 Iustin Pop
    (sname, child) = _MULTIPLEXERS.pop(node)
322 f7e6f3c8 Iustin Pop
    utils.KillProcess(child.pid, timeout=10, waitpid=True)
323 f7e6f3c8 Iustin Pop
    utils.RemoveFile(sname)
324 f7e6f3c8 Iustin Pop
325 f7e6f3c8 Iustin Pop
326 587f8ff6 Bernardo Dal Seno
def GetCommandOutput(node, cmd, tty=None, fail=False):
327 4b62db14 Michael Hanselmann
  """Returns the output of a command executed on the given node.
328 4b62db14 Michael Hanselmann

329 587f8ff6 Bernardo Dal Seno
  @type node: string
330 587f8ff6 Bernardo Dal Seno
  @param node: node the command should run on
331 587f8ff6 Bernardo Dal Seno
  @type cmd: string
332 587f8ff6 Bernardo Dal Seno
  @param cmd: command to be executed in the node (cannot be empty or None)
333 587f8ff6 Bernardo Dal Seno
  @type tty: bool or None
334 587f8ff6 Bernardo Dal Seno
  @param tty: if we should use tty; if None, it will be auto-detected
335 587f8ff6 Bernardo Dal Seno
  @type fail: bool
336 587f8ff6 Bernardo Dal Seno
  @param fail: whether the command is expected to fail
337 4b62db14 Michael Hanselmann
  """
338 587f8ff6 Bernardo Dal Seno
  assert cmd
339 50265802 René Nussbaumer
  p = StartLocalCommand(GetSSHCommand(node, cmd, tty=tty),
340 50265802 René Nussbaumer
                        stdout=subprocess.PIPE)
341 587f8ff6 Bernardo Dal Seno
  rcode = p.wait()
342 3b0db9e3 Michael Hanselmann
  _AssertRetCode(rcode, fail, cmd, node)
343 4b62db14 Michael Hanselmann
  return p.stdout.read()
344 cec9845c Michael Hanselmann
345 cec9845c Michael Hanselmann
346 cec9845c Michael Hanselmann
def UploadFile(node, src):
347 cec9845c Michael Hanselmann
  """Uploads a file to a node and returns the filename.
348 cec9845c Michael Hanselmann

349 cec9845c Michael Hanselmann
  Caller needs to remove the returned file on the node when it's not needed
350 cec9845c Michael Hanselmann
  anymore.
351 49d50e52 Michael Hanselmann

352 cec9845c Michael Hanselmann
  """
353 cec9845c Michael Hanselmann
  # Make sure nobody else has access to it while preserving local permissions
354 cec9845c Michael Hanselmann
  mode = os.stat(src).st_mode & 0700
355 cec9845c Michael Hanselmann
356 cec9845c Michael Hanselmann
  cmd = ('tmp=$(tempfile --mode %o --prefix gnt) && '
357 cec9845c Michael Hanselmann
         '[[ -f "${tmp}" ]] && '
358 cec9845c Michael Hanselmann
         'cat > "${tmp}" && '
359 cec9845c Michael Hanselmann
         'echo "${tmp}"') % mode
360 cec9845c Michael Hanselmann
361 d0c8c01d Iustin Pop
  f = open(src, "r")
362 cec9845c Michael Hanselmann
  try:
363 cec9845c Michael Hanselmann
    p = subprocess.Popen(GetSSHCommand(node, cmd), shell=False, stdin=f,
364 cec9845c Michael Hanselmann
                         stdout=subprocess.PIPE)
365 cec9845c Michael Hanselmann
    AssertEqual(p.wait(), 0)
366 cec9845c Michael Hanselmann
367 cec9845c Michael Hanselmann
    # Return temporary filename
368 cec9845c Michael Hanselmann
    return p.stdout.read().strip()
369 cec9845c Michael Hanselmann
  finally:
370 cec9845c Michael Hanselmann
    f.close()
371 5d640672 Michael Hanselmann
372 5d640672 Michael Hanselmann
373 b9955569 René Nussbaumer
def UploadData(node, data, mode=0600, filename=None):
374 b9955569 René Nussbaumer
  """Uploads data to a node and returns the filename.
375 b9955569 René Nussbaumer

376 b9955569 René Nussbaumer
  Caller needs to remove the returned file on the node when it's not needed
377 b9955569 René Nussbaumer
  anymore.
378 b9955569 René Nussbaumer

379 b9955569 René Nussbaumer
  """
380 b9955569 René Nussbaumer
  if filename:
381 b9955569 René Nussbaumer
    tmp = "tmp=%s" % utils.ShellQuote(filename)
382 b9955569 René Nussbaumer
  else:
383 b9955569 René Nussbaumer
    tmp = "tmp=$(tempfile --mode %o --prefix gnt)" % mode
384 b9955569 René Nussbaumer
  cmd = ("%s && "
385 b9955569 René Nussbaumer
         "[[ -f \"${tmp}\" ]] && "
386 b9955569 René Nussbaumer
         "cat > \"${tmp}\" && "
387 b9955569 René Nussbaumer
         "echo \"${tmp}\"") % tmp
388 b9955569 René Nussbaumer
389 b9955569 René Nussbaumer
  p = subprocess.Popen(GetSSHCommand(node, cmd), shell=False,
390 b9955569 René Nussbaumer
                       stdin=subprocess.PIPE, stdout=subprocess.PIPE)
391 b9955569 René Nussbaumer
  p.stdin.write(data)
392 b9955569 René Nussbaumer
  p.stdin.close()
393 b9955569 René Nussbaumer
  AssertEqual(p.wait(), 0)
394 b9955569 René Nussbaumer
395 b9955569 René Nussbaumer
  # Return temporary filename
396 b9955569 René Nussbaumer
  return p.stdout.read().strip()
397 b9955569 René Nussbaumer
398 b9955569 René Nussbaumer
399 49d50e52 Michael Hanselmann
def BackupFile(node, path):
400 49d50e52 Michael Hanselmann
  """Creates a backup of a file on the node and returns the filename.
401 49d50e52 Michael Hanselmann

402 49d50e52 Michael Hanselmann
  Caller needs to remove the returned file on the node when it's not needed
403 49d50e52 Michael Hanselmann
  anymore.
404 49d50e52 Michael Hanselmann

405 49d50e52 Michael Hanselmann
  """
406 7160f14a Michael Hanselmann
  vpath = MakeNodePath(node, path)
407 7160f14a Michael Hanselmann
408 49d50e52 Michael Hanselmann
  cmd = ("tmp=$(tempfile --prefix .gnt --directory=$(dirname %s)) && "
409 49d50e52 Michael Hanselmann
         "[[ -f \"$tmp\" ]] && "
410 49d50e52 Michael Hanselmann
         "cp %s $tmp && "
411 7160f14a Michael Hanselmann
         "echo $tmp") % (utils.ShellQuote(vpath), utils.ShellQuote(vpath))
412 49d50e52 Michael Hanselmann
413 49d50e52 Michael Hanselmann
  # Return temporary filename
414 7160f14a Michael Hanselmann
  result = GetCommandOutput(node, cmd).strip()
415 7160f14a Michael Hanselmann
416 7160f14a Michael Hanselmann
  print "Backup filename: %s" % result
417 7160f14a Michael Hanselmann
418 7160f14a Michael Hanselmann
  return result
419 49d50e52 Michael Hanselmann
420 49d50e52 Michael Hanselmann
421 4b62db14 Michael Hanselmann
def _ResolveName(cmd, key):
422 4b62db14 Michael Hanselmann
  """Helper function.
423 4b62db14 Michael Hanselmann

424 4b62db14 Michael Hanselmann
  """
425 4b62db14 Michael Hanselmann
  master = qa_config.GetMasterNode()
426 4b62db14 Michael Hanselmann
427 aecba21e Michael Hanselmann
  output = GetCommandOutput(master.primary, utils.ShellQuoteArgs(cmd))
428 4b62db14 Michael Hanselmann
  for line in output.splitlines():
429 d0c8c01d Iustin Pop
    (lkey, lvalue) = line.split(":", 1)
430 4b62db14 Michael Hanselmann
    if lkey == key:
431 4b62db14 Michael Hanselmann
      return lvalue.lstrip()
432 4b62db14 Michael Hanselmann
  raise KeyError("Key not found")
433 4b62db14 Michael Hanselmann
434 4b62db14 Michael Hanselmann
435 5d640672 Michael Hanselmann
def ResolveInstanceName(instance):
436 5d640672 Michael Hanselmann
  """Gets the full name of an instance.
437 5d640672 Michael Hanselmann

438 46f9a948 Michael Hanselmann
  @type instance: string
439 46f9a948 Michael Hanselmann
  @param instance: Instance name
440 46f9a948 Michael Hanselmann

441 5d640672 Michael Hanselmann
  """
442 d0c8c01d Iustin Pop
  return _ResolveName(["gnt-instance", "info", instance],
443 d0c8c01d Iustin Pop
                      "Instance name")
444 4b62db14 Michael Hanselmann
445 4b62db14 Michael Hanselmann
446 4b62db14 Michael Hanselmann
def ResolveNodeName(node):
447 4b62db14 Michael Hanselmann
  """Gets the full name of a node.
448 4b62db14 Michael Hanselmann

449 4b62db14 Michael Hanselmann
  """
450 aecba21e Michael Hanselmann
  return _ResolveName(["gnt-node", "info", node.primary],
451 d0c8c01d Iustin Pop
                      "Node name")
452 4b62db14 Michael Hanselmann
453 4b62db14 Michael Hanselmann
454 4b62db14 Michael Hanselmann
def GetNodeInstances(node, secondaries=False):
455 4b62db14 Michael Hanselmann
  """Gets a list of instances on a node.
456 4b62db14 Michael Hanselmann

457 4b62db14 Michael Hanselmann
  """
458 5d640672 Michael Hanselmann
  master = qa_config.GetMasterNode()
459 4b62db14 Michael Hanselmann
  node_name = ResolveNodeName(node)
460 5d640672 Michael Hanselmann
461 4b62db14 Michael Hanselmann
  # Get list of all instances
462 d0c8c01d Iustin Pop
  cmd = ["gnt-instance", "list", "--separator=:", "--no-headers",
463 d0c8c01d Iustin Pop
         "--output=name,pnode,snodes"]
464 aecba21e Michael Hanselmann
  output = GetCommandOutput(master.primary, utils.ShellQuoteArgs(cmd))
465 4b62db14 Michael Hanselmann
466 4b62db14 Michael Hanselmann
  instances = []
467 4b62db14 Michael Hanselmann
  for line in output.splitlines():
468 d0c8c01d Iustin Pop
    (name, pnode, snodes) = line.split(":", 2)
469 4b62db14 Michael Hanselmann
    if ((not secondaries and pnode == node_name) or
470 d0c8c01d Iustin Pop
        (secondaries and node_name in snodes.split(","))):
471 4b62db14 Michael Hanselmann
      instances.append(name)
472 5d640672 Michael Hanselmann
473 4b62db14 Michael Hanselmann
  return instances
474 23269c5b Michael Hanselmann
475 23269c5b Michael Hanselmann
476 288d6440 Michael Hanselmann
def _SelectQueryFields(rnd, fields):
477 288d6440 Michael Hanselmann
  """Generates a list of fields for query tests.
478 288d6440 Michael Hanselmann

479 288d6440 Michael Hanselmann
  """
480 288d6440 Michael Hanselmann
  # Create copy for shuffling
481 288d6440 Michael Hanselmann
  fields = list(fields)
482 288d6440 Michael Hanselmann
  rnd.shuffle(fields)
483 288d6440 Michael Hanselmann
484 288d6440 Michael Hanselmann
  # Check all fields
485 288d6440 Michael Hanselmann
  yield fields
486 288d6440 Michael Hanselmann
  yield sorted(fields)
487 288d6440 Michael Hanselmann
488 288d6440 Michael Hanselmann
  # Duplicate fields
489 288d6440 Michael Hanselmann
  yield fields + fields
490 288d6440 Michael Hanselmann
491 288d6440 Michael Hanselmann
  # Check small groups of fields
492 288d6440 Michael Hanselmann
  while fields:
493 288d6440 Michael Hanselmann
    yield [fields.pop() for _ in range(rnd.randint(2, 10)) if fields]
494 288d6440 Michael Hanselmann
495 288d6440 Michael Hanselmann
496 288d6440 Michael Hanselmann
def _List(listcmd, fields, names):
497 288d6440 Michael Hanselmann
  """Runs a list command.
498 288d6440 Michael Hanselmann

499 288d6440 Michael Hanselmann
  """
500 288d6440 Michael Hanselmann
  master = qa_config.GetMasterNode()
501 288d6440 Michael Hanselmann
502 58ea8d17 Michael Hanselmann
  cmd = [listcmd, "list", "--separator=|", "--no-headers",
503 288d6440 Michael Hanselmann
         "--output", ",".join(fields)]
504 288d6440 Michael Hanselmann
505 288d6440 Michael Hanselmann
  if names:
506 288d6440 Michael Hanselmann
    cmd.extend(names)
507 288d6440 Michael Hanselmann
508 aecba21e Michael Hanselmann
  return GetCommandOutput(master.primary,
509 288d6440 Michael Hanselmann
                          utils.ShellQuoteArgs(cmd)).splitlines()
510 288d6440 Michael Hanselmann
511 288d6440 Michael Hanselmann
512 6d1e4845 Michael Hanselmann
def GenericQueryTest(cmd, fields, namefield="name", test_unknown=True):
513 288d6440 Michael Hanselmann
  """Runs a number of tests on query commands.
514 288d6440 Michael Hanselmann

515 288d6440 Michael Hanselmann
  @param cmd: Command name
516 288d6440 Michael Hanselmann
  @param fields: List of field names
517 288d6440 Michael Hanselmann

518 288d6440 Michael Hanselmann
  """
519 288d6440 Michael Hanselmann
  rnd = random.Random(hash(cmd))
520 288d6440 Michael Hanselmann
521 3582eef6 Iustin Pop
  fields = list(fields)
522 288d6440 Michael Hanselmann
  rnd.shuffle(fields)
523 288d6440 Michael Hanselmann
524 288d6440 Michael Hanselmann
  # Test a number of field combinations
525 288d6440 Michael Hanselmann
  for testfields in _SelectQueryFields(rnd, fields):
526 93146c8c Iustin Pop
    AssertRedirectedCommand([cmd, "list", "--output", ",".join(testfields)])
527 288d6440 Michael Hanselmann
528 0fdf247d Michael Hanselmann
  if namefield is not None:
529 0fdf247d Michael Hanselmann
    namelist_fn = compat.partial(_List, cmd, [namefield])
530 288d6440 Michael Hanselmann
531 0fdf247d Michael Hanselmann
    # When no names were requested, the list must be sorted
532 0fdf247d Michael Hanselmann
    names = namelist_fn(None)
533 0fdf247d Michael Hanselmann
    AssertEqual(names, utils.NiceSort(names))
534 288d6440 Michael Hanselmann
535 0fdf247d Michael Hanselmann
    # When requesting specific names, the order must be kept
536 0fdf247d Michael Hanselmann
    revnames = list(reversed(names))
537 0fdf247d Michael Hanselmann
    AssertEqual(namelist_fn(revnames), revnames)
538 288d6440 Michael Hanselmann
539 0fdf247d Michael Hanselmann
    randnames = list(names)
540 0fdf247d Michael Hanselmann
    rnd.shuffle(randnames)
541 0fdf247d Michael Hanselmann
    AssertEqual(namelist_fn(randnames), randnames)
542 288d6440 Michael Hanselmann
543 6d1e4845 Michael Hanselmann
  if test_unknown:
544 6d1e4845 Michael Hanselmann
    # Listing unknown items must fail
545 6d1e4845 Michael Hanselmann
    AssertCommand([cmd, "list", "this.name.certainly.does.not.exist"],
546 6d1e4845 Michael Hanselmann
                  fail=True)
547 2214cf14 Michael Hanselmann
548 2214cf14 Michael Hanselmann
  # Check exit code for listing unknown field
549 93146c8c Iustin Pop
  AssertEqual(AssertRedirectedCommand([cmd, "list",
550 93146c8c Iustin Pop
                                       "--output=field/does/not/exist"],
551 93146c8c Iustin Pop
                                      fail=True),
552 2214cf14 Michael Hanselmann
              constants.EXIT_UNKNOWN_FIELD)
553 2214cf14 Michael Hanselmann
554 2214cf14 Michael Hanselmann
555 2214cf14 Michael Hanselmann
def GenericQueryFieldsTest(cmd, fields):
556 2214cf14 Michael Hanselmann
  master = qa_config.GetMasterNode()
557 2214cf14 Michael Hanselmann
558 2214cf14 Michael Hanselmann
  # Listing fields
559 93146c8c Iustin Pop
  AssertRedirectedCommand([cmd, "list-fields"])
560 93146c8c Iustin Pop
  AssertRedirectedCommand([cmd, "list-fields"] + fields)
561 2214cf14 Michael Hanselmann
562 2214cf14 Michael Hanselmann
  # Check listed fields (all, must be sorted)
563 2214cf14 Michael Hanselmann
  realcmd = [cmd, "list-fields", "--separator=|", "--no-headers"]
564 aecba21e Michael Hanselmann
  output = GetCommandOutput(master.primary,
565 2214cf14 Michael Hanselmann
                            utils.ShellQuoteArgs(realcmd)).splitlines()
566 2214cf14 Michael Hanselmann
  AssertEqual([line.split("|", 1)[0] for line in output],
567 c694367b Michael Hanselmann
              utils.NiceSort(fields))
568 2214cf14 Michael Hanselmann
569 2214cf14 Michael Hanselmann
  # Check exit code for listing unknown field
570 2214cf14 Michael Hanselmann
  AssertEqual(AssertCommand([cmd, "list-fields", "field/does/not/exist"],
571 2214cf14 Michael Hanselmann
                            fail=True),
572 2214cf14 Michael Hanselmann
              constants.EXIT_UNKNOWN_FIELD)
573 2214cf14 Michael Hanselmann
574 288d6440 Michael Hanselmann
575 dfe11bad Michael Hanselmann
def _FormatWithColor(text, seq):
576 dfe11bad Michael Hanselmann
  if not seq:
577 dfe11bad Michael Hanselmann
    return text
578 dfe11bad Michael Hanselmann
  return "%s%s%s" % (seq, text, _RESET_SEQ)
579 23269c5b Michael Hanselmann
580 23269c5b Michael Hanselmann
581 dfe11bad Michael Hanselmann
FormatWarning = lambda text: _FormatWithColor(text, _WARNING_SEQ)
582 dfe11bad Michael Hanselmann
FormatError = lambda text: _FormatWithColor(text, _ERROR_SEQ)
583 dfe11bad Michael Hanselmann
FormatInfo = lambda text: _FormatWithColor(text, _INFO_SEQ)
584 31fe5102 René Nussbaumer
585 31fe5102 René Nussbaumer
586 31fe5102 René Nussbaumer
def AddToEtcHosts(hostnames):
587 31fe5102 René Nussbaumer
  """Adds hostnames to /etc/hosts.
588 31fe5102 René Nussbaumer

589 31fe5102 René Nussbaumer
  @param hostnames: List of hostnames first used A records, all other CNAMEs
590 31fe5102 René Nussbaumer

591 31fe5102 René Nussbaumer
  """
592 31fe5102 René Nussbaumer
  master = qa_config.GetMasterNode()
593 aecba21e Michael Hanselmann
  tmp_hosts = UploadData(master.primary, "", mode=0644)
594 31fe5102 René Nussbaumer
595 31fe5102 René Nussbaumer
  data = []
596 31fe5102 René Nussbaumer
  for localhost in ("::1", "127.0.0.1"):
597 31fe5102 René Nussbaumer
    data.append("%s %s" % (localhost, " ".join(hostnames)))
598 31fe5102 René Nussbaumer
599 31fe5102 René Nussbaumer
  try:
600 48967eb0 Michael Hanselmann
    AssertCommand("{ cat %s && echo -e '%s'; } > %s && mv %s %s" %
601 48967eb0 Michael Hanselmann
                  (utils.ShellQuote(pathutils.ETC_HOSTS),
602 48967eb0 Michael Hanselmann
                   "\\n".join(data),
603 48967eb0 Michael Hanselmann
                   utils.ShellQuote(tmp_hosts),
604 48967eb0 Michael Hanselmann
                   utils.ShellQuote(tmp_hosts),
605 48967eb0 Michael Hanselmann
                   utils.ShellQuote(pathutils.ETC_HOSTS)))
606 48967eb0 Michael Hanselmann
  except Exception:
607 48967eb0 Michael Hanselmann
    AssertCommand(["rm", "-f", tmp_hosts])
608 48967eb0 Michael Hanselmann
    raise
609 31fe5102 René Nussbaumer
610 31fe5102 René Nussbaumer
611 31fe5102 René Nussbaumer
def RemoveFromEtcHosts(hostnames):
612 31fe5102 René Nussbaumer
  """Remove hostnames from /etc/hosts.
613 31fe5102 René Nussbaumer

614 31fe5102 René Nussbaumer
  @param hostnames: List of hostnames first used A records, all other CNAMEs
615 31fe5102 René Nussbaumer

616 31fe5102 René Nussbaumer
  """
617 31fe5102 René Nussbaumer
  master = qa_config.GetMasterNode()
618 aecba21e Michael Hanselmann
  tmp_hosts = UploadData(master.primary, "", mode=0644)
619 31fe5102 René Nussbaumer
  quoted_tmp_hosts = utils.ShellQuote(tmp_hosts)
620 31fe5102 René Nussbaumer
621 31fe5102 René Nussbaumer
  sed_data = " ".join(hostnames)
622 31fe5102 René Nussbaumer
  try:
623 48967eb0 Michael Hanselmann
    AssertCommand(("sed -e '/^\(::1\|127\.0\.0\.1\)\s\+%s/d' %s > %s"
624 48967eb0 Michael Hanselmann
                   " && mv %s %s") %
625 48967eb0 Michael Hanselmann
                   (sed_data, utils.ShellQuote(pathutils.ETC_HOSTS),
626 48967eb0 Michael Hanselmann
                    quoted_tmp_hosts, quoted_tmp_hosts,
627 48967eb0 Michael Hanselmann
                    utils.ShellQuote(pathutils.ETC_HOSTS)))
628 48967eb0 Michael Hanselmann
  except Exception:
629 48967eb0 Michael Hanselmann
    AssertCommand(["rm", "-f", tmp_hosts])
630 48967eb0 Michael Hanselmann
    raise
631 c9e05005 Michael Hanselmann
632 c9e05005 Michael Hanselmann
633 c9e05005 Michael Hanselmann
def RunInstanceCheck(instance, running):
634 c9e05005 Michael Hanselmann
  """Check if instance is running or not.
635 c9e05005 Michael Hanselmann

636 c9e05005 Michael Hanselmann
  """
637 6998aefe Michael Hanselmann
  instance_name = _GetName(instance, operator.attrgetter("name"))
638 2ac35588 Michael Hanselmann
639 c9e05005 Michael Hanselmann
  script = qa_config.GetInstanceCheckScript()
640 c9e05005 Michael Hanselmann
  if not script:
641 c9e05005 Michael Hanselmann
    return
642 c9e05005 Michael Hanselmann
643 c9e05005 Michael Hanselmann
  master_node = qa_config.GetMasterNode()
644 c9e05005 Michael Hanselmann
645 c9e05005 Michael Hanselmann
  # Build command to connect to master node
646 aecba21e Michael Hanselmann
  master_ssh = GetSSHCommand(master_node.primary, "--")
647 c9e05005 Michael Hanselmann
648 c9e05005 Michael Hanselmann
  if running:
649 c9e05005 Michael Hanselmann
    running_shellval = "1"
650 c9e05005 Michael Hanselmann
    running_text = ""
651 c9e05005 Michael Hanselmann
  else:
652 c9e05005 Michael Hanselmann
    running_shellval = ""
653 c9e05005 Michael Hanselmann
    running_text = "not "
654 c9e05005 Michael Hanselmann
655 c9e05005 Michael Hanselmann
  print FormatInfo("Checking if instance '%s' is %srunning" %
656 c9e05005 Michael Hanselmann
                   (instance_name, running_text))
657 c9e05005 Michael Hanselmann
658 c9e05005 Michael Hanselmann
  args = [script, instance_name]
659 c9e05005 Michael Hanselmann
  env = {
660 c9e05005 Michael Hanselmann
    "PATH": constants.HOOKS_PATH,
661 c9e05005 Michael Hanselmann
    "RUN_UUID": _RUN_UUID,
662 c9e05005 Michael Hanselmann
    "MASTER_SSH": utils.ShellQuoteArgs(master_ssh),
663 c9e05005 Michael Hanselmann
    "INSTANCE_NAME": instance_name,
664 c9e05005 Michael Hanselmann
    "INSTANCE_RUNNING": running_shellval,
665 c9e05005 Michael Hanselmann
    }
666 c9e05005 Michael Hanselmann
667 c9e05005 Michael Hanselmann
  result = os.spawnve(os.P_WAIT, script, args, env)
668 c9e05005 Michael Hanselmann
  if result != 0:
669 c9e05005 Michael Hanselmann
    raise qa_error.Error("Instance check failed with result %s" % result)
670 c9e05005 Michael Hanselmann
671 c9e05005 Michael Hanselmann
672 c9e05005 Michael Hanselmann
def _InstanceCheckInner(expected, instarg, args, result):
673 c9e05005 Michael Hanselmann
  """Helper function used by L{InstanceCheck}.
674 c9e05005 Michael Hanselmann

675 c9e05005 Michael Hanselmann
  """
676 c9e05005 Michael Hanselmann
  if instarg == FIRST_ARG:
677 c9e05005 Michael Hanselmann
    instance = args[0]
678 c9e05005 Michael Hanselmann
  elif instarg == RETURN_VALUE:
679 c9e05005 Michael Hanselmann
    instance = result
680 c9e05005 Michael Hanselmann
  else:
681 c9e05005 Michael Hanselmann
    raise Exception("Invalid value '%s' for instance argument" % instarg)
682 c9e05005 Michael Hanselmann
683 c9e05005 Michael Hanselmann
  if expected in (INST_DOWN, INST_UP):
684 c9e05005 Michael Hanselmann
    RunInstanceCheck(instance, (expected == INST_UP))
685 c9e05005 Michael Hanselmann
  elif expected is not None:
686 c9e05005 Michael Hanselmann
    raise Exception("Invalid value '%s'" % expected)
687 c9e05005 Michael Hanselmann
688 c9e05005 Michael Hanselmann
689 c9e05005 Michael Hanselmann
def InstanceCheck(before, after, instarg):
690 c9e05005 Michael Hanselmann
  """Decorator to check instance status before and after test.
691 c9e05005 Michael Hanselmann

692 c9e05005 Michael Hanselmann
  @param before: L{INST_DOWN} if instance must be stopped before test,
693 c9e05005 Michael Hanselmann
    L{INST_UP} if instance must be running before test, L{None} to not check.
694 c9e05005 Michael Hanselmann
  @param after: L{INST_DOWN} if instance must be stopped after test,
695 c9e05005 Michael Hanselmann
    L{INST_UP} if instance must be running after test, L{None} to not check.
696 c9e05005 Michael Hanselmann
  @param instarg: L{FIRST_ARG} to use first argument to test as instance (a
697 c9e05005 Michael Hanselmann
    dictionary), L{RETURN_VALUE} to use return value (disallows pre-checks)
698 c9e05005 Michael Hanselmann

699 c9e05005 Michael Hanselmann
  """
700 c9e05005 Michael Hanselmann
  def decorator(fn):
701 c9e05005 Michael Hanselmann
    @functools.wraps(fn)
702 c9e05005 Michael Hanselmann
    def wrapper(*args, **kwargs):
703 c9e05005 Michael Hanselmann
      _InstanceCheckInner(before, instarg, args, NotImplemented)
704 c9e05005 Michael Hanselmann
705 c9e05005 Michael Hanselmann
      result = fn(*args, **kwargs)
706 c9e05005 Michael Hanselmann
707 c9e05005 Michael Hanselmann
      _InstanceCheckInner(after, instarg, args, result)
708 c9e05005 Michael Hanselmann
709 c9e05005 Michael Hanselmann
      return result
710 c9e05005 Michael Hanselmann
    return wrapper
711 c9e05005 Michael Hanselmann
  return decorator
712 b4d2d2cb Michael Hanselmann
713 b4d2d2cb Michael Hanselmann
714 b4d2d2cb Michael Hanselmann
def GetNonexistentGroups(count):
715 b4d2d2cb Michael Hanselmann
  """Gets group names which shouldn't exist on the cluster.
716 b4d2d2cb Michael Hanselmann

717 b4d2d2cb Michael Hanselmann
  @param count: Number of groups to get
718 ea7693c1 Helga Velroyen
  @rtype: integer
719 b4d2d2cb Michael Hanselmann

720 b4d2d2cb Michael Hanselmann
  """
721 ea7693c1 Helga Velroyen
  return GetNonexistentEntityNames(count, "groups", "group")
722 b4d2d2cb Michael Hanselmann
723 ea7693c1 Helga Velroyen
724 ea7693c1 Helga Velroyen
def GetNonexistentEntityNames(count, name_config, name_prefix):
725 ea7693c1 Helga Velroyen
  """Gets entity names which shouldn't exist on the cluster.
726 ea7693c1 Helga Velroyen

727 ea7693c1 Helga Velroyen
  The actualy names can refer to arbitrary entities (for example
728 ea7693c1 Helga Velroyen
  groups, networks).
729 ea7693c1 Helga Velroyen

730 ea7693c1 Helga Velroyen
  @param count: Number of names to get
731 ea7693c1 Helga Velroyen
  @rtype: integer
732 ea7693c1 Helga Velroyen
  @param name_config: name of the leaf in the config containing
733 ea7693c1 Helga Velroyen
    this entity's configuration, including a 'inexistent-'
734 ea7693c1 Helga Velroyen
    element
735 ea7693c1 Helga Velroyen
  @rtype: string
736 ea7693c1 Helga Velroyen
  @param name_prefix: prefix of the entity's names, used to compose
737 ea7693c1 Helga Velroyen
    the default values; for example for groups, the prefix is
738 ea7693c1 Helga Velroyen
    'group' and the generated names are then group1, group2, ...
739 ea7693c1 Helga Velroyen
  @rtype: string
740 ea7693c1 Helga Velroyen

741 ea7693c1 Helga Velroyen
  """
742 ea7693c1 Helga Velroyen
  entities = qa_config.get(name_config, {})
743 ea7693c1 Helga Velroyen
744 ea7693c1 Helga Velroyen
  default = [name_prefix + str(i) for i in range(count)]
745 b4d2d2cb Michael Hanselmann
  assert count <= len(default)
746 b4d2d2cb Michael Hanselmann
747 ea7693c1 Helga Velroyen
  name_config_inexistent = "inexistent-" + name_config
748 ea7693c1 Helga Velroyen
  candidates = entities.get(name_config_inexistent, default)[:count]
749 b4d2d2cb Michael Hanselmann
750 b4d2d2cb Michael Hanselmann
  if len(candidates) < count:
751 ea7693c1 Helga Velroyen
    raise Exception("At least %s non-existent %s are needed" %
752 ea7693c1 Helga Velroyen
                    (count, name_config))
753 b4d2d2cb Michael Hanselmann
754 b4d2d2cb Michael Hanselmann
  return candidates
755 7160f14a Michael Hanselmann
756 7160f14a Michael Hanselmann
757 7160f14a Michael Hanselmann
def MakeNodePath(node, path):
758 7160f14a Michael Hanselmann
  """Builds an absolute path for a virtual node.
759 7160f14a Michael Hanselmann

760 7160f14a Michael Hanselmann
  @type node: string or L{qa_config._QaNode}
761 7160f14a Michael Hanselmann
  @param node: Node
762 7160f14a Michael Hanselmann
  @type path: string
763 7160f14a Michael Hanselmann
  @param path: Path without node-specific prefix
764 7160f14a Michael Hanselmann

765 7160f14a Michael Hanselmann
  """
766 7160f14a Michael Hanselmann
  (_, basedir) = qa_config.GetVclusterSettings()
767 7160f14a Michael Hanselmann
768 7160f14a Michael Hanselmann
  if isinstance(node, basestring):
769 7160f14a Michael Hanselmann
    name = node
770 7160f14a Michael Hanselmann
  else:
771 7160f14a Michael Hanselmann
    name = node.primary
772 7160f14a Michael Hanselmann
773 7160f14a Michael Hanselmann
  if basedir:
774 7160f14a Michael Hanselmann
    assert path.startswith("/")
775 7160f14a Michael Hanselmann
    return "%s%s" % (vcluster.MakeNodeRoot(basedir, name), path)
776 7160f14a Michael Hanselmann
  else:
777 7160f14a Michael Hanselmann
    return path