Statistics
| Branch: | Tag: | Revision:

root / qa / qa_utils.py @ ff699aa9

History | View | Annotate | Download (11.9 kB)

1 c68d1f43 Michael Hanselmann
#
2 c68d1f43 Michael Hanselmann
#
3 c68d1f43 Michael Hanselmann
4 f7e6f3c8 Iustin Pop
# Copyright (C) 2007, 2011 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 cec9845c Michael Hanselmann
from ganeti import utils
34 288d6440 Michael Hanselmann
from ganeti import compat
35 2214cf14 Michael Hanselmann
from ganeti import constants
36 cec9845c Michael Hanselmann
37 cec9845c Michael Hanselmann
import qa_config
38 cec9845c Michael Hanselmann
import qa_error
39 cec9845c Michael Hanselmann
40 cec9845c Michael Hanselmann
41 23269c5b Michael Hanselmann
_INFO_SEQ = None
42 23269c5b Michael Hanselmann
_WARNING_SEQ = None
43 23269c5b Michael Hanselmann
_ERROR_SEQ = None
44 23269c5b Michael Hanselmann
_RESET_SEQ = None
45 23269c5b Michael Hanselmann
46 f7e6f3c8 Iustin Pop
_MULTIPLEXERS = {}
47 f7e6f3c8 Iustin Pop
48 23269c5b Michael Hanselmann
49 23269c5b Michael Hanselmann
def _SetupColours():
50 23269c5b Michael Hanselmann
  """Initializes the colour constants.
51 23269c5b Michael Hanselmann

52 23269c5b Michael Hanselmann
  """
53 3582eef6 Iustin Pop
  # pylint: disable-msg=W0603
54 3582eef6 Iustin Pop
  # due to global usage
55 23269c5b Michael Hanselmann
  global _INFO_SEQ, _WARNING_SEQ, _ERROR_SEQ, _RESET_SEQ
56 23269c5b Michael Hanselmann
57 dfe11bad Michael Hanselmann
  # Don't use colours if stdout isn't a terminal
58 dfe11bad Michael Hanselmann
  if not sys.stdout.isatty():
59 dfe11bad Michael Hanselmann
    return
60 dfe11bad Michael Hanselmann
61 23269c5b Michael Hanselmann
  try:
62 23269c5b Michael Hanselmann
    import curses
63 23269c5b Michael Hanselmann
  except ImportError:
64 23269c5b Michael Hanselmann
    # Don't use colours if curses module can't be imported
65 23269c5b Michael Hanselmann
    return
66 23269c5b Michael Hanselmann
67 23269c5b Michael Hanselmann
  curses.setupterm()
68 23269c5b Michael Hanselmann
69 23269c5b Michael Hanselmann
  _RESET_SEQ = curses.tigetstr("op")
70 23269c5b Michael Hanselmann
71 23269c5b Michael Hanselmann
  setaf = curses.tigetstr("setaf")
72 23269c5b Michael Hanselmann
  _INFO_SEQ = curses.tparm(setaf, curses.COLOR_GREEN)
73 23269c5b Michael Hanselmann
  _WARNING_SEQ = curses.tparm(setaf, curses.COLOR_YELLOW)
74 23269c5b Michael Hanselmann
  _ERROR_SEQ = curses.tparm(setaf, curses.COLOR_RED)
75 23269c5b Michael Hanselmann
76 23269c5b Michael Hanselmann
77 23269c5b Michael Hanselmann
_SetupColours()
78 23269c5b Michael Hanselmann
79 23269c5b Michael Hanselmann
80 eaef8a05 Michael Hanselmann
def AssertIn(item, sequence):
81 eaef8a05 Michael Hanselmann
  """Raises an error when item is not in sequence.
82 eaef8a05 Michael Hanselmann

83 eaef8a05 Michael Hanselmann
  """
84 eaef8a05 Michael Hanselmann
  if item not in sequence:
85 eaef8a05 Michael Hanselmann
    raise qa_error.Error('%r not in %r' % (item, sequence))
86 eaef8a05 Michael Hanselmann
87 eaef8a05 Michael Hanselmann
88 e8ae0c20 Michael Hanselmann
def AssertEqual(first, second):
89 cec9845c Michael Hanselmann
  """Raises an error when values aren't equal.
90 cec9845c Michael Hanselmann

91 cec9845c Michael Hanselmann
  """
92 cec9845c Michael Hanselmann
  if not first == second:
93 e8ae0c20 Michael Hanselmann
    raise qa_error.Error('%r == %r' % (first, second))
94 e8ae0c20 Michael Hanselmann
95 e8ae0c20 Michael Hanselmann
96 e8ae0c20 Michael Hanselmann
def AssertNotEqual(first, second):
97 e8ae0c20 Michael Hanselmann
  """Raises an error when values are equal.
98 e8ae0c20 Michael Hanselmann

99 e8ae0c20 Michael Hanselmann
  """
100 e8ae0c20 Michael Hanselmann
  if not first != second:
101 e8ae0c20 Michael Hanselmann
    raise qa_error.Error('%r != %r' % (first, second))
102 cec9845c Michael Hanselmann
103 cec9845c Michael Hanselmann
104 e6ce18ac René Nussbaumer
def AssertMatch(string, pattern):
105 e6ce18ac René Nussbaumer
  """Raises an error when string doesn't match regexp pattern.
106 e6ce18ac René Nussbaumer

107 e6ce18ac René Nussbaumer
  """
108 e6ce18ac René Nussbaumer
  if not re.match(pattern, string):
109 e6ce18ac René Nussbaumer
    raise qa_error.Error("%r doesn't match /%r/" % (string, pattern))
110 e6ce18ac René Nussbaumer
111 e6ce18ac René Nussbaumer
112 2f4b4f78 Iustin Pop
def AssertCommand(cmd, fail=False, node=None):
113 2f4b4f78 Iustin Pop
  """Checks that a remote command succeeds.
114 2f4b4f78 Iustin Pop

115 2f4b4f78 Iustin Pop
  @param cmd: either a string (the command to execute) or a list (to
116 2f4b4f78 Iustin Pop
      be converted using L{utils.ShellQuoteArgs} into a string)
117 2f4b4f78 Iustin Pop
  @type fail: boolean
118 2f4b4f78 Iustin Pop
  @param fail: if the command is expected to fail instead of succeeding
119 2f4b4f78 Iustin Pop
  @param node: if passed, it should be the node on which the command
120 2f4b4f78 Iustin Pop
      should be executed, instead of the master node (can be either a
121 2f4b4f78 Iustin Pop
      dict or a string)
122 2f4b4f78 Iustin Pop

123 2f4b4f78 Iustin Pop
  """
124 2f4b4f78 Iustin Pop
  if node is None:
125 2f4b4f78 Iustin Pop
    node = qa_config.GetMasterNode()
126 2f4b4f78 Iustin Pop
127 2f4b4f78 Iustin Pop
  if isinstance(node, basestring):
128 2f4b4f78 Iustin Pop
    nodename = node
129 2f4b4f78 Iustin Pop
  else:
130 2f4b4f78 Iustin Pop
    nodename = node["primary"]
131 2f4b4f78 Iustin Pop
132 2f4b4f78 Iustin Pop
  if isinstance(cmd, basestring):
133 2f4b4f78 Iustin Pop
    cmdstr = cmd
134 2f4b4f78 Iustin Pop
  else:
135 2f4b4f78 Iustin Pop
    cmdstr = utils.ShellQuoteArgs(cmd)
136 2f4b4f78 Iustin Pop
137 2f4b4f78 Iustin Pop
  rcode = StartSSH(nodename, cmdstr).wait()
138 2f4b4f78 Iustin Pop
139 2f4b4f78 Iustin Pop
  if fail:
140 2f4b4f78 Iustin Pop
    if rcode == 0:
141 2f4b4f78 Iustin Pop
      raise qa_error.Error("Command '%s' on node %s was expected to fail but"
142 2f4b4f78 Iustin Pop
                           " didn't" % (cmdstr, nodename))
143 2f4b4f78 Iustin Pop
  else:
144 2f4b4f78 Iustin Pop
    if rcode != 0:
145 2f4b4f78 Iustin Pop
      raise qa_error.Error("Command '%s' on node %s failed, exit code %s" %
146 2f4b4f78 Iustin Pop
                           (cmdstr, nodename, rcode))
147 2f4b4f78 Iustin Pop
148 2214cf14 Michael Hanselmann
  return rcode
149 2214cf14 Michael Hanselmann
150 2f4b4f78 Iustin Pop
151 50265802 René Nussbaumer
def GetSSHCommand(node, cmd, strict=True, opts=None, tty=True):
152 cec9845c Michael Hanselmann
  """Builds SSH command to be executed.
153 cec9845c Michael Hanselmann

154 0a05f959 Adeodato Simo
  @type node: string
155 0a05f959 Adeodato Simo
  @param node: node the command should run on
156 0a05f959 Adeodato Simo
  @type cmd: string
157 f7e6f3c8 Iustin Pop
  @param cmd: command to be executed in the node; if None or empty
158 f7e6f3c8 Iustin Pop
      string, no command will be executed
159 0a05f959 Adeodato Simo
  @type strict: boolean
160 0a05f959 Adeodato Simo
  @param strict: whether to enable strict host key checking
161 f7e6f3c8 Iustin Pop
  @type opts: list
162 f7e6f3c8 Iustin Pop
  @param opts: list of additional options
163 50265802 René Nussbaumer
  @type tty: Bool
164 50265802 René Nussbaumer
  @param tty: If we should use tty
165 c68d1f43 Michael Hanselmann

166 cec9845c Michael Hanselmann
  """
167 50265802 René Nussbaumer
  args = ["ssh", "-oEscapeChar=none", "-oBatchMode=yes", "-l", "root"]
168 50265802 René Nussbaumer
169 50265802 René Nussbaumer
  if tty:
170 50265802 René Nussbaumer
    args.append("-t")
171 cec9845c Michael Hanselmann
172 cec9845c Michael Hanselmann
  if strict:
173 cec9845c Michael Hanselmann
    tmp = 'yes'
174 cec9845c Michael Hanselmann
  else:
175 cec9845c Michael Hanselmann
    tmp = 'no'
176 cec9845c Michael Hanselmann
  args.append('-oStrictHostKeyChecking=%s' % tmp)
177 cec9845c Michael Hanselmann
  args.append('-oClearAllForwardings=yes')
178 cec9845c Michael Hanselmann
  args.append('-oForwardAgent=yes')
179 f7e6f3c8 Iustin Pop
  if opts:
180 f7e6f3c8 Iustin Pop
    args.extend(opts)
181 f7e6f3c8 Iustin Pop
  if node in _MULTIPLEXERS:
182 f7e6f3c8 Iustin Pop
    spath = _MULTIPLEXERS[node][0]
183 f7e6f3c8 Iustin Pop
    args.append('-oControlPath=%s' % spath)
184 f7e6f3c8 Iustin Pop
    args.append('-oControlMaster=no')
185 cec9845c Michael Hanselmann
  args.append(node)
186 f7e6f3c8 Iustin Pop
  if cmd:
187 f7e6f3c8 Iustin Pop
    args.append(cmd)
188 cec9845c Michael Hanselmann
189 cec9845c Michael Hanselmann
  return args
190 cec9845c Michael Hanselmann
191 cec9845c Michael Hanselmann
192 5d831182 Michael Hanselmann
def StartLocalCommand(cmd, **kwargs):
193 5d831182 Michael Hanselmann
  """Starts a local command.
194 5d831182 Michael Hanselmann

195 5d831182 Michael Hanselmann
  """
196 5d831182 Michael Hanselmann
  print "Command: %s" % utils.ShellQuoteArgs(cmd)
197 5d831182 Michael Hanselmann
  return subprocess.Popen(cmd, shell=False, **kwargs)
198 5d831182 Michael Hanselmann
199 5d831182 Michael Hanselmann
200 cec9845c Michael Hanselmann
def StartSSH(node, cmd, strict=True):
201 cec9845c Michael Hanselmann
  """Starts SSH.
202 cec9845c Michael Hanselmann

203 cec9845c Michael Hanselmann
  """
204 5d831182 Michael Hanselmann
  return StartLocalCommand(GetSSHCommand(node, cmd, strict=strict))
205 4b62db14 Michael Hanselmann
206 4b62db14 Michael Hanselmann
207 f7e6f3c8 Iustin Pop
def StartMultiplexer(node):
208 f7e6f3c8 Iustin Pop
  """Starts a multiplexer command.
209 f7e6f3c8 Iustin Pop

210 f7e6f3c8 Iustin Pop
  @param node: the node for which to open the multiplexer
211 f7e6f3c8 Iustin Pop

212 f7e6f3c8 Iustin Pop
  """
213 f7e6f3c8 Iustin Pop
  if node in _MULTIPLEXERS:
214 f7e6f3c8 Iustin Pop
    return
215 f7e6f3c8 Iustin Pop
216 f7e6f3c8 Iustin Pop
  # Note: yes, we only need mktemp, since we'll remove the file anyway
217 f7e6f3c8 Iustin Pop
  sname = tempfile.mktemp(prefix="ganeti-qa-multiplexer.")
218 f7e6f3c8 Iustin Pop
  utils.RemoveFile(sname)
219 f7e6f3c8 Iustin Pop
  opts = ["-N", "-oControlPath=%s" % sname, "-oControlMaster=yes"]
220 f7e6f3c8 Iustin Pop
  print "Created socket at %s" % sname
221 f7e6f3c8 Iustin Pop
  child = StartLocalCommand(GetSSHCommand(node, None, opts=opts))
222 f7e6f3c8 Iustin Pop
  _MULTIPLEXERS[node] = (sname, child)
223 f7e6f3c8 Iustin Pop
224 f7e6f3c8 Iustin Pop
225 f7e6f3c8 Iustin Pop
def CloseMultiplexers():
226 f7e6f3c8 Iustin Pop
  """Closes all current multiplexers and cleans up.
227 f7e6f3c8 Iustin Pop

228 f7e6f3c8 Iustin Pop
  """
229 f7e6f3c8 Iustin Pop
  for node in _MULTIPLEXERS.keys():
230 f7e6f3c8 Iustin Pop
    (sname, child) = _MULTIPLEXERS.pop(node)
231 f7e6f3c8 Iustin Pop
    utils.KillProcess(child.pid, timeout=10, waitpid=True)
232 f7e6f3c8 Iustin Pop
    utils.RemoveFile(sname)
233 f7e6f3c8 Iustin Pop
234 f7e6f3c8 Iustin Pop
235 50265802 René Nussbaumer
def GetCommandOutput(node, cmd, tty=True):
236 4b62db14 Michael Hanselmann
  """Returns the output of a command executed on the given node.
237 4b62db14 Michael Hanselmann

238 4b62db14 Michael Hanselmann
  """
239 50265802 René Nussbaumer
  p = StartLocalCommand(GetSSHCommand(node, cmd, tty=tty),
240 50265802 René Nussbaumer
                        stdout=subprocess.PIPE)
241 4b62db14 Michael Hanselmann
  AssertEqual(p.wait(), 0)
242 4b62db14 Michael Hanselmann
  return p.stdout.read()
243 cec9845c Michael Hanselmann
244 cec9845c Michael Hanselmann
245 cec9845c Michael Hanselmann
def UploadFile(node, src):
246 cec9845c Michael Hanselmann
  """Uploads a file to a node and returns the filename.
247 cec9845c Michael Hanselmann

248 cec9845c Michael Hanselmann
  Caller needs to remove the returned file on the node when it's not needed
249 cec9845c Michael Hanselmann
  anymore.
250 49d50e52 Michael Hanselmann

251 cec9845c Michael Hanselmann
  """
252 cec9845c Michael Hanselmann
  # Make sure nobody else has access to it while preserving local permissions
253 cec9845c Michael Hanselmann
  mode = os.stat(src).st_mode & 0700
254 cec9845c Michael Hanselmann
255 cec9845c Michael Hanselmann
  cmd = ('tmp=$(tempfile --mode %o --prefix gnt) && '
256 cec9845c Michael Hanselmann
         '[[ -f "${tmp}" ]] && '
257 cec9845c Michael Hanselmann
         'cat > "${tmp}" && '
258 cec9845c Michael Hanselmann
         'echo "${tmp}"') % mode
259 cec9845c Michael Hanselmann
260 cec9845c Michael Hanselmann
  f = open(src, 'r')
261 cec9845c Michael Hanselmann
  try:
262 cec9845c Michael Hanselmann
    p = subprocess.Popen(GetSSHCommand(node, cmd), shell=False, stdin=f,
263 cec9845c Michael Hanselmann
                         stdout=subprocess.PIPE)
264 cec9845c Michael Hanselmann
    AssertEqual(p.wait(), 0)
265 cec9845c Michael Hanselmann
266 cec9845c Michael Hanselmann
    # Return temporary filename
267 cec9845c Michael Hanselmann
    return p.stdout.read().strip()
268 cec9845c Michael Hanselmann
  finally:
269 cec9845c Michael Hanselmann
    f.close()
270 5d640672 Michael Hanselmann
271 5d640672 Michael Hanselmann
272 b9955569 René Nussbaumer
def UploadData(node, data, mode=0600, filename=None):
273 b9955569 René Nussbaumer
  """Uploads data to a node and returns the filename.
274 b9955569 René Nussbaumer

275 b9955569 René Nussbaumer
  Caller needs to remove the returned file on the node when it's not needed
276 b9955569 René Nussbaumer
  anymore.
277 b9955569 René Nussbaumer

278 b9955569 René Nussbaumer
  """
279 b9955569 René Nussbaumer
  if filename:
280 b9955569 René Nussbaumer
    tmp = "tmp=%s" % utils.ShellQuote(filename)
281 b9955569 René Nussbaumer
  else:
282 b9955569 René Nussbaumer
    tmp = "tmp=$(tempfile --mode %o --prefix gnt)" % mode
283 b9955569 René Nussbaumer
  cmd = ("%s && "
284 b9955569 René Nussbaumer
         "[[ -f \"${tmp}\" ]] && "
285 b9955569 René Nussbaumer
         "cat > \"${tmp}\" && "
286 b9955569 René Nussbaumer
         "echo \"${tmp}\"") % tmp
287 b9955569 René Nussbaumer
288 b9955569 René Nussbaumer
  p = subprocess.Popen(GetSSHCommand(node, cmd), shell=False,
289 b9955569 René Nussbaumer
                       stdin=subprocess.PIPE, stdout=subprocess.PIPE)
290 b9955569 René Nussbaumer
  p.stdin.write(data)
291 b9955569 René Nussbaumer
  p.stdin.close()
292 b9955569 René Nussbaumer
  AssertEqual(p.wait(), 0)
293 b9955569 René Nussbaumer
294 b9955569 René Nussbaumer
  # Return temporary filename
295 b9955569 René Nussbaumer
  return p.stdout.read().strip()
296 b9955569 René Nussbaumer
297 b9955569 René Nussbaumer
298 49d50e52 Michael Hanselmann
def BackupFile(node, path):
299 49d50e52 Michael Hanselmann
  """Creates a backup of a file on the node and returns the filename.
300 49d50e52 Michael Hanselmann

301 49d50e52 Michael Hanselmann
  Caller needs to remove the returned file on the node when it's not needed
302 49d50e52 Michael Hanselmann
  anymore.
303 49d50e52 Michael Hanselmann

304 49d50e52 Michael Hanselmann
  """
305 49d50e52 Michael Hanselmann
  cmd = ("tmp=$(tempfile --prefix .gnt --directory=$(dirname %s)) && "
306 49d50e52 Michael Hanselmann
         "[[ -f \"$tmp\" ]] && "
307 49d50e52 Michael Hanselmann
         "cp %s $tmp && "
308 49d50e52 Michael Hanselmann
         "echo $tmp") % (utils.ShellQuote(path), utils.ShellQuote(path))
309 49d50e52 Michael Hanselmann
310 49d50e52 Michael Hanselmann
  # Return temporary filename
311 49d50e52 Michael Hanselmann
  return GetCommandOutput(node, cmd).strip()
312 49d50e52 Michael Hanselmann
313 49d50e52 Michael Hanselmann
314 4b62db14 Michael Hanselmann
def _ResolveName(cmd, key):
315 4b62db14 Michael Hanselmann
  """Helper function.
316 4b62db14 Michael Hanselmann

317 4b62db14 Michael Hanselmann
  """
318 4b62db14 Michael Hanselmann
  master = qa_config.GetMasterNode()
319 4b62db14 Michael Hanselmann
320 4b62db14 Michael Hanselmann
  output = GetCommandOutput(master['primary'], utils.ShellQuoteArgs(cmd))
321 4b62db14 Michael Hanselmann
  for line in output.splitlines():
322 4b62db14 Michael Hanselmann
    (lkey, lvalue) = line.split(':', 1)
323 4b62db14 Michael Hanselmann
    if lkey == key:
324 4b62db14 Michael Hanselmann
      return lvalue.lstrip()
325 4b62db14 Michael Hanselmann
  raise KeyError("Key not found")
326 4b62db14 Michael Hanselmann
327 4b62db14 Michael Hanselmann
328 5d640672 Michael Hanselmann
def ResolveInstanceName(instance):
329 5d640672 Michael Hanselmann
  """Gets the full name of an instance.
330 5d640672 Michael Hanselmann

331 46f9a948 Michael Hanselmann
  @type instance: string
332 46f9a948 Michael Hanselmann
  @param instance: Instance name
333 46f9a948 Michael Hanselmann

334 5d640672 Michael Hanselmann
  """
335 46f9a948 Michael Hanselmann
  return _ResolveName(['gnt-instance', 'info', instance],
336 4b62db14 Michael Hanselmann
                      'Instance name')
337 4b62db14 Michael Hanselmann
338 4b62db14 Michael Hanselmann
339 4b62db14 Michael Hanselmann
def ResolveNodeName(node):
340 4b62db14 Michael Hanselmann
  """Gets the full name of a node.
341 4b62db14 Michael Hanselmann

342 4b62db14 Michael Hanselmann
  """
343 4b62db14 Michael Hanselmann
  return _ResolveName(['gnt-node', 'info', node['primary']],
344 4b62db14 Michael Hanselmann
                      'Node name')
345 4b62db14 Michael Hanselmann
346 4b62db14 Michael Hanselmann
347 4b62db14 Michael Hanselmann
def GetNodeInstances(node, secondaries=False):
348 4b62db14 Michael Hanselmann
  """Gets a list of instances on a node.
349 4b62db14 Michael Hanselmann

350 4b62db14 Michael Hanselmann
  """
351 5d640672 Michael Hanselmann
  master = qa_config.GetMasterNode()
352 4b62db14 Michael Hanselmann
  node_name = ResolveNodeName(node)
353 5d640672 Michael Hanselmann
354 4b62db14 Michael Hanselmann
  # Get list of all instances
355 4b62db14 Michael Hanselmann
  cmd = ['gnt-instance', 'list', '--separator=:', '--no-headers',
356 4b62db14 Michael Hanselmann
         '--output=name,pnode,snodes']
357 4b62db14 Michael Hanselmann
  output = GetCommandOutput(master['primary'], utils.ShellQuoteArgs(cmd))
358 4b62db14 Michael Hanselmann
359 4b62db14 Michael Hanselmann
  instances = []
360 4b62db14 Michael Hanselmann
  for line in output.splitlines():
361 4b62db14 Michael Hanselmann
    (name, pnode, snodes) = line.split(':', 2)
362 4b62db14 Michael Hanselmann
    if ((not secondaries and pnode == node_name) or
363 4b62db14 Michael Hanselmann
        (secondaries and node_name in snodes.split(','))):
364 4b62db14 Michael Hanselmann
      instances.append(name)
365 5d640672 Michael Hanselmann
366 4b62db14 Michael Hanselmann
  return instances
367 23269c5b Michael Hanselmann
368 23269c5b Michael Hanselmann
369 288d6440 Michael Hanselmann
def _SelectQueryFields(rnd, fields):
370 288d6440 Michael Hanselmann
  """Generates a list of fields for query tests.
371 288d6440 Michael Hanselmann

372 288d6440 Michael Hanselmann
  """
373 288d6440 Michael Hanselmann
  # Create copy for shuffling
374 288d6440 Michael Hanselmann
  fields = list(fields)
375 288d6440 Michael Hanselmann
  rnd.shuffle(fields)
376 288d6440 Michael Hanselmann
377 288d6440 Michael Hanselmann
  # Check all fields
378 288d6440 Michael Hanselmann
  yield fields
379 288d6440 Michael Hanselmann
  yield sorted(fields)
380 288d6440 Michael Hanselmann
381 288d6440 Michael Hanselmann
  # Duplicate fields
382 288d6440 Michael Hanselmann
  yield fields + fields
383 288d6440 Michael Hanselmann
384 288d6440 Michael Hanselmann
  # Check small groups of fields
385 288d6440 Michael Hanselmann
  while fields:
386 288d6440 Michael Hanselmann
    yield [fields.pop() for _ in range(rnd.randint(2, 10)) if fields]
387 288d6440 Michael Hanselmann
388 288d6440 Michael Hanselmann
389 288d6440 Michael Hanselmann
def _List(listcmd, fields, names):
390 288d6440 Michael Hanselmann
  """Runs a list command.
391 288d6440 Michael Hanselmann

392 288d6440 Michael Hanselmann
  """
393 288d6440 Michael Hanselmann
  master = qa_config.GetMasterNode()
394 288d6440 Michael Hanselmann
395 288d6440 Michael Hanselmann
  cmd = [listcmd, "list", "--separator=|", "--no-header",
396 288d6440 Michael Hanselmann
         "--output", ",".join(fields)]
397 288d6440 Michael Hanselmann
398 288d6440 Michael Hanselmann
  if names:
399 288d6440 Michael Hanselmann
    cmd.extend(names)
400 288d6440 Michael Hanselmann
401 288d6440 Michael Hanselmann
  return GetCommandOutput(master["primary"],
402 288d6440 Michael Hanselmann
                          utils.ShellQuoteArgs(cmd)).splitlines()
403 288d6440 Michael Hanselmann
404 288d6440 Michael Hanselmann
405 288d6440 Michael Hanselmann
def GenericQueryTest(cmd, fields):
406 288d6440 Michael Hanselmann
  """Runs a number of tests on query commands.
407 288d6440 Michael Hanselmann

408 288d6440 Michael Hanselmann
  @param cmd: Command name
409 288d6440 Michael Hanselmann
  @param fields: List of field names
410 288d6440 Michael Hanselmann

411 288d6440 Michael Hanselmann
  """
412 288d6440 Michael Hanselmann
  rnd = random.Random(hash(cmd))
413 288d6440 Michael Hanselmann
414 3582eef6 Iustin Pop
  fields = list(fields)
415 288d6440 Michael Hanselmann
  rnd.shuffle(fields)
416 288d6440 Michael Hanselmann
417 288d6440 Michael Hanselmann
  # Test a number of field combinations
418 288d6440 Michael Hanselmann
  for testfields in _SelectQueryFields(rnd, fields):
419 288d6440 Michael Hanselmann
    AssertCommand([cmd, "list", "--output", ",".join(testfields)])
420 288d6440 Michael Hanselmann
421 288d6440 Michael Hanselmann
  namelist_fn = compat.partial(_List, cmd, ["name"])
422 288d6440 Michael Hanselmann
423 288d6440 Michael Hanselmann
  # When no names were requested, the list must be sorted
424 288d6440 Michael Hanselmann
  names = namelist_fn(None)
425 288d6440 Michael Hanselmann
  AssertEqual(names, utils.NiceSort(names))
426 288d6440 Michael Hanselmann
427 288d6440 Michael Hanselmann
  # When requesting specific names, the order must be kept
428 288d6440 Michael Hanselmann
  revnames = list(reversed(names))
429 288d6440 Michael Hanselmann
  AssertEqual(namelist_fn(revnames), revnames)
430 288d6440 Michael Hanselmann
431 288d6440 Michael Hanselmann
  randnames = list(names)
432 288d6440 Michael Hanselmann
  rnd.shuffle(randnames)
433 288d6440 Michael Hanselmann
  AssertEqual(namelist_fn(randnames), randnames)
434 288d6440 Michael Hanselmann
435 2214cf14 Michael Hanselmann
  # Listing unknown items must fail
436 2214cf14 Michael Hanselmann
  AssertCommand([cmd, "list", "this.name.certainly.does.not.exist"], fail=True)
437 2214cf14 Michael Hanselmann
438 2214cf14 Michael Hanselmann
  # Check exit code for listing unknown field
439 2214cf14 Michael Hanselmann
  AssertEqual(AssertCommand([cmd, "list", "--output=field/does/not/exist"],
440 2214cf14 Michael Hanselmann
                            fail=True),
441 2214cf14 Michael Hanselmann
              constants.EXIT_UNKNOWN_FIELD)
442 2214cf14 Michael Hanselmann
443 2214cf14 Michael Hanselmann
444 2214cf14 Michael Hanselmann
def GenericQueryFieldsTest(cmd, fields):
445 2214cf14 Michael Hanselmann
  master = qa_config.GetMasterNode()
446 2214cf14 Michael Hanselmann
447 2214cf14 Michael Hanselmann
  # Listing fields
448 2214cf14 Michael Hanselmann
  AssertCommand([cmd, "list-fields"])
449 2214cf14 Michael Hanselmann
  AssertCommand([cmd, "list-fields"] + fields)
450 2214cf14 Michael Hanselmann
451 2214cf14 Michael Hanselmann
  # Check listed fields (all, must be sorted)
452 2214cf14 Michael Hanselmann
  realcmd = [cmd, "list-fields", "--separator=|", "--no-headers"]
453 2214cf14 Michael Hanselmann
  output = GetCommandOutput(master["primary"],
454 2214cf14 Michael Hanselmann
                            utils.ShellQuoteArgs(realcmd)).splitlines()
455 2214cf14 Michael Hanselmann
  AssertEqual([line.split("|", 1)[0] for line in output],
456 c694367b Michael Hanselmann
              utils.NiceSort(fields))
457 2214cf14 Michael Hanselmann
458 2214cf14 Michael Hanselmann
  # Check exit code for listing unknown field
459 2214cf14 Michael Hanselmann
  AssertEqual(AssertCommand([cmd, "list-fields", "field/does/not/exist"],
460 2214cf14 Michael Hanselmann
                            fail=True),
461 2214cf14 Michael Hanselmann
              constants.EXIT_UNKNOWN_FIELD)
462 2214cf14 Michael Hanselmann
463 288d6440 Michael Hanselmann
464 dfe11bad Michael Hanselmann
def _FormatWithColor(text, seq):
465 dfe11bad Michael Hanselmann
  if not seq:
466 dfe11bad Michael Hanselmann
    return text
467 dfe11bad Michael Hanselmann
  return "%s%s%s" % (seq, text, _RESET_SEQ)
468 23269c5b Michael Hanselmann
469 23269c5b Michael Hanselmann
470 dfe11bad Michael Hanselmann
FormatWarning = lambda text: _FormatWithColor(text, _WARNING_SEQ)
471 dfe11bad Michael Hanselmann
FormatError = lambda text: _FormatWithColor(text, _ERROR_SEQ)
472 dfe11bad Michael Hanselmann
FormatInfo = lambda text: _FormatWithColor(text, _INFO_SEQ)