root / qa / qa_utils.py @ e8ae0c20
History | View | Annotate | Download (5.1 kB)
1 | cec9845c | Michael Hanselmann | # Copyright (C) 2007 Google Inc.
|
---|---|---|---|
2 | cec9845c | Michael Hanselmann | #
|
3 | cec9845c | Michael Hanselmann | # This program is free software; you can redistribute it and/or modify
|
4 | cec9845c | Michael Hanselmann | # it under the terms of the GNU General Public License as published by
|
5 | cec9845c | Michael Hanselmann | # the Free Software Foundation; either version 2 of the License, or
|
6 | cec9845c | Michael Hanselmann | # (at your option) any later version.
|
7 | cec9845c | Michael Hanselmann | #
|
8 | cec9845c | Michael Hanselmann | # This program is distributed in the hope that it will be useful, but
|
9 | cec9845c | Michael Hanselmann | # WITHOUT ANY WARRANTY; without even the implied warranty of
|
10 | cec9845c | Michael Hanselmann | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
11 | cec9845c | Michael Hanselmann | # General Public License for more details.
|
12 | cec9845c | Michael Hanselmann | #
|
13 | cec9845c | Michael Hanselmann | # You should have received a copy of the GNU General Public License
|
14 | cec9845c | Michael Hanselmann | # along with this program; if not, write to the Free Software
|
15 | cec9845c | Michael Hanselmann | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
16 | cec9845c | Michael Hanselmann | # 02110-1301, USA.
|
17 | cec9845c | Michael Hanselmann | |
18 | cec9845c | Michael Hanselmann | |
19 | cec9845c | Michael Hanselmann | """Utilities for QA tests.
|
20 | cec9845c | Michael Hanselmann |
|
21 | cec9845c | Michael Hanselmann | """
|
22 | cec9845c | Michael Hanselmann | |
23 | cec9845c | Michael Hanselmann | import os |
24 | 23269c5b | Michael Hanselmann | import sys |
25 | cec9845c | Michael Hanselmann | import subprocess |
26 | cec9845c | Michael Hanselmann | |
27 | cec9845c | Michael Hanselmann | from ganeti import utils |
28 | cec9845c | Michael Hanselmann | |
29 | cec9845c | Michael Hanselmann | import qa_config |
30 | cec9845c | Michael Hanselmann | import qa_error |
31 | cec9845c | Michael Hanselmann | |
32 | cec9845c | Michael Hanselmann | |
33 | 23269c5b | Michael Hanselmann | _INFO_SEQ = None
|
34 | 23269c5b | Michael Hanselmann | _WARNING_SEQ = None
|
35 | 23269c5b | Michael Hanselmann | _ERROR_SEQ = None
|
36 | 23269c5b | Michael Hanselmann | _RESET_SEQ = None
|
37 | 23269c5b | Michael Hanselmann | |
38 | 23269c5b | Michael Hanselmann | |
39 | 23269c5b | Michael Hanselmann | def _SetupColours(): |
40 | 23269c5b | Michael Hanselmann | """Initializes the colour constants.
|
41 | 23269c5b | Michael Hanselmann |
|
42 | 23269c5b | Michael Hanselmann | """
|
43 | 23269c5b | Michael Hanselmann | global _INFO_SEQ, _WARNING_SEQ, _ERROR_SEQ, _RESET_SEQ
|
44 | 23269c5b | Michael Hanselmann | |
45 | 23269c5b | Michael Hanselmann | try:
|
46 | 23269c5b | Michael Hanselmann | import curses |
47 | 23269c5b | Michael Hanselmann | except ImportError: |
48 | 23269c5b | Michael Hanselmann | # Don't use colours if curses module can't be imported
|
49 | 23269c5b | Michael Hanselmann | return
|
50 | 23269c5b | Michael Hanselmann | |
51 | 23269c5b | Michael Hanselmann | curses.setupterm() |
52 | 23269c5b | Michael Hanselmann | |
53 | 23269c5b | Michael Hanselmann | _RESET_SEQ = curses.tigetstr("op")
|
54 | 23269c5b | Michael Hanselmann | |
55 | 23269c5b | Michael Hanselmann | setaf = curses.tigetstr("setaf")
|
56 | 23269c5b | Michael Hanselmann | _INFO_SEQ = curses.tparm(setaf, curses.COLOR_GREEN) |
57 | 23269c5b | Michael Hanselmann | _WARNING_SEQ = curses.tparm(setaf, curses.COLOR_YELLOW) |
58 | 23269c5b | Michael Hanselmann | _ERROR_SEQ = curses.tparm(setaf, curses.COLOR_RED) |
59 | 23269c5b | Michael Hanselmann | |
60 | 23269c5b | Michael Hanselmann | |
61 | 23269c5b | Michael Hanselmann | _SetupColours() |
62 | 23269c5b | Michael Hanselmann | |
63 | 23269c5b | Michael Hanselmann | |
64 | e8ae0c20 | Michael Hanselmann | def AssertEqual(first, second): |
65 | cec9845c | Michael Hanselmann | """Raises an error when values aren't equal.
|
66 | cec9845c | Michael Hanselmann |
|
67 | cec9845c | Michael Hanselmann | """
|
68 | cec9845c | Michael Hanselmann | if not first == second: |
69 | e8ae0c20 | Michael Hanselmann | raise qa_error.Error('%r == %r' % (first, second)) |
70 | e8ae0c20 | Michael Hanselmann | |
71 | e8ae0c20 | Michael Hanselmann | |
72 | e8ae0c20 | Michael Hanselmann | def AssertNotEqual(first, second): |
73 | e8ae0c20 | Michael Hanselmann | """Raises an error when values are equal.
|
74 | e8ae0c20 | Michael Hanselmann |
|
75 | e8ae0c20 | Michael Hanselmann | """
|
76 | e8ae0c20 | Michael Hanselmann | if not first != second: |
77 | e8ae0c20 | Michael Hanselmann | raise qa_error.Error('%r != %r' % (first, second)) |
78 | cec9845c | Michael Hanselmann | |
79 | cec9845c | Michael Hanselmann | |
80 | cec9845c | Michael Hanselmann | def GetSSHCommand(node, cmd, strict=True): |
81 | cec9845c | Michael Hanselmann | """Builds SSH command to be executed.
|
82 | cec9845c | Michael Hanselmann |
|
83 | cec9845c | Michael Hanselmann | """
|
84 | cec9845c | Michael Hanselmann | args = [ 'ssh', '-oEscapeChar=none', '-oBatchMode=yes', '-l', 'root' ] |
85 | cec9845c | Michael Hanselmann | |
86 | cec9845c | Michael Hanselmann | if strict:
|
87 | cec9845c | Michael Hanselmann | tmp = 'yes'
|
88 | cec9845c | Michael Hanselmann | else:
|
89 | cec9845c | Michael Hanselmann | tmp = 'no'
|
90 | cec9845c | Michael Hanselmann | args.append('-oStrictHostKeyChecking=%s' % tmp)
|
91 | cec9845c | Michael Hanselmann | args.append('-oClearAllForwardings=yes')
|
92 | cec9845c | Michael Hanselmann | args.append('-oForwardAgent=yes')
|
93 | cec9845c | Michael Hanselmann | args.append(node) |
94 | cec9845c | Michael Hanselmann | |
95 | cec9845c | Michael Hanselmann | if qa_config.options.dry_run:
|
96 | cec9845c | Michael Hanselmann | prefix = 'exit 0; '
|
97 | cec9845c | Michael Hanselmann | else:
|
98 | cec9845c | Michael Hanselmann | prefix = ''
|
99 | cec9845c | Michael Hanselmann | |
100 | cec9845c | Michael Hanselmann | args.append(prefix + cmd) |
101 | cec9845c | Michael Hanselmann | |
102 | cec9845c | Michael Hanselmann | print 'SSH:', utils.ShellQuoteArgs(args) |
103 | cec9845c | Michael Hanselmann | |
104 | cec9845c | Michael Hanselmann | return args
|
105 | cec9845c | Michael Hanselmann | |
106 | cec9845c | Michael Hanselmann | |
107 | cec9845c | Michael Hanselmann | def StartSSH(node, cmd, strict=True): |
108 | cec9845c | Michael Hanselmann | """Starts SSH.
|
109 | cec9845c | Michael Hanselmann |
|
110 | cec9845c | Michael Hanselmann | """
|
111 | 4b62db14 | Michael Hanselmann | return subprocess.Popen(GetSSHCommand(node, cmd, strict=strict),
|
112 | 4b62db14 | Michael Hanselmann | shell=False)
|
113 | 4b62db14 | Michael Hanselmann | |
114 | 4b62db14 | Michael Hanselmann | |
115 | 4b62db14 | Michael Hanselmann | def GetCommandOutput(node, cmd): |
116 | 4b62db14 | Michael Hanselmann | """Returns the output of a command executed on the given node.
|
117 | 4b62db14 | Michael Hanselmann |
|
118 | 4b62db14 | Michael Hanselmann | """
|
119 | 4b62db14 | Michael Hanselmann | p = subprocess.Popen(GetSSHCommand(node, cmd), |
120 | 4b62db14 | Michael Hanselmann | shell=False, stdout=subprocess.PIPE)
|
121 | 4b62db14 | Michael Hanselmann | AssertEqual(p.wait(), 0)
|
122 | 4b62db14 | Michael Hanselmann | return p.stdout.read()
|
123 | cec9845c | Michael Hanselmann | |
124 | cec9845c | Michael Hanselmann | |
125 | cec9845c | Michael Hanselmann | def UploadFile(node, src): |
126 | cec9845c | Michael Hanselmann | """Uploads a file to a node and returns the filename.
|
127 | cec9845c | Michael Hanselmann |
|
128 | cec9845c | Michael Hanselmann | Caller needs to remove the returned file on the node when it's not needed
|
129 | cec9845c | Michael Hanselmann | anymore.
|
130 | cec9845c | Michael Hanselmann | """
|
131 | cec9845c | Michael Hanselmann | # Make sure nobody else has access to it while preserving local permissions
|
132 | cec9845c | Michael Hanselmann | mode = os.stat(src).st_mode & 0700
|
133 | cec9845c | Michael Hanselmann | |
134 | cec9845c | Michael Hanselmann | cmd = ('tmp=$(tempfile --mode %o --prefix gnt) && '
|
135 | cec9845c | Michael Hanselmann | '[[ -f "${tmp}" ]] && '
|
136 | cec9845c | Michael Hanselmann | 'cat > "${tmp}" && '
|
137 | cec9845c | Michael Hanselmann | 'echo "${tmp}"') % mode
|
138 | cec9845c | Michael Hanselmann | |
139 | cec9845c | Michael Hanselmann | f = open(src, 'r') |
140 | cec9845c | Michael Hanselmann | try:
|
141 | cec9845c | Michael Hanselmann | p = subprocess.Popen(GetSSHCommand(node, cmd), shell=False, stdin=f,
|
142 | cec9845c | Michael Hanselmann | stdout=subprocess.PIPE) |
143 | cec9845c | Michael Hanselmann | AssertEqual(p.wait(), 0)
|
144 | cec9845c | Michael Hanselmann | |
145 | cec9845c | Michael Hanselmann | # Return temporary filename
|
146 | cec9845c | Michael Hanselmann | return p.stdout.read().strip()
|
147 | cec9845c | Michael Hanselmann | finally:
|
148 | cec9845c | Michael Hanselmann | f.close() |
149 | 5d640672 | Michael Hanselmann | |
150 | 5d640672 | Michael Hanselmann | |
151 | 4b62db14 | Michael Hanselmann | def _ResolveName(cmd, key): |
152 | 4b62db14 | Michael Hanselmann | """Helper function.
|
153 | 4b62db14 | Michael Hanselmann |
|
154 | 4b62db14 | Michael Hanselmann | """
|
155 | 4b62db14 | Michael Hanselmann | master = qa_config.GetMasterNode() |
156 | 4b62db14 | Michael Hanselmann | |
157 | 4b62db14 | Michael Hanselmann | output = GetCommandOutput(master['primary'], utils.ShellQuoteArgs(cmd))
|
158 | 4b62db14 | Michael Hanselmann | for line in output.splitlines(): |
159 | 4b62db14 | Michael Hanselmann | (lkey, lvalue) = line.split(':', 1) |
160 | 4b62db14 | Michael Hanselmann | if lkey == key:
|
161 | 4b62db14 | Michael Hanselmann | return lvalue.lstrip()
|
162 | 4b62db14 | Michael Hanselmann | raise KeyError("Key not found") |
163 | 4b62db14 | Michael Hanselmann | |
164 | 4b62db14 | Michael Hanselmann | |
165 | 5d640672 | Michael Hanselmann | def ResolveInstanceName(instance): |
166 | 5d640672 | Michael Hanselmann | """Gets the full name of an instance.
|
167 | 5d640672 | Michael Hanselmann |
|
168 | 5d640672 | Michael Hanselmann | """
|
169 | e8ae0c20 | Michael Hanselmann | return _ResolveName(['gnt-instance', 'info', instance['name']], |
170 | 4b62db14 | Michael Hanselmann | 'Instance name')
|
171 | 4b62db14 | Michael Hanselmann | |
172 | 4b62db14 | Michael Hanselmann | |
173 | 4b62db14 | Michael Hanselmann | def ResolveNodeName(node): |
174 | 4b62db14 | Michael Hanselmann | """Gets the full name of a node.
|
175 | 4b62db14 | Michael Hanselmann |
|
176 | 4b62db14 | Michael Hanselmann | """
|
177 | 4b62db14 | Michael Hanselmann | return _ResolveName(['gnt-node', 'info', node['primary']], |
178 | 4b62db14 | Michael Hanselmann | 'Node name')
|
179 | 4b62db14 | Michael Hanselmann | |
180 | 4b62db14 | Michael Hanselmann | |
181 | 4b62db14 | Michael Hanselmann | def GetNodeInstances(node, secondaries=False): |
182 | 4b62db14 | Michael Hanselmann | """Gets a list of instances on a node.
|
183 | 4b62db14 | Michael Hanselmann |
|
184 | 4b62db14 | Michael Hanselmann | """
|
185 | 5d640672 | Michael Hanselmann | master = qa_config.GetMasterNode() |
186 | 5d640672 | Michael Hanselmann | |
187 | 4b62db14 | Michael Hanselmann | node_name = ResolveNodeName(node) |
188 | 5d640672 | Michael Hanselmann | |
189 | 4b62db14 | Michael Hanselmann | # Get list of all instances
|
190 | 4b62db14 | Michael Hanselmann | cmd = ['gnt-instance', 'list', '--separator=:', '--no-headers', |
191 | 4b62db14 | Michael Hanselmann | '--output=name,pnode,snodes']
|
192 | 4b62db14 | Michael Hanselmann | output = GetCommandOutput(master['primary'], utils.ShellQuoteArgs(cmd))
|
193 | 4b62db14 | Michael Hanselmann | |
194 | 4b62db14 | Michael Hanselmann | instances = [] |
195 | 4b62db14 | Michael Hanselmann | for line in output.splitlines(): |
196 | 4b62db14 | Michael Hanselmann | (name, pnode, snodes) = line.split(':', 2) |
197 | 4b62db14 | Michael Hanselmann | if ((not secondaries and pnode == node_name) or |
198 | 4b62db14 | Michael Hanselmann | (secondaries and node_name in snodes.split(','))): |
199 | 4b62db14 | Michael Hanselmann | instances.append(name) |
200 | 5d640672 | Michael Hanselmann | |
201 | 4b62db14 | Michael Hanselmann | return instances
|
202 | 23269c5b | Michael Hanselmann | |
203 | 23269c5b | Michael Hanselmann | |
204 | 23269c5b | Michael Hanselmann | def _PrintWithColor(text, seq): |
205 | 23269c5b | Michael Hanselmann | f = sys.stdout |
206 | 23269c5b | Michael Hanselmann | |
207 | 23269c5b | Michael Hanselmann | if not f.isatty(): |
208 | 23269c5b | Michael Hanselmann | seq = None
|
209 | 23269c5b | Michael Hanselmann | |
210 | 23269c5b | Michael Hanselmann | if seq:
|
211 | 23269c5b | Michael Hanselmann | f.write(seq) |
212 | 23269c5b | Michael Hanselmann | |
213 | 23269c5b | Michael Hanselmann | f.write(text) |
214 | 23269c5b | Michael Hanselmann | f.write("\n")
|
215 | 23269c5b | Michael Hanselmann | |
216 | 23269c5b | Michael Hanselmann | if seq:
|
217 | 23269c5b | Michael Hanselmann | f.write(_RESET_SEQ) |
218 | 23269c5b | Michael Hanselmann | |
219 | 23269c5b | Michael Hanselmann | |
220 | 23269c5b | Michael Hanselmann | def PrintWarning(text): |
221 | 23269c5b | Michael Hanselmann | return _PrintWithColor(text, _WARNING_SEQ)
|
222 | 23269c5b | Michael Hanselmann | |
223 | 23269c5b | Michael Hanselmann | |
224 | 90ab92e3 | Michael Hanselmann | def PrintError(text): |
225 | 23269c5b | Michael Hanselmann | return _PrintWithColor(text, _ERROR_SEQ)
|
226 | 23269c5b | Michael Hanselmann | |
227 | 23269c5b | Michael Hanselmann | |
228 | 90ab92e3 | Michael Hanselmann | def PrintInfo(text): |
229 | 23269c5b | Michael Hanselmann | return _PrintWithColor(text, _INFO_SEQ) |