Revision 587f8ff6
b/qa/qa_cluster.py | ||
---|---|---|
1 | 1 |
# |
2 | 2 |
# |
3 | 3 |
|
4 |
# Copyright (C) 2007, 2010, 2011, 2012 Google Inc. |
|
4 |
# Copyright (C) 2007, 2010, 2011, 2012, 2013 Google Inc.
|
|
5 | 5 |
# |
6 | 6 |
# This program is free software; you can redistribute it and/or modify |
7 | 7 |
# it under the terms of the GNU General Public License as published by |
... | ... | |
23 | 23 |
|
24 | 24 |
""" |
25 | 25 |
|
26 |
import re |
|
26 | 27 |
import tempfile |
27 | 28 |
import os.path |
28 | 29 |
|
... | ... | |
59 | 60 |
AssertEqual(qa_utils.GetCommandOutput(node["primary"], cmd), content) |
60 | 61 |
|
61 | 62 |
|
63 |
# Cluster-verify errors (date, "ERROR", then error code) |
|
64 |
_CVERROR_RE = re.compile(r"^[\w\s:]+\s+- ERROR:([A-Z0-9_-]+):") |
|
65 |
|
|
66 |
|
|
67 |
def _GetCVErrorCodes(cvout): |
|
68 |
ret = set() |
|
69 |
for l in cvout.splitlines(): |
|
70 |
m = _CVERROR_RE.match(l) |
|
71 |
if m: |
|
72 |
ecode = m.group(1) |
|
73 |
ret.add(ecode) |
|
74 |
return ret |
|
75 |
|
|
76 |
|
|
77 |
def AssertClusterVerify(fail=False, errors=None): |
|
78 |
"""Run cluster-verify and check the result |
|
79 |
|
|
80 |
@type fail: bool |
|
81 |
@param fail: if cluster-verify is expected to fail instead of succeeding |
|
82 |
@type errors: list of tuples |
|
83 |
@param errors: List of CV_XXX errors that are expected; if specified, all the |
|
84 |
errors listed must appear in cluster-verify output. A non-empty value |
|
85 |
implies C{fail=True}. |
|
86 |
|
|
87 |
""" |
|
88 |
cvcmd = "gnt-cluster verify" |
|
89 |
mnode = qa_config.GetMasterNode() |
|
90 |
if errors: |
|
91 |
cvout = GetCommandOutput(mnode["primary"], cvcmd + " --error-codes", |
|
92 |
fail=True) |
|
93 |
actual = _GetCVErrorCodes(cvout) |
|
94 |
expected = compat.UniqueFrozenset(e for (_, e, _) in errors) |
|
95 |
if not actual.issuperset(expected): |
|
96 |
missing = expected.difference(actual) |
|
97 |
raise qa_error.Error("Cluster-verify didn't return these expected" |
|
98 |
" errors: %s" % utils.CommaJoin(missing)) |
|
99 |
else: |
|
100 |
AssertCommand(cvcmd, fail=fail, node=mnode) |
|
101 |
|
|
102 |
|
|
62 | 103 |
# data for testing failures due to bad keys/values for disk parameters |
63 | 104 |
_FAIL_PARAMS = ["nonexistent:resync-rate=1", |
64 | 105 |
"drbd:nonexistent=1", |
b/qa/qa_utils.py | ||
---|---|---|
1 | 1 |
# |
2 | 2 |
# |
3 | 3 |
|
4 |
# Copyright (C) 2007, 2011, 2012 Google Inc. |
|
4 |
# Copyright (C) 2007, 2011, 2012, 2013 Google Inc.
|
|
5 | 5 |
# |
6 | 6 |
# This program is free software; you can redistribute it and/or modify |
7 | 7 |
# it under the terms of the GNU General Public License as published by |
... | ... | |
148 | 148 |
return result |
149 | 149 |
|
150 | 150 |
|
151 |
def _AssertRetCode(rcode, fail, cmdstr, nodename): |
|
152 |
"""Check the return value from a command and possibly raise an exception. |
|
153 |
|
|
154 |
""" |
|
155 |
if fail and rcode == 0: |
|
156 |
raise qa_error.Error("Command '%s' on node %s was expected to fail but" |
|
157 |
" didn't" % (cmdstr, nodename)) |
|
158 |
elif not fail and rcode != 0: |
|
159 |
raise qa_error.Error("Command '%s' on node %s failed, exit code %s" % |
|
160 |
(cmdstr, nodename, rcode)) |
|
161 |
|
|
162 |
|
|
151 | 163 |
def AssertCommand(cmd, fail=False, node=None): |
152 | 164 |
"""Checks that a remote command succeeds. |
153 | 165 |
|
... | ... | |
173 | 185 |
cmdstr = utils.ShellQuoteArgs(cmd) |
174 | 186 |
|
175 | 187 |
rcode = StartSSH(nodename, cmdstr).wait() |
176 |
|
|
177 |
if fail: |
|
178 |
if rcode == 0: |
|
179 |
raise qa_error.Error("Command '%s' on node %s was expected to fail but" |
|
180 |
" didn't" % (cmdstr, nodename)) |
|
181 |
else: |
|
182 |
if rcode != 0: |
|
183 |
raise qa_error.Error("Command '%s' on node %s failed, exit code %s" % |
|
184 |
(cmdstr, nodename, rcode)) |
|
188 |
_AssertRetCode(rcode, fail, cmdstr, nodename) |
|
185 | 189 |
|
186 | 190 |
return rcode |
187 | 191 |
|
... | ... | |
278 | 282 |
utils.RemoveFile(sname) |
279 | 283 |
|
280 | 284 |
|
281 |
def GetCommandOutput(node, cmd, tty=None): |
|
285 |
def GetCommandOutput(node, cmd, tty=None, fail=False):
|
|
282 | 286 |
"""Returns the output of a command executed on the given node. |
283 | 287 |
|
288 |
@type node: string |
|
289 |
@param node: node the command should run on |
|
290 |
@type cmd: string |
|
291 |
@param cmd: command to be executed in the node (cannot be empty or None) |
|
292 |
@type tty: bool or None |
|
293 |
@param tty: if we should use tty; if None, it will be auto-detected |
|
294 |
@type fail: bool |
|
295 |
@param fail: whether the command is expected to fail |
|
284 | 296 |
""" |
297 |
assert cmd |
|
285 | 298 |
p = StartLocalCommand(GetSSHCommand(node, cmd, tty=tty), |
286 | 299 |
stdout=subprocess.PIPE) |
287 |
AssertEqual(p.wait(), 0) |
|
300 |
rcode = p.wait() |
|
301 |
_AssertRetCode(rcode, fail, node, cmd) |
|
288 | 302 |
return p.stdout.read() |
289 | 303 |
|
290 | 304 |
|
Also available in: Unified diff