Statistics
| Branch: | Tag: | Revision:

root / qa / qa_utils.py @ 5d831182

History | View | Annotate | Download (6.1 kB)

1 c68d1f43 Michael Hanselmann
#
2 c68d1f43 Michael Hanselmann
#
3 c68d1f43 Michael Hanselmann
4 cec9845c Michael Hanselmann
# Copyright (C) 2007 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 cec9845c Michael Hanselmann
31 cec9845c Michael Hanselmann
from ganeti import utils
32 cec9845c Michael Hanselmann
33 cec9845c Michael Hanselmann
import qa_config
34 cec9845c Michael Hanselmann
import qa_error
35 cec9845c Michael Hanselmann
36 cec9845c Michael Hanselmann
37 23269c5b Michael Hanselmann
_INFO_SEQ = None
38 23269c5b Michael Hanselmann
_WARNING_SEQ = None
39 23269c5b Michael Hanselmann
_ERROR_SEQ = None
40 23269c5b Michael Hanselmann
_RESET_SEQ = None
41 23269c5b Michael Hanselmann
42 23269c5b Michael Hanselmann
43 23269c5b Michael Hanselmann
def _SetupColours():
44 23269c5b Michael Hanselmann
  """Initializes the colour constants.
45 23269c5b Michael Hanselmann

46 23269c5b Michael Hanselmann
  """
47 23269c5b Michael Hanselmann
  global _INFO_SEQ, _WARNING_SEQ, _ERROR_SEQ, _RESET_SEQ
48 23269c5b Michael Hanselmann
49 dfe11bad Michael Hanselmann
  # Don't use colours if stdout isn't a terminal
50 dfe11bad Michael Hanselmann
  if not sys.stdout.isatty():
51 dfe11bad Michael Hanselmann
    return
52 dfe11bad Michael Hanselmann
53 23269c5b Michael Hanselmann
  try:
54 23269c5b Michael Hanselmann
    import curses
55 23269c5b Michael Hanselmann
  except ImportError:
56 23269c5b Michael Hanselmann
    # Don't use colours if curses module can't be imported
57 23269c5b Michael Hanselmann
    return
58 23269c5b Michael Hanselmann
59 23269c5b Michael Hanselmann
  curses.setupterm()
60 23269c5b Michael Hanselmann
61 23269c5b Michael Hanselmann
  _RESET_SEQ = curses.tigetstr("op")
62 23269c5b Michael Hanselmann
63 23269c5b Michael Hanselmann
  setaf = curses.tigetstr("setaf")
64 23269c5b Michael Hanselmann
  _INFO_SEQ = curses.tparm(setaf, curses.COLOR_GREEN)
65 23269c5b Michael Hanselmann
  _WARNING_SEQ = curses.tparm(setaf, curses.COLOR_YELLOW)
66 23269c5b Michael Hanselmann
  _ERROR_SEQ = curses.tparm(setaf, curses.COLOR_RED)
67 23269c5b Michael Hanselmann
68 23269c5b Michael Hanselmann
69 23269c5b Michael Hanselmann
_SetupColours()
70 23269c5b Michael Hanselmann
71 23269c5b Michael Hanselmann
72 eaef8a05 Michael Hanselmann
def AssertIn(item, sequence):
73 eaef8a05 Michael Hanselmann
  """Raises an error when item is not in sequence.
74 eaef8a05 Michael Hanselmann

75 eaef8a05 Michael Hanselmann
  """
76 eaef8a05 Michael Hanselmann
  if item not in sequence:
77 eaef8a05 Michael Hanselmann
    raise qa_error.Error('%r not in %r' % (item, sequence))
78 eaef8a05 Michael Hanselmann
79 eaef8a05 Michael Hanselmann
80 e8ae0c20 Michael Hanselmann
def AssertEqual(first, second):
81 cec9845c Michael Hanselmann
  """Raises an error when values aren't equal.
82 cec9845c Michael Hanselmann

83 cec9845c Michael Hanselmann
  """
84 cec9845c Michael Hanselmann
  if not first == second:
85 e8ae0c20 Michael Hanselmann
    raise qa_error.Error('%r == %r' % (first, second))
86 e8ae0c20 Michael Hanselmann
87 e8ae0c20 Michael Hanselmann
88 e8ae0c20 Michael Hanselmann
def AssertNotEqual(first, second):
89 e8ae0c20 Michael Hanselmann
  """Raises an error when values are equal.
90 e8ae0c20 Michael Hanselmann

91 e8ae0c20 Michael Hanselmann
  """
92 e8ae0c20 Michael Hanselmann
  if not first != second:
93 e8ae0c20 Michael Hanselmann
    raise qa_error.Error('%r != %r' % (first, second))
94 cec9845c Michael Hanselmann
95 cec9845c Michael Hanselmann
96 e6ce18ac René Nussbaumer
def AssertMatch(string, pattern):
97 e6ce18ac René Nussbaumer
  """Raises an error when string doesn't match regexp pattern.
98 e6ce18ac René Nussbaumer

99 e6ce18ac René Nussbaumer
  """
100 e6ce18ac René Nussbaumer
  if not re.match(pattern, string):
101 e6ce18ac René Nussbaumer
    raise qa_error.Error("%r doesn't match /%r/" % (string, pattern))
102 e6ce18ac René Nussbaumer
103 e6ce18ac René Nussbaumer
104 cec9845c Michael Hanselmann
def GetSSHCommand(node, cmd, strict=True):
105 cec9845c Michael Hanselmann
  """Builds SSH command to be executed.
106 cec9845c Michael Hanselmann

107 c68d1f43 Michael Hanselmann
  Args:
108 c68d1f43 Michael Hanselmann
  - node: Node the command should run on
109 c68d1f43 Michael Hanselmann
  - cmd: Command to be executed as a list with all parameters
110 c68d1f43 Michael Hanselmann
  - strict: Whether to enable strict host key checking
111 c68d1f43 Michael Hanselmann

112 cec9845c Michael Hanselmann
  """
113 305cb9bb Michael Hanselmann
  args = [ 'ssh', '-oEscapeChar=none', '-oBatchMode=yes', '-l', 'root', '-t' ]
114 cec9845c Michael Hanselmann
115 cec9845c Michael Hanselmann
  if strict:
116 cec9845c Michael Hanselmann
    tmp = 'yes'
117 cec9845c Michael Hanselmann
  else:
118 cec9845c Michael Hanselmann
    tmp = 'no'
119 cec9845c Michael Hanselmann
  args.append('-oStrictHostKeyChecking=%s' % tmp)
120 cec9845c Michael Hanselmann
  args.append('-oClearAllForwardings=yes')
121 cec9845c Michael Hanselmann
  args.append('-oForwardAgent=yes')
122 cec9845c Michael Hanselmann
  args.append(node)
123 26a61f87 Michael Hanselmann
  args.append(cmd)
124 cec9845c Michael Hanselmann
125 cec9845c Michael Hanselmann
  return args
126 cec9845c Michael Hanselmann
127 cec9845c Michael Hanselmann
128 5d831182 Michael Hanselmann
def StartLocalCommand(cmd, **kwargs):
129 5d831182 Michael Hanselmann
  """Starts a local command.
130 5d831182 Michael Hanselmann

131 5d831182 Michael Hanselmann
  """
132 5d831182 Michael Hanselmann
  print "Command: %s" % utils.ShellQuoteArgs(cmd)
133 5d831182 Michael Hanselmann
  return subprocess.Popen(cmd, shell=False, **kwargs)
134 5d831182 Michael Hanselmann
135 5d831182 Michael Hanselmann
136 cec9845c Michael Hanselmann
def StartSSH(node, cmd, strict=True):
137 cec9845c Michael Hanselmann
  """Starts SSH.
138 cec9845c Michael Hanselmann

139 cec9845c Michael Hanselmann
  """
140 5d831182 Michael Hanselmann
  return StartLocalCommand(GetSSHCommand(node, cmd, strict=strict))
141 4b62db14 Michael Hanselmann
142 4b62db14 Michael Hanselmann
143 4b62db14 Michael Hanselmann
def GetCommandOutput(node, cmd):
144 4b62db14 Michael Hanselmann
  """Returns the output of a command executed on the given node.
145 4b62db14 Michael Hanselmann

146 4b62db14 Michael Hanselmann
  """
147 5d831182 Michael Hanselmann
  p = StartLocalCommand(GetSSHCommand(node, cmd), stdout=subprocess.PIPE)
148 4b62db14 Michael Hanselmann
  AssertEqual(p.wait(), 0)
149 4b62db14 Michael Hanselmann
  return p.stdout.read()
150 cec9845c Michael Hanselmann
151 cec9845c Michael Hanselmann
152 cec9845c Michael Hanselmann
def UploadFile(node, src):
153 cec9845c Michael Hanselmann
  """Uploads a file to a node and returns the filename.
154 cec9845c Michael Hanselmann

155 cec9845c Michael Hanselmann
  Caller needs to remove the returned file on the node when it's not needed
156 cec9845c Michael Hanselmann
  anymore.
157 49d50e52 Michael Hanselmann

158 cec9845c Michael Hanselmann
  """
159 cec9845c Michael Hanselmann
  # Make sure nobody else has access to it while preserving local permissions
160 cec9845c Michael Hanselmann
  mode = os.stat(src).st_mode & 0700
161 cec9845c Michael Hanselmann
162 cec9845c Michael Hanselmann
  cmd = ('tmp=$(tempfile --mode %o --prefix gnt) && '
163 cec9845c Michael Hanselmann
         '[[ -f "${tmp}" ]] && '
164 cec9845c Michael Hanselmann
         'cat > "${tmp}" && '
165 cec9845c Michael Hanselmann
         'echo "${tmp}"') % mode
166 cec9845c Michael Hanselmann
167 cec9845c Michael Hanselmann
  f = open(src, 'r')
168 cec9845c Michael Hanselmann
  try:
169 cec9845c Michael Hanselmann
    p = subprocess.Popen(GetSSHCommand(node, cmd), shell=False, stdin=f,
170 cec9845c Michael Hanselmann
                         stdout=subprocess.PIPE)
171 cec9845c Michael Hanselmann
    AssertEqual(p.wait(), 0)
172 cec9845c Michael Hanselmann
173 cec9845c Michael Hanselmann
    # Return temporary filename
174 cec9845c Michael Hanselmann
    return p.stdout.read().strip()
175 cec9845c Michael Hanselmann
  finally:
176 cec9845c Michael Hanselmann
    f.close()
177 5d640672 Michael Hanselmann
178 5d640672 Michael Hanselmann
179 49d50e52 Michael Hanselmann
def BackupFile(node, path):
180 49d50e52 Michael Hanselmann
  """Creates a backup of a file on the node and returns the filename.
181 49d50e52 Michael Hanselmann

182 49d50e52 Michael Hanselmann
  Caller needs to remove the returned file on the node when it's not needed
183 49d50e52 Michael Hanselmann
  anymore.
184 49d50e52 Michael Hanselmann

185 49d50e52 Michael Hanselmann
  """
186 49d50e52 Michael Hanselmann
  cmd = ("tmp=$(tempfile --prefix .gnt --directory=$(dirname %s)) && "
187 49d50e52 Michael Hanselmann
         "[[ -f \"$tmp\" ]] && "
188 49d50e52 Michael Hanselmann
         "cp %s $tmp && "
189 49d50e52 Michael Hanselmann
         "echo $tmp") % (utils.ShellQuote(path), utils.ShellQuote(path))
190 49d50e52 Michael Hanselmann
191 49d50e52 Michael Hanselmann
  # Return temporary filename
192 49d50e52 Michael Hanselmann
  return GetCommandOutput(node, cmd).strip()
193 49d50e52 Michael Hanselmann
194 49d50e52 Michael Hanselmann
195 4b62db14 Michael Hanselmann
def _ResolveName(cmd, key):
196 4b62db14 Michael Hanselmann
  """Helper function.
197 4b62db14 Michael Hanselmann

198 4b62db14 Michael Hanselmann
  """
199 4b62db14 Michael Hanselmann
  master = qa_config.GetMasterNode()
200 4b62db14 Michael Hanselmann
201 4b62db14 Michael Hanselmann
  output = GetCommandOutput(master['primary'], utils.ShellQuoteArgs(cmd))
202 4b62db14 Michael Hanselmann
  for line in output.splitlines():
203 4b62db14 Michael Hanselmann
    (lkey, lvalue) = line.split(':', 1)
204 4b62db14 Michael Hanselmann
    if lkey == key:
205 4b62db14 Michael Hanselmann
      return lvalue.lstrip()
206 4b62db14 Michael Hanselmann
  raise KeyError("Key not found")
207 4b62db14 Michael Hanselmann
208 4b62db14 Michael Hanselmann
209 5d640672 Michael Hanselmann
def ResolveInstanceName(instance):
210 5d640672 Michael Hanselmann
  """Gets the full name of an instance.
211 5d640672 Michael Hanselmann

212 5d640672 Michael Hanselmann
  """
213 e8ae0c20 Michael Hanselmann
  return _ResolveName(['gnt-instance', 'info', instance['name']],
214 4b62db14 Michael Hanselmann
                      'Instance name')
215 4b62db14 Michael Hanselmann
216 4b62db14 Michael Hanselmann
217 4b62db14 Michael Hanselmann
def ResolveNodeName(node):
218 4b62db14 Michael Hanselmann
  """Gets the full name of a node.
219 4b62db14 Michael Hanselmann

220 4b62db14 Michael Hanselmann
  """
221 4b62db14 Michael Hanselmann
  return _ResolveName(['gnt-node', 'info', node['primary']],
222 4b62db14 Michael Hanselmann
                      'Node name')
223 4b62db14 Michael Hanselmann
224 4b62db14 Michael Hanselmann
225 4b62db14 Michael Hanselmann
def GetNodeInstances(node, secondaries=False):
226 4b62db14 Michael Hanselmann
  """Gets a list of instances on a node.
227 4b62db14 Michael Hanselmann

228 4b62db14 Michael Hanselmann
  """
229 5d640672 Michael Hanselmann
  master = qa_config.GetMasterNode()
230 4b62db14 Michael Hanselmann
  node_name = ResolveNodeName(node)
231 5d640672 Michael Hanselmann
232 4b62db14 Michael Hanselmann
  # Get list of all instances
233 4b62db14 Michael Hanselmann
  cmd = ['gnt-instance', 'list', '--separator=:', '--no-headers',
234 4b62db14 Michael Hanselmann
         '--output=name,pnode,snodes']
235 4b62db14 Michael Hanselmann
  output = GetCommandOutput(master['primary'], utils.ShellQuoteArgs(cmd))
236 4b62db14 Michael Hanselmann
237 4b62db14 Michael Hanselmann
  instances = []
238 4b62db14 Michael Hanselmann
  for line in output.splitlines():
239 4b62db14 Michael Hanselmann
    (name, pnode, snodes) = line.split(':', 2)
240 4b62db14 Michael Hanselmann
    if ((not secondaries and pnode == node_name) or
241 4b62db14 Michael Hanselmann
        (secondaries and node_name in snodes.split(','))):
242 4b62db14 Michael Hanselmann
      instances.append(name)
243 5d640672 Michael Hanselmann
244 4b62db14 Michael Hanselmann
  return instances
245 23269c5b Michael Hanselmann
246 23269c5b Michael Hanselmann
247 dfe11bad Michael Hanselmann
def _FormatWithColor(text, seq):
248 dfe11bad Michael Hanselmann
  if not seq:
249 dfe11bad Michael Hanselmann
    return text
250 dfe11bad Michael Hanselmann
  return "%s%s%s" % (seq, text, _RESET_SEQ)
251 23269c5b Michael Hanselmann
252 23269c5b Michael Hanselmann
253 dfe11bad Michael Hanselmann
FormatWarning = lambda text: _FormatWithColor(text, _WARNING_SEQ)
254 dfe11bad Michael Hanselmann
FormatError = lambda text: _FormatWithColor(text, _ERROR_SEQ)
255 dfe11bad Michael Hanselmann
FormatInfo = lambda text: _FormatWithColor(text, _INFO_SEQ)