Statistics
| Branch: | Tag: | Revision:

root / qa / qa_utils.py @ cf62af3a

History | View | Annotate | Download (19.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 cec9845c Michael Hanselmann
33 c9e05005 Michael Hanselmann
try:
34 c9e05005 Michael Hanselmann
  import functools
35 c9e05005 Michael Hanselmann
except ImportError, err:
36 c9e05005 Michael Hanselmann
  raise ImportError("Python 2.5 or higher is required: %s" % err)
37 c9e05005 Michael Hanselmann
38 cec9845c Michael Hanselmann
from ganeti import utils
39 288d6440 Michael Hanselmann
from ganeti import compat
40 2214cf14 Michael Hanselmann
from ganeti import constants
41 c9e05005 Michael Hanselmann
from ganeti import ht
42 48967eb0 Michael Hanselmann
from ganeti import pathutils
43 cec9845c Michael Hanselmann
44 cec9845c Michael Hanselmann
import qa_config
45 cec9845c Michael Hanselmann
import qa_error
46 cec9845c Michael Hanselmann
47 cec9845c Michael Hanselmann
48 23269c5b Michael Hanselmann
_INFO_SEQ = None
49 23269c5b Michael Hanselmann
_WARNING_SEQ = None
50 23269c5b Michael Hanselmann
_ERROR_SEQ = None
51 23269c5b Michael Hanselmann
_RESET_SEQ = None
52 23269c5b Michael Hanselmann
53 f7e6f3c8 Iustin Pop
_MULTIPLEXERS = {}
54 f7e6f3c8 Iustin Pop
55 c9e05005 Michael Hanselmann
#: Unique ID per QA run
56 c9e05005 Michael Hanselmann
_RUN_UUID = utils.NewUUID()
57 c9e05005 Michael Hanselmann
58 afd5ca04 Iustin Pop
#: Path to the QA query output log file
59 afd5ca04 Iustin Pop
_QA_OUTPUT = pathutils.GetLogFilename("qa-output")
60 afd5ca04 Iustin Pop
61 c9e05005 Michael Hanselmann
62 c9e05005 Michael Hanselmann
(INST_DOWN,
63 c9e05005 Michael Hanselmann
 INST_UP) = range(500, 502)
64 c9e05005 Michael Hanselmann
65 c9e05005 Michael Hanselmann
(FIRST_ARG,
66 c9e05005 Michael Hanselmann
 RETURN_VALUE) = range(1000, 1002)
67 c9e05005 Michael Hanselmann
68 23269c5b Michael Hanselmann
69 23269c5b Michael Hanselmann
def _SetupColours():
70 23269c5b Michael Hanselmann
  """Initializes the colour constants.
71 23269c5b Michael Hanselmann

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

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

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

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

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

135 889bed16 Michael Hanselmann
  @type entity: string or dict
136 889bed16 Michael Hanselmann
  @type key: string
137 889bed16 Michael Hanselmann
  @param key: Dictionary key containing name
138 889bed16 Michael Hanselmann

139 889bed16 Michael Hanselmann
  """
140 889bed16 Michael Hanselmann
  if isinstance(entity, basestring):
141 889bed16 Michael Hanselmann
    result = entity
142 889bed16 Michael Hanselmann
  elif isinstance(entity, dict):
143 889bed16 Michael Hanselmann
    result = entity[key]
144 889bed16 Michael Hanselmann
  else:
145 889bed16 Michael Hanselmann
    raise qa_error.Error("Expected string or dictionary, got %s: %s" %
146 889bed16 Michael Hanselmann
                         (type(entity), entity))
147 889bed16 Michael Hanselmann
148 889bed16 Michael Hanselmann
  if not ht.TNonEmptyString(result):
149 889bed16 Michael Hanselmann
    raise Exception("Invalid name '%s'" % result)
150 889bed16 Michael Hanselmann
151 889bed16 Michael Hanselmann
  return result
152 889bed16 Michael Hanselmann
153 889bed16 Michael Hanselmann
154 587f8ff6 Bernardo Dal Seno
def _AssertRetCode(rcode, fail, cmdstr, nodename):
155 587f8ff6 Bernardo Dal Seno
  """Check the return value from a command and possibly raise an exception.
156 587f8ff6 Bernardo Dal Seno

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

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

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

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

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

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

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

234 cec9845c Michael Hanselmann
  """
235 710bc88c Iustin Pop
  args = ["ssh", "-oEscapeChar=none", "-oBatchMode=yes", "-lroot"]
236 50265802 René Nussbaumer
237 f14a8b15 Iustin Pop
  if tty is None:
238 f14a8b15 Iustin Pop
    tty = sys.stdout.isatty()
239 f14a8b15 Iustin Pop
240 50265802 René Nussbaumer
  if tty:
241 50265802 René Nussbaumer
    args.append("-t")
242 cec9845c Michael Hanselmann
243 cec9845c Michael Hanselmann
  if strict:
244 d0c8c01d Iustin Pop
    tmp = "yes"
245 cec9845c Michael Hanselmann
  else:
246 d0c8c01d Iustin Pop
    tmp = "no"
247 d0c8c01d Iustin Pop
  args.append("-oStrictHostKeyChecking=%s" % tmp)
248 d0c8c01d Iustin Pop
  args.append("-oClearAllForwardings=yes")
249 d0c8c01d Iustin Pop
  args.append("-oForwardAgent=yes")
250 f7e6f3c8 Iustin Pop
  if opts:
251 f7e6f3c8 Iustin Pop
    args.extend(opts)
252 f7e6f3c8 Iustin Pop
  if node in _MULTIPLEXERS:
253 f7e6f3c8 Iustin Pop
    spath = _MULTIPLEXERS[node][0]
254 d0c8c01d Iustin Pop
    args.append("-oControlPath=%s" % spath)
255 d0c8c01d Iustin Pop
    args.append("-oControlMaster=no")
256 cec9845c Michael Hanselmann
  args.append(node)
257 f7e6f3c8 Iustin Pop
  if cmd:
258 f7e6f3c8 Iustin Pop
    args.append(cmd)
259 cec9845c Michael Hanselmann
260 cec9845c Michael Hanselmann
  return args
261 cec9845c Michael Hanselmann
262 cec9845c Michael Hanselmann
263 56b9f2db Iustin Pop
def StartLocalCommand(cmd, _nolog_opts=False, log_cmd=True, **kwargs):
264 5d831182 Michael Hanselmann
  """Starts a local command.
265 5d831182 Michael Hanselmann

266 5d831182 Michael Hanselmann
  """
267 56b9f2db Iustin Pop
  if log_cmd:
268 56b9f2db Iustin Pop
    if _nolog_opts:
269 56b9f2db Iustin Pop
      pcmd = [i for i in cmd if not i.startswith("-")]
270 56b9f2db Iustin Pop
    else:
271 56b9f2db Iustin Pop
      pcmd = cmd
272 56b9f2db Iustin Pop
    print "Command: %s" % utils.ShellQuoteArgs(pcmd)
273 5d831182 Michael Hanselmann
  return subprocess.Popen(cmd, shell=False, **kwargs)
274 5d831182 Michael Hanselmann
275 5d831182 Michael Hanselmann
276 56b9f2db Iustin Pop
def StartSSH(node, cmd, strict=True, log_cmd=True):
277 cec9845c Michael Hanselmann
  """Starts SSH.
278 cec9845c Michael Hanselmann

279 cec9845c Michael Hanselmann
  """
280 710bc88c Iustin Pop
  return StartLocalCommand(GetSSHCommand(node, cmd, strict=strict),
281 56b9f2db Iustin Pop
                           _nolog_opts=True, log_cmd=log_cmd)
282 4b62db14 Michael Hanselmann
283 4b62db14 Michael Hanselmann
284 f7e6f3c8 Iustin Pop
def StartMultiplexer(node):
285 f7e6f3c8 Iustin Pop
  """Starts a multiplexer command.
286 f7e6f3c8 Iustin Pop

287 f7e6f3c8 Iustin Pop
  @param node: the node for which to open the multiplexer
288 f7e6f3c8 Iustin Pop

289 f7e6f3c8 Iustin Pop
  """
290 f7e6f3c8 Iustin Pop
  if node in _MULTIPLEXERS:
291 f7e6f3c8 Iustin Pop
    return
292 f7e6f3c8 Iustin Pop
293 f7e6f3c8 Iustin Pop
  # Note: yes, we only need mktemp, since we'll remove the file anyway
294 f7e6f3c8 Iustin Pop
  sname = tempfile.mktemp(prefix="ganeti-qa-multiplexer.")
295 f7e6f3c8 Iustin Pop
  utils.RemoveFile(sname)
296 f7e6f3c8 Iustin Pop
  opts = ["-N", "-oControlPath=%s" % sname, "-oControlMaster=yes"]
297 f7e6f3c8 Iustin Pop
  print "Created socket at %s" % sname
298 f7e6f3c8 Iustin Pop
  child = StartLocalCommand(GetSSHCommand(node, None, opts=opts))
299 f7e6f3c8 Iustin Pop
  _MULTIPLEXERS[node] = (sname, child)
300 f7e6f3c8 Iustin Pop
301 f7e6f3c8 Iustin Pop
302 f7e6f3c8 Iustin Pop
def CloseMultiplexers():
303 f7e6f3c8 Iustin Pop
  """Closes all current multiplexers and cleans up.
304 f7e6f3c8 Iustin Pop

305 f7e6f3c8 Iustin Pop
  """
306 f7e6f3c8 Iustin Pop
  for node in _MULTIPLEXERS.keys():
307 f7e6f3c8 Iustin Pop
    (sname, child) = _MULTIPLEXERS.pop(node)
308 f7e6f3c8 Iustin Pop
    utils.KillProcess(child.pid, timeout=10, waitpid=True)
309 f7e6f3c8 Iustin Pop
    utils.RemoveFile(sname)
310 f7e6f3c8 Iustin Pop
311 f7e6f3c8 Iustin Pop
312 587f8ff6 Bernardo Dal Seno
def GetCommandOutput(node, cmd, tty=None, fail=False):
313 4b62db14 Michael Hanselmann
  """Returns the output of a command executed on the given node.
314 4b62db14 Michael Hanselmann

315 587f8ff6 Bernardo Dal Seno
  @type node: string
316 587f8ff6 Bernardo Dal Seno
  @param node: node the command should run on
317 587f8ff6 Bernardo Dal Seno
  @type cmd: string
318 587f8ff6 Bernardo Dal Seno
  @param cmd: command to be executed in the node (cannot be empty or None)
319 587f8ff6 Bernardo Dal Seno
  @type tty: bool or None
320 587f8ff6 Bernardo Dal Seno
  @param tty: if we should use tty; if None, it will be auto-detected
321 587f8ff6 Bernardo Dal Seno
  @type fail: bool
322 587f8ff6 Bernardo Dal Seno
  @param fail: whether the command is expected to fail
323 4b62db14 Michael Hanselmann
  """
324 587f8ff6 Bernardo Dal Seno
  assert cmd
325 50265802 René Nussbaumer
  p = StartLocalCommand(GetSSHCommand(node, cmd, tty=tty),
326 50265802 René Nussbaumer
                        stdout=subprocess.PIPE)
327 587f8ff6 Bernardo Dal Seno
  rcode = p.wait()
328 587f8ff6 Bernardo Dal Seno
  _AssertRetCode(rcode, fail, node, cmd)
329 4b62db14 Michael Hanselmann
  return p.stdout.read()
330 cec9845c Michael Hanselmann
331 cec9845c Michael Hanselmann
332 cec9845c Michael Hanselmann
def UploadFile(node, src):
333 cec9845c Michael Hanselmann
  """Uploads a file to a node and returns the filename.
334 cec9845c Michael Hanselmann

335 cec9845c Michael Hanselmann
  Caller needs to remove the returned file on the node when it's not needed
336 cec9845c Michael Hanselmann
  anymore.
337 49d50e52 Michael Hanselmann

338 cec9845c Michael Hanselmann
  """
339 cec9845c Michael Hanselmann
  # Make sure nobody else has access to it while preserving local permissions
340 cec9845c Michael Hanselmann
  mode = os.stat(src).st_mode & 0700
341 cec9845c Michael Hanselmann
342 cec9845c Michael Hanselmann
  cmd = ('tmp=$(tempfile --mode %o --prefix gnt) && '
343 cec9845c Michael Hanselmann
         '[[ -f "${tmp}" ]] && '
344 cec9845c Michael Hanselmann
         'cat > "${tmp}" && '
345 cec9845c Michael Hanselmann
         'echo "${tmp}"') % mode
346 cec9845c Michael Hanselmann
347 d0c8c01d Iustin Pop
  f = open(src, "r")
348 cec9845c Michael Hanselmann
  try:
349 cec9845c Michael Hanselmann
    p = subprocess.Popen(GetSSHCommand(node, cmd), shell=False, stdin=f,
350 cec9845c Michael Hanselmann
                         stdout=subprocess.PIPE)
351 cec9845c Michael Hanselmann
    AssertEqual(p.wait(), 0)
352 cec9845c Michael Hanselmann
353 cec9845c Michael Hanselmann
    # Return temporary filename
354 cec9845c Michael Hanselmann
    return p.stdout.read().strip()
355 cec9845c Michael Hanselmann
  finally:
356 cec9845c Michael Hanselmann
    f.close()
357 5d640672 Michael Hanselmann
358 5d640672 Michael Hanselmann
359 b9955569 René Nussbaumer
def UploadData(node, data, mode=0600, filename=None):
360 b9955569 René Nussbaumer
  """Uploads data to a node and returns the filename.
361 b9955569 René Nussbaumer

362 b9955569 René Nussbaumer
  Caller needs to remove the returned file on the node when it's not needed
363 b9955569 René Nussbaumer
  anymore.
364 b9955569 René Nussbaumer

365 b9955569 René Nussbaumer
  """
366 b9955569 René Nussbaumer
  if filename:
367 b9955569 René Nussbaumer
    tmp = "tmp=%s" % utils.ShellQuote(filename)
368 b9955569 René Nussbaumer
  else:
369 b9955569 René Nussbaumer
    tmp = "tmp=$(tempfile --mode %o --prefix gnt)" % mode
370 b9955569 René Nussbaumer
  cmd = ("%s && "
371 b9955569 René Nussbaumer
         "[[ -f \"${tmp}\" ]] && "
372 b9955569 René Nussbaumer
         "cat > \"${tmp}\" && "
373 b9955569 René Nussbaumer
         "echo \"${tmp}\"") % tmp
374 b9955569 René Nussbaumer
375 b9955569 René Nussbaumer
  p = subprocess.Popen(GetSSHCommand(node, cmd), shell=False,
376 b9955569 René Nussbaumer
                       stdin=subprocess.PIPE, stdout=subprocess.PIPE)
377 b9955569 René Nussbaumer
  p.stdin.write(data)
378 b9955569 René Nussbaumer
  p.stdin.close()
379 b9955569 René Nussbaumer
  AssertEqual(p.wait(), 0)
380 b9955569 René Nussbaumer
381 b9955569 René Nussbaumer
  # Return temporary filename
382 b9955569 René Nussbaumer
  return p.stdout.read().strip()
383 b9955569 René Nussbaumer
384 b9955569 René Nussbaumer
385 49d50e52 Michael Hanselmann
def BackupFile(node, path):
386 49d50e52 Michael Hanselmann
  """Creates a backup of a file on the node and returns the filename.
387 49d50e52 Michael Hanselmann

388 49d50e52 Michael Hanselmann
  Caller needs to remove the returned file on the node when it's not needed
389 49d50e52 Michael Hanselmann
  anymore.
390 49d50e52 Michael Hanselmann

391 49d50e52 Michael Hanselmann
  """
392 49d50e52 Michael Hanselmann
  cmd = ("tmp=$(tempfile --prefix .gnt --directory=$(dirname %s)) && "
393 49d50e52 Michael Hanselmann
         "[[ -f \"$tmp\" ]] && "
394 49d50e52 Michael Hanselmann
         "cp %s $tmp && "
395 49d50e52 Michael Hanselmann
         "echo $tmp") % (utils.ShellQuote(path), utils.ShellQuote(path))
396 49d50e52 Michael Hanselmann
397 49d50e52 Michael Hanselmann
  # Return temporary filename
398 49d50e52 Michael Hanselmann
  return GetCommandOutput(node, cmd).strip()
399 49d50e52 Michael Hanselmann
400 49d50e52 Michael Hanselmann
401 4b62db14 Michael Hanselmann
def _ResolveName(cmd, key):
402 4b62db14 Michael Hanselmann
  """Helper function.
403 4b62db14 Michael Hanselmann

404 4b62db14 Michael Hanselmann
  """
405 4b62db14 Michael Hanselmann
  master = qa_config.GetMasterNode()
406 4b62db14 Michael Hanselmann
407 d0c8c01d Iustin Pop
  output = GetCommandOutput(master["primary"], utils.ShellQuoteArgs(cmd))
408 4b62db14 Michael Hanselmann
  for line in output.splitlines():
409 d0c8c01d Iustin Pop
    (lkey, lvalue) = line.split(":", 1)
410 4b62db14 Michael Hanselmann
    if lkey == key:
411 4b62db14 Michael Hanselmann
      return lvalue.lstrip()
412 4b62db14 Michael Hanselmann
  raise KeyError("Key not found")
413 4b62db14 Michael Hanselmann
414 4b62db14 Michael Hanselmann
415 5d640672 Michael Hanselmann
def ResolveInstanceName(instance):
416 5d640672 Michael Hanselmann
  """Gets the full name of an instance.
417 5d640672 Michael Hanselmann

418 46f9a948 Michael Hanselmann
  @type instance: string
419 46f9a948 Michael Hanselmann
  @param instance: Instance name
420 46f9a948 Michael Hanselmann

421 5d640672 Michael Hanselmann
  """
422 d0c8c01d Iustin Pop
  return _ResolveName(["gnt-instance", "info", instance],
423 d0c8c01d Iustin Pop
                      "Instance name")
424 4b62db14 Michael Hanselmann
425 4b62db14 Michael Hanselmann
426 4b62db14 Michael Hanselmann
def ResolveNodeName(node):
427 4b62db14 Michael Hanselmann
  """Gets the full name of a node.
428 4b62db14 Michael Hanselmann

429 4b62db14 Michael Hanselmann
  """
430 d0c8c01d Iustin Pop
  return _ResolveName(["gnt-node", "info", node["primary"]],
431 d0c8c01d Iustin Pop
                      "Node name")
432 4b62db14 Michael Hanselmann
433 4b62db14 Michael Hanselmann
434 4b62db14 Michael Hanselmann
def GetNodeInstances(node, secondaries=False):
435 4b62db14 Michael Hanselmann
  """Gets a list of instances on a node.
436 4b62db14 Michael Hanselmann

437 4b62db14 Michael Hanselmann
  """
438 5d640672 Michael Hanselmann
  master = qa_config.GetMasterNode()
439 4b62db14 Michael Hanselmann
  node_name = ResolveNodeName(node)
440 5d640672 Michael Hanselmann
441 4b62db14 Michael Hanselmann
  # Get list of all instances
442 d0c8c01d Iustin Pop
  cmd = ["gnt-instance", "list", "--separator=:", "--no-headers",
443 d0c8c01d Iustin Pop
         "--output=name,pnode,snodes"]
444 d0c8c01d Iustin Pop
  output = GetCommandOutput(master["primary"], utils.ShellQuoteArgs(cmd))
445 4b62db14 Michael Hanselmann
446 4b62db14 Michael Hanselmann
  instances = []
447 4b62db14 Michael Hanselmann
  for line in output.splitlines():
448 d0c8c01d Iustin Pop
    (name, pnode, snodes) = line.split(":", 2)
449 4b62db14 Michael Hanselmann
    if ((not secondaries and pnode == node_name) or
450 d0c8c01d Iustin Pop
        (secondaries and node_name in snodes.split(","))):
451 4b62db14 Michael Hanselmann
      instances.append(name)
452 5d640672 Michael Hanselmann
453 4b62db14 Michael Hanselmann
  return instances
454 23269c5b Michael Hanselmann
455 23269c5b Michael Hanselmann
456 288d6440 Michael Hanselmann
def _SelectQueryFields(rnd, fields):
457 288d6440 Michael Hanselmann
  """Generates a list of fields for query tests.
458 288d6440 Michael Hanselmann

459 288d6440 Michael Hanselmann
  """
460 288d6440 Michael Hanselmann
  # Create copy for shuffling
461 288d6440 Michael Hanselmann
  fields = list(fields)
462 288d6440 Michael Hanselmann
  rnd.shuffle(fields)
463 288d6440 Michael Hanselmann
464 288d6440 Michael Hanselmann
  # Check all fields
465 288d6440 Michael Hanselmann
  yield fields
466 288d6440 Michael Hanselmann
  yield sorted(fields)
467 288d6440 Michael Hanselmann
468 288d6440 Michael Hanselmann
  # Duplicate fields
469 288d6440 Michael Hanselmann
  yield fields + fields
470 288d6440 Michael Hanselmann
471 288d6440 Michael Hanselmann
  # Check small groups of fields
472 288d6440 Michael Hanselmann
  while fields:
473 288d6440 Michael Hanselmann
    yield [fields.pop() for _ in range(rnd.randint(2, 10)) if fields]
474 288d6440 Michael Hanselmann
475 288d6440 Michael Hanselmann
476 288d6440 Michael Hanselmann
def _List(listcmd, fields, names):
477 288d6440 Michael Hanselmann
  """Runs a list command.
478 288d6440 Michael Hanselmann

479 288d6440 Michael Hanselmann
  """
480 288d6440 Michael Hanselmann
  master = qa_config.GetMasterNode()
481 288d6440 Michael Hanselmann
482 58ea8d17 Michael Hanselmann
  cmd = [listcmd, "list", "--separator=|", "--no-headers",
483 288d6440 Michael Hanselmann
         "--output", ",".join(fields)]
484 288d6440 Michael Hanselmann
485 288d6440 Michael Hanselmann
  if names:
486 288d6440 Michael Hanselmann
    cmd.extend(names)
487 288d6440 Michael Hanselmann
488 288d6440 Michael Hanselmann
  return GetCommandOutput(master["primary"],
489 288d6440 Michael Hanselmann
                          utils.ShellQuoteArgs(cmd)).splitlines()
490 288d6440 Michael Hanselmann
491 288d6440 Michael Hanselmann
492 6d1e4845 Michael Hanselmann
def GenericQueryTest(cmd, fields, namefield="name", test_unknown=True):
493 288d6440 Michael Hanselmann
  """Runs a number of tests on query commands.
494 288d6440 Michael Hanselmann

495 288d6440 Michael Hanselmann
  @param cmd: Command name
496 288d6440 Michael Hanselmann
  @param fields: List of field names
497 288d6440 Michael Hanselmann

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

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

571 31fe5102 René Nussbaumer
  """
572 31fe5102 René Nussbaumer
  master = qa_config.GetMasterNode()
573 31fe5102 René Nussbaumer
  tmp_hosts = UploadData(master["primary"], "", mode=0644)
574 31fe5102 René Nussbaumer
575 31fe5102 René Nussbaumer
  data = []
576 31fe5102 René Nussbaumer
  for localhost in ("::1", "127.0.0.1"):
577 31fe5102 René Nussbaumer
    data.append("%s %s" % (localhost, " ".join(hostnames)))
578 31fe5102 René Nussbaumer
579 31fe5102 René Nussbaumer
  try:
580 48967eb0 Michael Hanselmann
    AssertCommand("{ cat %s && echo -e '%s'; } > %s && mv %s %s" %
581 48967eb0 Michael Hanselmann
                  (utils.ShellQuote(pathutils.ETC_HOSTS),
582 48967eb0 Michael Hanselmann
                   "\\n".join(data),
583 48967eb0 Michael Hanselmann
                   utils.ShellQuote(tmp_hosts),
584 48967eb0 Michael Hanselmann
                   utils.ShellQuote(tmp_hosts),
585 48967eb0 Michael Hanselmann
                   utils.ShellQuote(pathutils.ETC_HOSTS)))
586 48967eb0 Michael Hanselmann
  except Exception:
587 48967eb0 Michael Hanselmann
    AssertCommand(["rm", "-f", tmp_hosts])
588 48967eb0 Michael Hanselmann
    raise
589 31fe5102 René Nussbaumer
590 31fe5102 René Nussbaumer
591 31fe5102 René Nussbaumer
def RemoveFromEtcHosts(hostnames):
592 31fe5102 René Nussbaumer
  """Remove hostnames from /etc/hosts.
593 31fe5102 René Nussbaumer

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

596 31fe5102 René Nussbaumer
  """
597 31fe5102 René Nussbaumer
  master = qa_config.GetMasterNode()
598 31fe5102 René Nussbaumer
  tmp_hosts = UploadData(master["primary"], "", mode=0644)
599 31fe5102 René Nussbaumer
  quoted_tmp_hosts = utils.ShellQuote(tmp_hosts)
600 31fe5102 René Nussbaumer
601 31fe5102 René Nussbaumer
  sed_data = " ".join(hostnames)
602 31fe5102 René Nussbaumer
  try:
603 48967eb0 Michael Hanselmann
    AssertCommand(("sed -e '/^\(::1\|127\.0\.0\.1\)\s\+%s/d' %s > %s"
604 48967eb0 Michael Hanselmann
                   " && mv %s %s") %
605 48967eb0 Michael Hanselmann
                   (sed_data, utils.ShellQuote(pathutils.ETC_HOSTS),
606 48967eb0 Michael Hanselmann
                    quoted_tmp_hosts, quoted_tmp_hosts,
607 48967eb0 Michael Hanselmann
                    utils.ShellQuote(pathutils.ETC_HOSTS)))
608 48967eb0 Michael Hanselmann
  except Exception:
609 48967eb0 Michael Hanselmann
    AssertCommand(["rm", "-f", tmp_hosts])
610 48967eb0 Michael Hanselmann
    raise
611 c9e05005 Michael Hanselmann
612 c9e05005 Michael Hanselmann
613 c9e05005 Michael Hanselmann
def RunInstanceCheck(instance, running):
614 c9e05005 Michael Hanselmann
  """Check if instance is running or not.
615 c9e05005 Michael Hanselmann

616 c9e05005 Michael Hanselmann
  """
617 889bed16 Michael Hanselmann
  instance_name = _GetName(instance, "name")
618 2ac35588 Michael Hanselmann
619 c9e05005 Michael Hanselmann
  script = qa_config.GetInstanceCheckScript()
620 c9e05005 Michael Hanselmann
  if not script:
621 c9e05005 Michael Hanselmann
    return
622 c9e05005 Michael Hanselmann
623 c9e05005 Michael Hanselmann
  master_node = qa_config.GetMasterNode()
624 c9e05005 Michael Hanselmann
625 c9e05005 Michael Hanselmann
  # Build command to connect to master node
626 c9e05005 Michael Hanselmann
  master_ssh = GetSSHCommand(master_node["primary"], "--")
627 c9e05005 Michael Hanselmann
628 c9e05005 Michael Hanselmann
  if running:
629 c9e05005 Michael Hanselmann
    running_shellval = "1"
630 c9e05005 Michael Hanselmann
    running_text = ""
631 c9e05005 Michael Hanselmann
  else:
632 c9e05005 Michael Hanselmann
    running_shellval = ""
633 c9e05005 Michael Hanselmann
    running_text = "not "
634 c9e05005 Michael Hanselmann
635 c9e05005 Michael Hanselmann
  print FormatInfo("Checking if instance '%s' is %srunning" %
636 c9e05005 Michael Hanselmann
                   (instance_name, running_text))
637 c9e05005 Michael Hanselmann
638 c9e05005 Michael Hanselmann
  args = [script, instance_name]
639 c9e05005 Michael Hanselmann
  env = {
640 c9e05005 Michael Hanselmann
    "PATH": constants.HOOKS_PATH,
641 c9e05005 Michael Hanselmann
    "RUN_UUID": _RUN_UUID,
642 c9e05005 Michael Hanselmann
    "MASTER_SSH": utils.ShellQuoteArgs(master_ssh),
643 c9e05005 Michael Hanselmann
    "INSTANCE_NAME": instance_name,
644 c9e05005 Michael Hanselmann
    "INSTANCE_RUNNING": running_shellval,
645 c9e05005 Michael Hanselmann
    }
646 c9e05005 Michael Hanselmann
647 c9e05005 Michael Hanselmann
  result = os.spawnve(os.P_WAIT, script, args, env)
648 c9e05005 Michael Hanselmann
  if result != 0:
649 c9e05005 Michael Hanselmann
    raise qa_error.Error("Instance check failed with result %s" % result)
650 c9e05005 Michael Hanselmann
651 c9e05005 Michael Hanselmann
652 c9e05005 Michael Hanselmann
def _InstanceCheckInner(expected, instarg, args, result):
653 c9e05005 Michael Hanselmann
  """Helper function used by L{InstanceCheck}.
654 c9e05005 Michael Hanselmann

655 c9e05005 Michael Hanselmann
  """
656 c9e05005 Michael Hanselmann
  if instarg == FIRST_ARG:
657 c9e05005 Michael Hanselmann
    instance = args[0]
658 c9e05005 Michael Hanselmann
  elif instarg == RETURN_VALUE:
659 c9e05005 Michael Hanselmann
    instance = result
660 c9e05005 Michael Hanselmann
  else:
661 c9e05005 Michael Hanselmann
    raise Exception("Invalid value '%s' for instance argument" % instarg)
662 c9e05005 Michael Hanselmann
663 c9e05005 Michael Hanselmann
  if expected in (INST_DOWN, INST_UP):
664 c9e05005 Michael Hanselmann
    RunInstanceCheck(instance, (expected == INST_UP))
665 c9e05005 Michael Hanselmann
  elif expected is not None:
666 c9e05005 Michael Hanselmann
    raise Exception("Invalid value '%s'" % expected)
667 c9e05005 Michael Hanselmann
668 c9e05005 Michael Hanselmann
669 c9e05005 Michael Hanselmann
def InstanceCheck(before, after, instarg):
670 c9e05005 Michael Hanselmann
  """Decorator to check instance status before and after test.
671 c9e05005 Michael Hanselmann

672 c9e05005 Michael Hanselmann
  @param before: L{INST_DOWN} if instance must be stopped before test,
673 c9e05005 Michael Hanselmann
    L{INST_UP} if instance must be running before test, L{None} to not check.
674 c9e05005 Michael Hanselmann
  @param after: L{INST_DOWN} if instance must be stopped after test,
675 c9e05005 Michael Hanselmann
    L{INST_UP} if instance must be running after test, L{None} to not check.
676 c9e05005 Michael Hanselmann
  @param instarg: L{FIRST_ARG} to use first argument to test as instance (a
677 c9e05005 Michael Hanselmann
    dictionary), L{RETURN_VALUE} to use return value (disallows pre-checks)
678 c9e05005 Michael Hanselmann

679 c9e05005 Michael Hanselmann
  """
680 c9e05005 Michael Hanselmann
  def decorator(fn):
681 c9e05005 Michael Hanselmann
    @functools.wraps(fn)
682 c9e05005 Michael Hanselmann
    def wrapper(*args, **kwargs):
683 c9e05005 Michael Hanselmann
      _InstanceCheckInner(before, instarg, args, NotImplemented)
684 c9e05005 Michael Hanselmann
685 c9e05005 Michael Hanselmann
      result = fn(*args, **kwargs)
686 c9e05005 Michael Hanselmann
687 c9e05005 Michael Hanselmann
      _InstanceCheckInner(after, instarg, args, result)
688 c9e05005 Michael Hanselmann
689 c9e05005 Michael Hanselmann
      return result
690 c9e05005 Michael Hanselmann
    return wrapper
691 c9e05005 Michael Hanselmann
  return decorator
692 b4d2d2cb Michael Hanselmann
693 b4d2d2cb Michael Hanselmann
694 b4d2d2cb Michael Hanselmann
def GetNonexistentGroups(count):
695 b4d2d2cb Michael Hanselmann
  """Gets group names which shouldn't exist on the cluster.
696 b4d2d2cb Michael Hanselmann

697 b4d2d2cb Michael Hanselmann
  @param count: Number of groups to get
698 ea7693c1 Helga Velroyen
  @rtype: integer
699 b4d2d2cb Michael Hanselmann

700 b4d2d2cb Michael Hanselmann
  """
701 ea7693c1 Helga Velroyen
  return GetNonexistentEntityNames(count, "groups", "group")
702 b4d2d2cb Michael Hanselmann
703 ea7693c1 Helga Velroyen
704 ea7693c1 Helga Velroyen
def GetNonexistentEntityNames(count, name_config, name_prefix):
705 ea7693c1 Helga Velroyen
  """Gets entity names which shouldn't exist on the cluster.
706 ea7693c1 Helga Velroyen

707 ea7693c1 Helga Velroyen
  The actualy names can refer to arbitrary entities (for example
708 ea7693c1 Helga Velroyen
  groups, networks).
709 ea7693c1 Helga Velroyen

710 ea7693c1 Helga Velroyen
  @param count: Number of names to get
711 ea7693c1 Helga Velroyen
  @rtype: integer
712 ea7693c1 Helga Velroyen
  @param name_config: name of the leaf in the config containing
713 ea7693c1 Helga Velroyen
    this entity's configuration, including a 'inexistent-'
714 ea7693c1 Helga Velroyen
    element
715 ea7693c1 Helga Velroyen
  @rtype: string
716 ea7693c1 Helga Velroyen
  @param name_prefix: prefix of the entity's names, used to compose
717 ea7693c1 Helga Velroyen
    the default values; for example for groups, the prefix is
718 ea7693c1 Helga Velroyen
    'group' and the generated names are then group1, group2, ...
719 ea7693c1 Helga Velroyen
  @rtype: string
720 ea7693c1 Helga Velroyen

721 ea7693c1 Helga Velroyen
  """
722 ea7693c1 Helga Velroyen
  entities = qa_config.get(name_config, {})
723 ea7693c1 Helga Velroyen
724 ea7693c1 Helga Velroyen
  default = [name_prefix + str(i) for i in range(count)]
725 b4d2d2cb Michael Hanselmann
  assert count <= len(default)
726 b4d2d2cb Michael Hanselmann
727 ea7693c1 Helga Velroyen
  name_config_inexistent = "inexistent-" + name_config
728 ea7693c1 Helga Velroyen
  candidates = entities.get(name_config_inexistent, default)[:count]
729 b4d2d2cb Michael Hanselmann
730 b4d2d2cb Michael Hanselmann
  if len(candidates) < count:
731 ea7693c1 Helga Velroyen
    raise Exception("At least %s non-existent %s are needed" %
732 ea7693c1 Helga Velroyen
                    (count, name_config))
733 b4d2d2cb Michael Hanselmann
734 b4d2d2cb Michael Hanselmann
  return candidates