root / qa / qa_utils.py @ 36e23a40
History | View | Annotate | Download (5.4 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 | 23269c5b | Michael Hanselmann | import sys |
28 | cec9845c | Michael Hanselmann | import subprocess |
29 | cec9845c | Michael Hanselmann | |
30 | cec9845c | Michael Hanselmann | from ganeti import utils |
31 | cec9845c | Michael Hanselmann | |
32 | cec9845c | Michael Hanselmann | import qa_config |
33 | cec9845c | Michael Hanselmann | import qa_error |
34 | cec9845c | Michael Hanselmann | |
35 | cec9845c | Michael Hanselmann | |
36 | 23269c5b | Michael Hanselmann | _INFO_SEQ = None
|
37 | 23269c5b | Michael Hanselmann | _WARNING_SEQ = None
|
38 | 23269c5b | Michael Hanselmann | _ERROR_SEQ = None
|
39 | 23269c5b | Michael Hanselmann | _RESET_SEQ = None
|
40 | 23269c5b | Michael Hanselmann | |
41 | 23269c5b | Michael Hanselmann | |
42 | 23269c5b | Michael Hanselmann | def _SetupColours(): |
43 | 23269c5b | Michael Hanselmann | """Initializes the colour constants.
|
44 | 23269c5b | Michael Hanselmann |
|
45 | 23269c5b | Michael Hanselmann | """
|
46 | 23269c5b | Michael Hanselmann | global _INFO_SEQ, _WARNING_SEQ, _ERROR_SEQ, _RESET_SEQ
|
47 | 23269c5b | Michael Hanselmann | |
48 | dfe11bad | Michael Hanselmann | # Don't use colours if stdout isn't a terminal
|
49 | dfe11bad | Michael Hanselmann | if not sys.stdout.isatty(): |
50 | dfe11bad | Michael Hanselmann | return
|
51 | dfe11bad | Michael Hanselmann | |
52 | 23269c5b | Michael Hanselmann | try:
|
53 | 23269c5b | Michael Hanselmann | import curses |
54 | 23269c5b | Michael Hanselmann | except ImportError: |
55 | 23269c5b | Michael Hanselmann | # Don't use colours if curses module can't be imported
|
56 | 23269c5b | Michael Hanselmann | return
|
57 | 23269c5b | Michael Hanselmann | |
58 | 23269c5b | Michael Hanselmann | curses.setupterm() |
59 | 23269c5b | Michael Hanselmann | |
60 | 23269c5b | Michael Hanselmann | _RESET_SEQ = curses.tigetstr("op")
|
61 | 23269c5b | Michael Hanselmann | |
62 | 23269c5b | Michael Hanselmann | setaf = curses.tigetstr("setaf")
|
63 | 23269c5b | Michael Hanselmann | _INFO_SEQ = curses.tparm(setaf, curses.COLOR_GREEN) |
64 | 23269c5b | Michael Hanselmann | _WARNING_SEQ = curses.tparm(setaf, curses.COLOR_YELLOW) |
65 | 23269c5b | Michael Hanselmann | _ERROR_SEQ = curses.tparm(setaf, curses.COLOR_RED) |
66 | 23269c5b | Michael Hanselmann | |
67 | 23269c5b | Michael Hanselmann | |
68 | 23269c5b | Michael Hanselmann | _SetupColours() |
69 | 23269c5b | Michael Hanselmann | |
70 | 23269c5b | Michael Hanselmann | |
71 | eaef8a05 | Michael Hanselmann | def AssertIn(item, sequence): |
72 | eaef8a05 | Michael Hanselmann | """Raises an error when item is not in sequence.
|
73 | eaef8a05 | Michael Hanselmann |
|
74 | eaef8a05 | Michael Hanselmann | """
|
75 | eaef8a05 | Michael Hanselmann | if item not in sequence: |
76 | eaef8a05 | Michael Hanselmann | raise qa_error.Error('%r not in %r' % (item, sequence)) |
77 | eaef8a05 | Michael Hanselmann | |
78 | eaef8a05 | Michael Hanselmann | |
79 | e8ae0c20 | Michael Hanselmann | def AssertEqual(first, second): |
80 | cec9845c | Michael Hanselmann | """Raises an error when values aren't equal.
|
81 | cec9845c | Michael Hanselmann |
|
82 | cec9845c | Michael Hanselmann | """
|
83 | cec9845c | Michael Hanselmann | if not first == second: |
84 | e8ae0c20 | Michael Hanselmann | raise qa_error.Error('%r == %r' % (first, second)) |
85 | e8ae0c20 | Michael Hanselmann | |
86 | e8ae0c20 | Michael Hanselmann | |
87 | e8ae0c20 | Michael Hanselmann | def AssertNotEqual(first, second): |
88 | e8ae0c20 | Michael Hanselmann | """Raises an error when values are equal.
|
89 | e8ae0c20 | Michael Hanselmann |
|
90 | e8ae0c20 | Michael Hanselmann | """
|
91 | e8ae0c20 | Michael Hanselmann | if not first != second: |
92 | e8ae0c20 | Michael Hanselmann | raise qa_error.Error('%r != %r' % (first, second)) |
93 | cec9845c | Michael Hanselmann | |
94 | cec9845c | Michael Hanselmann | |
95 | cec9845c | Michael Hanselmann | def GetSSHCommand(node, cmd, strict=True): |
96 | cec9845c | Michael Hanselmann | """Builds SSH command to be executed.
|
97 | cec9845c | Michael Hanselmann |
|
98 | c68d1f43 | Michael Hanselmann | Args:
|
99 | c68d1f43 | Michael Hanselmann | - node: Node the command should run on
|
100 | c68d1f43 | Michael Hanselmann | - cmd: Command to be executed as a list with all parameters
|
101 | c68d1f43 | Michael Hanselmann | - strict: Whether to enable strict host key checking
|
102 | c68d1f43 | Michael Hanselmann |
|
103 | cec9845c | Michael Hanselmann | """
|
104 | 305cb9bb | Michael Hanselmann | args = [ 'ssh', '-oEscapeChar=none', '-oBatchMode=yes', '-l', 'root', '-t' ] |
105 | cec9845c | Michael Hanselmann | |
106 | cec9845c | Michael Hanselmann | if strict:
|
107 | cec9845c | Michael Hanselmann | tmp = 'yes'
|
108 | cec9845c | Michael Hanselmann | else:
|
109 | cec9845c | Michael Hanselmann | tmp = 'no'
|
110 | cec9845c | Michael Hanselmann | args.append('-oStrictHostKeyChecking=%s' % tmp)
|
111 | cec9845c | Michael Hanselmann | args.append('-oClearAllForwardings=yes')
|
112 | cec9845c | Michael Hanselmann | args.append('-oForwardAgent=yes')
|
113 | cec9845c | Michael Hanselmann | args.append(node) |
114 | 26a61f87 | Michael Hanselmann | args.append(cmd) |
115 | cec9845c | Michael Hanselmann | |
116 | cec9845c | Michael Hanselmann | print 'SSH:', utils.ShellQuoteArgs(args) |
117 | cec9845c | Michael Hanselmann | |
118 | cec9845c | Michael Hanselmann | return args
|
119 | cec9845c | Michael Hanselmann | |
120 | cec9845c | Michael Hanselmann | |
121 | cec9845c | Michael Hanselmann | def StartSSH(node, cmd, strict=True): |
122 | cec9845c | Michael Hanselmann | """Starts SSH.
|
123 | cec9845c | Michael Hanselmann |
|
124 | cec9845c | Michael Hanselmann | """
|
125 | 4b62db14 | Michael Hanselmann | return subprocess.Popen(GetSSHCommand(node, cmd, strict=strict),
|
126 | 4b62db14 | Michael Hanselmann | shell=False)
|
127 | 4b62db14 | Michael Hanselmann | |
128 | 4b62db14 | Michael Hanselmann | |
129 | 4b62db14 | Michael Hanselmann | def GetCommandOutput(node, cmd): |
130 | 4b62db14 | Michael Hanselmann | """Returns the output of a command executed on the given node.
|
131 | 4b62db14 | Michael Hanselmann |
|
132 | 4b62db14 | Michael Hanselmann | """
|
133 | 4b62db14 | Michael Hanselmann | p = subprocess.Popen(GetSSHCommand(node, cmd), |
134 | 4b62db14 | Michael Hanselmann | shell=False, stdout=subprocess.PIPE)
|
135 | 4b62db14 | Michael Hanselmann | AssertEqual(p.wait(), 0)
|
136 | 4b62db14 | Michael Hanselmann | return p.stdout.read()
|
137 | cec9845c | Michael Hanselmann | |
138 | cec9845c | Michael Hanselmann | |
139 | cec9845c | Michael Hanselmann | def UploadFile(node, src): |
140 | cec9845c | Michael Hanselmann | """Uploads a file to a node and returns the filename.
|
141 | cec9845c | Michael Hanselmann |
|
142 | cec9845c | Michael Hanselmann | Caller needs to remove the returned file on the node when it's not needed
|
143 | cec9845c | Michael Hanselmann | anymore.
|
144 | cec9845c | Michael Hanselmann | """
|
145 | cec9845c | Michael Hanselmann | # Make sure nobody else has access to it while preserving local permissions
|
146 | cec9845c | Michael Hanselmann | mode = os.stat(src).st_mode & 0700
|
147 | cec9845c | Michael Hanselmann | |
148 | cec9845c | Michael Hanselmann | cmd = ('tmp=$(tempfile --mode %o --prefix gnt) && '
|
149 | cec9845c | Michael Hanselmann | '[[ -f "${tmp}" ]] && '
|
150 | cec9845c | Michael Hanselmann | 'cat > "${tmp}" && '
|
151 | cec9845c | Michael Hanselmann | 'echo "${tmp}"') % mode
|
152 | cec9845c | Michael Hanselmann | |
153 | cec9845c | Michael Hanselmann | f = open(src, 'r') |
154 | cec9845c | Michael Hanselmann | try:
|
155 | cec9845c | Michael Hanselmann | p = subprocess.Popen(GetSSHCommand(node, cmd), shell=False, stdin=f,
|
156 | cec9845c | Michael Hanselmann | stdout=subprocess.PIPE) |
157 | cec9845c | Michael Hanselmann | AssertEqual(p.wait(), 0)
|
158 | cec9845c | Michael Hanselmann | |
159 | cec9845c | Michael Hanselmann | # Return temporary filename
|
160 | cec9845c | Michael Hanselmann | return p.stdout.read().strip()
|
161 | cec9845c | Michael Hanselmann | finally:
|
162 | cec9845c | Michael Hanselmann | f.close() |
163 | 5d640672 | Michael Hanselmann | |
164 | 5d640672 | Michael Hanselmann | |
165 | 4b62db14 | Michael Hanselmann | def _ResolveName(cmd, key): |
166 | 4b62db14 | Michael Hanselmann | """Helper function.
|
167 | 4b62db14 | Michael Hanselmann |
|
168 | 4b62db14 | Michael Hanselmann | """
|
169 | 4b62db14 | Michael Hanselmann | master = qa_config.GetMasterNode() |
170 | 4b62db14 | Michael Hanselmann | |
171 | 4b62db14 | Michael Hanselmann | output = GetCommandOutput(master['primary'], utils.ShellQuoteArgs(cmd))
|
172 | 4b62db14 | Michael Hanselmann | for line in output.splitlines(): |
173 | 4b62db14 | Michael Hanselmann | (lkey, lvalue) = line.split(':', 1) |
174 | 4b62db14 | Michael Hanselmann | if lkey == key:
|
175 | 4b62db14 | Michael Hanselmann | return lvalue.lstrip()
|
176 | 4b62db14 | Michael Hanselmann | raise KeyError("Key not found") |
177 | 4b62db14 | Michael Hanselmann | |
178 | 4b62db14 | Michael Hanselmann | |
179 | 5d640672 | Michael Hanselmann | def ResolveInstanceName(instance): |
180 | 5d640672 | Michael Hanselmann | """Gets the full name of an instance.
|
181 | 5d640672 | Michael Hanselmann |
|
182 | 5d640672 | Michael Hanselmann | """
|
183 | e8ae0c20 | Michael Hanselmann | return _ResolveName(['gnt-instance', 'info', instance['name']], |
184 | 4b62db14 | Michael Hanselmann | 'Instance name')
|
185 | 4b62db14 | Michael Hanselmann | |
186 | 4b62db14 | Michael Hanselmann | |
187 | 4b62db14 | Michael Hanselmann | def ResolveNodeName(node): |
188 | 4b62db14 | Michael Hanselmann | """Gets the full name of a node.
|
189 | 4b62db14 | Michael Hanselmann |
|
190 | 4b62db14 | Michael Hanselmann | """
|
191 | 4b62db14 | Michael Hanselmann | return _ResolveName(['gnt-node', 'info', node['primary']], |
192 | 4b62db14 | Michael Hanselmann | 'Node name')
|
193 | 4b62db14 | Michael Hanselmann | |
194 | 4b62db14 | Michael Hanselmann | |
195 | 4b62db14 | Michael Hanselmann | def GetNodeInstances(node, secondaries=False): |
196 | 4b62db14 | Michael Hanselmann | """Gets a list of instances on a node.
|
197 | 4b62db14 | Michael Hanselmann |
|
198 | 4b62db14 | Michael Hanselmann | """
|
199 | 5d640672 | Michael Hanselmann | master = qa_config.GetMasterNode() |
200 | 4b62db14 | Michael Hanselmann | node_name = ResolveNodeName(node) |
201 | 5d640672 | Michael Hanselmann | |
202 | 4b62db14 | Michael Hanselmann | # Get list of all instances
|
203 | 4b62db14 | Michael Hanselmann | cmd = ['gnt-instance', 'list', '--separator=:', '--no-headers', |
204 | 4b62db14 | Michael Hanselmann | '--output=name,pnode,snodes']
|
205 | 4b62db14 | Michael Hanselmann | output = GetCommandOutput(master['primary'], utils.ShellQuoteArgs(cmd))
|
206 | 4b62db14 | Michael Hanselmann | |
207 | 4b62db14 | Michael Hanselmann | instances = [] |
208 | 4b62db14 | Michael Hanselmann | for line in output.splitlines(): |
209 | 4b62db14 | Michael Hanselmann | (name, pnode, snodes) = line.split(':', 2) |
210 | 4b62db14 | Michael Hanselmann | if ((not secondaries and pnode == node_name) or |
211 | 4b62db14 | Michael Hanselmann | (secondaries and node_name in snodes.split(','))): |
212 | 4b62db14 | Michael Hanselmann | instances.append(name) |
213 | 5d640672 | Michael Hanselmann | |
214 | 4b62db14 | Michael Hanselmann | return instances
|
215 | 23269c5b | Michael Hanselmann | |
216 | 23269c5b | Michael Hanselmann | |
217 | dfe11bad | Michael Hanselmann | def _FormatWithColor(text, seq): |
218 | dfe11bad | Michael Hanselmann | if not seq: |
219 | dfe11bad | Michael Hanselmann | return text
|
220 | dfe11bad | Michael Hanselmann | return "%s%s%s" % (seq, text, _RESET_SEQ) |
221 | 23269c5b | Michael Hanselmann | |
222 | 23269c5b | Michael Hanselmann | |
223 | dfe11bad | Michael Hanselmann | FormatWarning = lambda text: _FormatWithColor(text, _WARNING_SEQ)
|
224 | dfe11bad | Michael Hanselmann | FormatError = lambda text: _FormatWithColor(text, _ERROR_SEQ)
|
225 | dfe11bad | Michael Hanselmann | FormatInfo = lambda text: _FormatWithColor(text, _INFO_SEQ) |