Revision ed54b47e
b/Makefile.am | ||
---|---|---|
30 | 30 |
lib/rapi \ |
31 | 31 |
man \ |
32 | 32 |
qa \ |
33 |
qa/hooks \ |
|
34 | 33 |
scripts \ |
35 | 34 |
test \ |
36 | 35 |
test/data \ |
... | ... | |
51 | 50 |
man/*.[78] \ |
52 | 51 |
man/*.in \ |
53 | 52 |
qa/*.py[co] \ |
54 |
qa/hooks/*.py[co] \ |
|
55 | 53 |
test/*.py[co] \ |
56 | 54 |
stamp-directories \ |
57 | 55 |
$(nodist_pkgpython_PYTHON) |
... | ... | |
141 | 139 |
doc/examples/ganeti.initd.in \ |
142 | 140 |
doc/examples/ganeti.cron.in \ |
143 | 141 |
doc/examples/dumb-allocator \ |
144 |
qa/hooks/datehook.py \ |
|
145 |
qa/hooks/loghook.py \ |
|
146 | 142 |
test/testutils.py \ |
147 | 143 |
test/mocks.py \ |
148 | 144 |
$(dist_TESTS) \ |
b/qa/ganeti-qa.py | ||
---|---|---|
263 | 263 |
sys.exit(1) |
264 | 264 |
|
265 | 265 |
qa_config.Load(config_file) |
266 |
qa_utils.LoadHooks() |
|
267 | 266 |
|
268 | 267 |
RunTest(qa_other.UploadKnownHostsFile, known_hosts_file) |
269 | 268 |
|
/dev/null | ||
---|---|---|
1 |
# Copyright (C) 2007 Google Inc. |
|
2 |
# |
|
3 |
# This program is free software; you can redistribute it and/or modify |
|
4 |
# it under the terms of the GNU General Public License as published by |
|
5 |
# the Free Software Foundation; either version 2 of the License, or |
|
6 |
# (at your option) any later version. |
|
7 |
# |
|
8 |
# This program is distributed in the hope that it will be useful, but |
|
9 |
# WITHOUT ANY WARRANTY; without even the implied warranty of |
|
10 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
11 |
# General Public License for more details. |
|
12 |
# |
|
13 |
# You should have received a copy of the GNU General Public License |
|
14 |
# along with this program; if not, write to the Free Software |
|
15 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
|
16 |
# 02110-1301, USA. |
|
17 |
|
|
18 |
|
|
19 |
"""Example QA hook. |
|
20 |
|
|
21 |
""" |
|
22 |
|
|
23 |
from ganeti import utils |
|
24 |
|
|
25 |
import qa_utils |
|
26 |
import qa_config |
|
27 |
|
|
28 |
from qa_utils import AssertEqual, StartSSH |
|
29 |
|
|
30 |
|
|
31 |
class DateHook: |
|
32 |
def run(self, ctx): |
|
33 |
if ctx.name == 'cluster-init' and ctx.phase == 'pre': |
|
34 |
self._CallDate(ctx) |
|
35 |
|
|
36 |
def _CallDate(self, ctx): |
|
37 |
for node in qa_config.get('nodes'): |
|
38 |
cmd = ['date'] |
|
39 |
AssertEqual(StartSSH(node['primary'], |
|
40 |
utils.ShellQuoteArgs(cmd)).wait(), 0) |
|
41 |
|
|
42 |
hook = DateHook |
/dev/null | ||
---|---|---|
1 |
# Copyright (C) 2007 Google Inc. |
|
2 |
# |
|
3 |
# This program is free software; you can redistribute it and/or modify |
|
4 |
# it under the terms of the GNU General Public License as published by |
|
5 |
# the Free Software Foundation; either version 2 of the License, or |
|
6 |
# (at your option) any later version. |
|
7 |
# |
|
8 |
# This program is distributed in the hope that it will be useful, but |
|
9 |
# WITHOUT ANY WARRANTY; without even the implied warranty of |
|
10 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
11 |
# General Public License for more details. |
|
12 |
# |
|
13 |
# You should have received a copy of the GNU General Public License |
|
14 |
# along with this program; if not, write to the Free Software |
|
15 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
|
16 |
# 02110-1301, USA. |
|
17 |
|
|
18 |
|
|
19 |
"""QA hook to log all function calls. |
|
20 |
|
|
21 |
""" |
|
22 |
|
|
23 |
from ganeti import utils |
|
24 |
|
|
25 |
import qa_utils |
|
26 |
import qa_config |
|
27 |
|
|
28 |
from qa_utils import AssertEqual, StartSSH |
|
29 |
|
|
30 |
|
|
31 |
class LogHook: |
|
32 |
def __init__(self): |
|
33 |
file_name = qa_config.get('options', {}).get('hook-logfile', None) |
|
34 |
if file_name: |
|
35 |
self.log = open(file_name, "a+") |
|
36 |
else: |
|
37 |
self.log = None |
|
38 |
|
|
39 |
def __del__(self): |
|
40 |
if self.log: |
|
41 |
self.log.close() |
|
42 |
|
|
43 |
def run(self, ctx): |
|
44 |
if not self.log: |
|
45 |
return |
|
46 |
|
|
47 |
msg = "%s-%s" % (ctx.phase, ctx.name) |
|
48 |
if ctx.phase == 'post': |
|
49 |
msg += " success=%s" % ctx.success |
|
50 |
if ctx.args: |
|
51 |
msg += " %s" % repr(ctx.args) |
|
52 |
if ctx.kwargs: |
|
53 |
msg += " %s" % repr(ctx.kwargs) |
|
54 |
if ctx.phase == 'pre': |
|
55 |
self.log.write("---\n") |
|
56 |
self.log.write(msg) |
|
57 |
self.log.write("\n") |
|
58 |
self.log.flush() |
|
59 |
|
|
60 |
|
|
61 |
hook = LogHook |
b/qa/qa-sample.yaml | ||
---|---|---|
83 | 83 |
options: |
84 | 84 |
burnin-instances: 2 |
85 | 85 |
burnin-disk-template: drbd |
86 |
|
|
87 |
# Directory containing QA hooks |
|
88 |
#hooks-dir: hooks/ |
|
89 |
|
|
90 |
# Logfile for loghook.py |
|
91 |
hook-logfile: /tmp/qa.log |
b/qa/qa_cluster.py | ||
---|---|---|
54 | 54 |
content) |
55 | 55 |
|
56 | 56 |
|
57 |
@qa_utils.DefineHook('cluster-init') |
|
58 | 57 |
def TestClusterInit(): |
59 | 58 |
"""gnt-cluster init""" |
60 | 59 |
master = qa_config.GetMasterNode() |
... | ... | |
79 | 78 |
utils.ShellQuoteArgs(cmd)).wait(), 0) |
80 | 79 |
|
81 | 80 |
|
82 |
@qa_utils.DefineHook('cluster-rename') |
|
83 | 81 |
def TestClusterRename(): |
84 | 82 |
"""gnt-cluster rename""" |
85 | 83 |
master = qa_config.GetMasterNode() |
... | ... | |
110 | 108 |
utils.ShellQuoteArgs(cmd_verify)).wait(), 0) |
111 | 109 |
|
112 | 110 |
|
113 |
@qa_utils.DefineHook('cluster-verify') |
|
114 | 111 |
def TestClusterVerify(): |
115 | 112 |
"""gnt-cluster verify""" |
116 | 113 |
master = qa_config.GetMasterNode() |
... | ... | |
120 | 117 |
utils.ShellQuoteArgs(cmd)).wait(), 0) |
121 | 118 |
|
122 | 119 |
|
123 |
@qa_utils.DefineHook('cluster-info') |
|
124 | 120 |
def TestClusterInfo(): |
125 | 121 |
"""gnt-cluster info""" |
126 | 122 |
master = qa_config.GetMasterNode() |
... | ... | |
130 | 126 |
utils.ShellQuoteArgs(cmd)).wait(), 0) |
131 | 127 |
|
132 | 128 |
|
133 |
@qa_utils.DefineHook('cluster-getmaster') |
|
134 | 129 |
def TestClusterGetmaster(): |
135 | 130 |
"""gnt-cluster getmaster""" |
136 | 131 |
master = qa_config.GetMasterNode() |
... | ... | |
140 | 135 |
utils.ShellQuoteArgs(cmd)).wait(), 0) |
141 | 136 |
|
142 | 137 |
|
143 |
@qa_utils.DefineHook('cluster-version') |
|
144 | 138 |
def TestClusterVersion(): |
145 | 139 |
"""gnt-cluster version""" |
146 | 140 |
master = qa_config.GetMasterNode() |
... | ... | |
150 | 144 |
utils.ShellQuoteArgs(cmd)).wait(), 0) |
151 | 145 |
|
152 | 146 |
|
153 |
@qa_utils.DefineHook('cluster-burnin') |
|
154 | 147 |
def TestClusterBurnin(): |
155 | 148 |
"""Burnin""" |
156 | 149 |
master = qa_config.GetMasterNode() |
... | ... | |
191 | 184 |
qa_config.ReleaseInstance(inst) |
192 | 185 |
|
193 | 186 |
|
194 |
@qa_utils.DefineHook('cluster-master-failover') |
|
195 | 187 |
def TestClusterMasterFailover(): |
196 | 188 |
"""gnt-cluster masterfailover""" |
197 | 189 |
master = qa_config.GetMasterNode() |
... | ... | |
209 | 201 |
qa_config.ReleaseNode(failovermaster) |
210 | 202 |
|
211 | 203 |
|
212 |
@qa_utils.DefineHook('cluster-copyfile') |
|
213 | 204 |
def TestClusterCopyfile(): |
214 | 205 |
"""gnt-cluster copyfile""" |
215 | 206 |
master = qa_config.GetMasterNode() |
... | ... | |
234 | 225 |
_RemoveFileFromAllNodes(testname) |
235 | 226 |
|
236 | 227 |
|
237 |
@qa_utils.DefineHook('cluster-command') |
|
238 | 228 |
def TestClusterCommand(): |
239 | 229 |
"""gnt-cluster command""" |
240 | 230 |
master = qa_config.GetMasterNode() |
... | ... | |
252 | 242 |
_RemoveFileFromAllNodes(rfile) |
253 | 243 |
|
254 | 244 |
|
255 |
@qa_utils.DefineHook('cluster-destroy') |
|
256 | 245 |
def TestClusterDestroy(): |
257 | 246 |
"""gnt-cluster destroy""" |
258 | 247 |
master = qa_config.GetMasterNode() |
b/qa/qa_daemon.py | ||
---|---|---|
104 | 104 |
print qa_utils.FormatWarning(msg) |
105 | 105 |
|
106 | 106 |
|
107 |
@qa_utils.DefineHook('daemon-automatic-restart') |
|
108 | 107 |
def TestInstanceAutomaticRestart(node, instance): |
109 | 108 |
"""Test automatic restart of instance by ganeti-watcher. |
110 | 109 |
|
... | ... | |
126 | 125 |
utils.ShellQuoteArgs(cmd)).wait(), 0) |
127 | 126 |
|
128 | 127 |
|
129 |
@qa_utils.DefineHook('daemon-consecutive-failures') |
|
130 | 128 |
def TestInstanceConsecutiveFailures(node, instance): |
131 | 129 |
"""Test five consecutive instance failures. |
132 | 130 |
|
b/qa/qa_env.py | ||
---|---|---|
31 | 31 |
from qa_utils import AssertEqual, StartSSH |
32 | 32 |
|
33 | 33 |
|
34 |
@qa_utils.DefineHook('env-ssh-connection') |
|
35 | 34 |
def TestSshConnection(): |
36 | 35 |
"""Test SSH connection. |
37 | 36 |
|
... | ... | |
40 | 39 |
AssertEqual(StartSSH(node['primary'], 'exit').wait(), 0) |
41 | 40 |
|
42 | 41 |
|
43 |
@qa_utils.DefineHook('env-ganeti-commands') |
|
44 | 42 |
def TestGanetiCommands(): |
45 | 43 |
"""Test availibility of Ganeti commands. |
46 | 44 |
|
... | ... | |
59 | 57 |
AssertEqual(StartSSH(node['primary'], cmd).wait(), 0) |
60 | 58 |
|
61 | 59 |
|
62 |
@qa_utils.DefineHook('env-icmp-ping') |
|
63 | 60 |
def TestIcmpPing(): |
64 | 61 |
"""ICMP ping each node. |
65 | 62 |
|
b/qa/qa_instance.py | ||
---|---|---|
66 | 66 |
raise |
67 | 67 |
|
68 | 68 |
|
69 |
@qa_utils.DefineHook('instance-add-plain-disk') |
|
70 | 69 |
def TestInstanceAddWithPlainDisk(node): |
71 | 70 |
"""gnt-instance add -t plain""" |
72 | 71 |
return _DiskTest(node['primary'], 'plain') |
73 | 72 |
|
74 | 73 |
|
75 |
@qa_utils.DefineHook('instance-add-drbd-disk') |
|
76 | 74 |
def TestInstanceAddWithDrbdDisk(node, node2): |
77 | 75 |
"""gnt-instance add -t drbd""" |
78 | 76 |
return _DiskTest("%s:%s" % (node['primary'], node2['primary']), |
79 | 77 |
'drbd') |
80 | 78 |
|
81 | 79 |
|
82 |
@qa_utils.DefineHook('instance-remove') |
|
83 | 80 |
def TestInstanceRemove(instance): |
84 | 81 |
"""gnt-instance remove""" |
85 | 82 |
master = qa_config.GetMasterNode() |
... | ... | |
91 | 88 |
qa_config.ReleaseInstance(instance) |
92 | 89 |
|
93 | 90 |
|
94 |
@qa_utils.DefineHook('instance-startup') |
|
95 | 91 |
def TestInstanceStartup(instance): |
96 | 92 |
"""gnt-instance startup""" |
97 | 93 |
master = qa_config.GetMasterNode() |
... | ... | |
101 | 97 |
utils.ShellQuoteArgs(cmd)).wait(), 0) |
102 | 98 |
|
103 | 99 |
|
104 |
@qa_utils.DefineHook('instance-shutdown') |
|
105 | 100 |
def TestInstanceShutdown(instance): |
106 | 101 |
"""gnt-instance shutdown""" |
107 | 102 |
master = qa_config.GetMasterNode() |
... | ... | |
111 | 106 |
utils.ShellQuoteArgs(cmd)).wait(), 0) |
112 | 107 |
|
113 | 108 |
|
114 |
@qa_utils.DefineHook('instance-reboot') |
|
115 | 109 |
def TestInstanceReboot(instance): |
116 | 110 |
"""gnt-instance reboot""" |
117 | 111 |
master = qa_config.GetMasterNode() |
... | ... | |
123 | 117 |
utils.ShellQuoteArgs(cmd)).wait(), 0) |
124 | 118 |
|
125 | 119 |
|
126 |
@qa_utils.DefineHook('instance-reinstall') |
|
127 | 120 |
def TestInstanceReinstall(instance): |
128 | 121 |
"""gnt-instance reinstall""" |
129 | 122 |
master = qa_config.GetMasterNode() |
... | ... | |
133 | 126 |
utils.ShellQuoteArgs(cmd)).wait(), 0) |
134 | 127 |
|
135 | 128 |
|
136 |
@qa_utils.DefineHook('instance-failover') |
|
137 | 129 |
def TestInstanceFailover(instance): |
138 | 130 |
"""gnt-instance failover""" |
139 | 131 |
master = qa_config.GetMasterNode() |
... | ... | |
148 | 140 |
utils.ShellQuoteArgs(cmd)).wait(), 0) |
149 | 141 |
|
150 | 142 |
|
151 |
@qa_utils.DefineHook('instance-info') |
|
152 | 143 |
def TestInstanceInfo(instance): |
153 | 144 |
"""gnt-instance info""" |
154 | 145 |
master = qa_config.GetMasterNode() |
... | ... | |
158 | 149 |
utils.ShellQuoteArgs(cmd)).wait(), 0) |
159 | 150 |
|
160 | 151 |
|
161 |
@qa_utils.DefineHook('instance-modify') |
|
162 | 152 |
def TestInstanceModify(instance): |
163 | 153 |
"""gnt-instance modify""" |
164 | 154 |
master = qa_config.GetMasterNode() |
... | ... | |
191 | 181 |
utils.ShellQuoteArgs(cmd)).wait(), 0) |
192 | 182 |
|
193 | 183 |
|
194 |
@qa_utils.DefineHook('instance-list') |
|
195 | 184 |
def TestInstanceList(): |
196 | 185 |
"""gnt-instance list""" |
197 | 186 |
master = qa_config.GetMasterNode() |
... | ... | |
201 | 190 |
utils.ShellQuoteArgs(cmd)).wait(), 0) |
202 | 191 |
|
203 | 192 |
|
204 |
@qa_utils.DefineHook('instance-console') |
|
205 | 193 |
def TestInstanceConsole(instance): |
206 | 194 |
"""gnt-instance console""" |
207 | 195 |
master = qa_config.GetMasterNode() |
... | ... | |
211 | 199 |
utils.ShellQuoteArgs(cmd)).wait(), 0) |
212 | 200 |
|
213 | 201 |
|
214 |
@qa_utils.DefineHook('instance-replace-disks') |
|
215 | 202 |
def TestReplaceDisks(instance, pnode, snode, othernode): |
216 | 203 |
"""gnt-instance replace-disks""" |
217 | 204 |
master = qa_config.GetMasterNode() |
... | ... | |
240 | 227 |
utils.ShellQuoteArgs(cmd)).wait(), 0) |
241 | 228 |
|
242 | 229 |
|
243 |
@qa_utils.DefineHook('backup-export') |
|
244 | 230 |
def TestInstanceExport(instance, node): |
245 | 231 |
"""gnt-backup export""" |
246 | 232 |
master = qa_config.GetMasterNode() |
... | ... | |
252 | 238 |
return qa_utils.ResolveInstanceName(instance) |
253 | 239 |
|
254 | 240 |
|
255 |
@qa_utils.DefineHook('backup-import') |
|
256 | 241 |
def TestInstanceImport(node, newinst, expnode, name): |
257 | 242 |
"""gnt-backup import""" |
258 | 243 |
master = qa_config.GetMasterNode() |
... | ... | |
269 | 254 |
utils.ShellQuoteArgs(cmd)).wait(), 0) |
270 | 255 |
|
271 | 256 |
|
272 |
@qa_utils.DefineHook('backup-list') |
|
273 | 257 |
def TestBackupList(expnode): |
274 | 258 |
"""gnt-backup list""" |
275 | 259 |
master = qa_config.GetMasterNode() |
b/qa/qa_node.py | ||
---|---|---|
28 | 28 |
from qa_utils import AssertEqual, StartSSH |
29 | 29 |
|
30 | 30 |
|
31 |
@qa_utils.DefineHook('node-add') |
|
32 | 31 |
def _NodeAdd(node, readd=False): |
33 | 32 |
master = qa_config.GetMasterNode() |
34 | 33 |
|
... | ... | |
49 | 48 |
node['_added'] = True |
50 | 49 |
|
51 | 50 |
|
52 |
@qa_utils.DefineHook('node-remove') |
|
53 | 51 |
def _NodeRemove(node): |
54 | 52 |
master = qa_config.GetMasterNode() |
55 | 53 |
|
... | ... | |
75 | 73 |
_NodeRemove(node) |
76 | 74 |
|
77 | 75 |
|
78 |
@qa_utils.DefineHook('node-readd') |
|
79 | 76 |
def TestNodeReadd(node): |
80 | 77 |
"""gnt-node add --readd""" |
81 | 78 |
_NodeAdd(node, readd=True) |
82 | 79 |
|
83 | 80 |
|
84 |
@qa_utils.DefineHook('node-info') |
|
85 | 81 |
def TestNodeInfo(): |
86 | 82 |
"""gnt-node info""" |
87 | 83 |
master = qa_config.GetMasterNode() |
... | ... | |
91 | 87 |
utils.ShellQuoteArgs(cmd)).wait(), 0) |
92 | 88 |
|
93 | 89 |
|
94 |
@qa_utils.DefineHook('node-volumes') |
|
95 | 90 |
def TestNodeVolumes(): |
96 | 91 |
"""gnt-node volumes""" |
97 | 92 |
master = qa_config.GetMasterNode() |
... | ... | |
101 | 96 |
utils.ShellQuoteArgs(cmd)).wait(), 0) |
102 | 97 |
|
103 | 98 |
|
104 |
@qa_utils.DefineHook('node-failover') |
|
105 | 99 |
def TestNodeFailover(node, node2): |
106 | 100 |
"""gnt-node failover""" |
107 | 101 |
master = qa_config.GetMasterNode() |
... | ... | |
122 | 116 |
utils.ShellQuoteArgs(cmd)).wait(), 0) |
123 | 117 |
|
124 | 118 |
|
125 |
@qa_utils.DefineHook('node-evacuate') |
|
126 | 119 |
def TestNodeEvacuate(node, node2): |
127 | 120 |
"""gnt-node evacuate""" |
128 | 121 |
master = qa_config.GetMasterNode() |
b/qa/qa_os.py | ||
---|---|---|
39 | 39 |
_TEMP_OS_PATH = os.path.join(constants.OS_SEARCH_PATH[0], _TEMP_OS_NAME) |
40 | 40 |
|
41 | 41 |
|
42 |
@qa_utils.DefineHook('os-list') |
|
43 | 42 |
def TestOsList(): |
44 | 43 |
"""gnt-os list""" |
45 | 44 |
master = qa_config.GetMasterNode() |
... | ... | |
49 | 48 |
utils.ShellQuoteArgs(cmd)).wait(), 0) |
50 | 49 |
|
51 | 50 |
|
52 |
@qa_utils.DefineHook('os-diagnose') |
|
53 | 51 |
def TestOsDiagnose(): |
54 | 52 |
"""gnt-os diagnose""" |
55 | 53 |
master = qa_config.GetMasterNode() |
... | ... | |
128 | 126 |
_RemoveTempOs(node, dir) |
129 | 127 |
|
130 | 128 |
|
131 |
@qa_utils.DefineHook('os-valid') |
|
132 | 129 |
def TestOsValid(): |
133 | 130 |
"""Testing valid OS definition""" |
134 | 131 |
return _TestOs(1) |
135 | 132 |
|
136 | 133 |
|
137 |
@qa_utils.DefineHook('os-invalid') |
|
138 | 134 |
def TestOsInvalid(): |
139 | 135 |
"""Testing invalid OS definition""" |
140 | 136 |
return _TestOs(0) |
141 | 137 |
|
142 | 138 |
|
143 |
@qa_utils.DefineHook('os-partially-valid') |
|
144 | 139 |
def TestOsPartiallyValid(): |
145 | 140 |
"""Testing partially valid OS definition""" |
146 | 141 |
return _TestOs(2) |
b/qa/qa_rapi.py | ||
---|---|---|
97 | 97 |
AssertEqual(data, verify) |
98 | 98 |
|
99 | 99 |
|
100 |
@qa_utils.DefineHook('rapi-version') |
|
101 | 100 |
def TestVersion(): |
102 | 101 |
"""Testing remote API version. |
103 | 102 |
|
... | ... | |
107 | 106 |
]) |
108 | 107 |
|
109 | 108 |
|
110 |
@qa_utils.DefineHook('rapi-empty-cluster') |
|
111 | 109 |
def TestEmptyCluster(): |
112 | 110 |
"""Testing remote API on an empty cluster. |
113 | 111 |
|
... | ... | |
143 | 141 |
]) |
144 | 142 |
|
145 | 143 |
|
146 |
@qa_utils.DefineHook('rapi-instance') |
|
147 | 144 |
def TestInstance(instance): |
148 | 145 |
"""Testing getting instance(s) info via remote API. |
149 | 146 |
|
... | ... | |
168 | 165 |
]) |
169 | 166 |
|
170 | 167 |
|
171 |
@qa_utils.DefineHook('rapi-node') |
|
172 | 168 |
def TestNode(node): |
173 | 169 |
"""Testing getting node(s) info via remote API. |
174 | 170 |
|
b/qa/qa_tags.py | ||
---|---|---|
74 | 74 |
utils.ShellQuoteArgs(cmd)).wait(), 0) |
75 | 75 |
|
76 | 76 |
|
77 |
@qa_utils.DefineHook('tags-cluster') |
|
78 | 77 |
def TestClusterTags(): |
79 | 78 |
"""gnt-cluster tags""" |
80 | 79 |
_TestTags(constants.TAG_CLUSTER, "") |
81 | 80 |
|
82 | 81 |
|
83 |
@qa_utils.DefineHook('tags-node') |
|
84 | 82 |
def TestNodeTags(node): |
85 | 83 |
"""gnt-node tags""" |
86 | 84 |
_TestTags(constants.TAG_NODE, node["primary"]) |
87 | 85 |
|
88 | 86 |
|
89 |
@qa_utils.DefineHook('tags-instance') |
|
90 | 87 |
def TestInstanceTags(instance): |
91 | 88 |
"""gnt-instance tags""" |
92 | 89 |
_TestTags(constants.TAG_INSTANCE, instance["name"]) |
b/qa/qa_utils.py | ||
---|---|---|
39 | 39 |
_RESET_SEQ = None |
40 | 40 |
|
41 | 41 |
|
42 |
# List of all hooks |
|
43 |
_hooks = [] |
|
44 |
|
|
45 |
|
|
46 | 42 |
def _SetupColours(): |
47 | 43 |
"""Initializes the colour constants. |
48 | 44 |
|
... | ... | |
225 | 221 |
FormatWarning = lambda text: _FormatWithColor(text, _WARNING_SEQ) |
226 | 222 |
FormatError = lambda text: _FormatWithColor(text, _ERROR_SEQ) |
227 | 223 |
FormatInfo = lambda text: _FormatWithColor(text, _INFO_SEQ) |
228 |
|
|
229 |
|
|
230 |
def LoadHooks(): |
|
231 |
"""Load all QA hooks. |
|
232 |
|
|
233 |
""" |
|
234 |
hooks_dir = qa_config.get('options', {}).get('hooks-dir', None) |
|
235 |
if not hooks_dir: |
|
236 |
return |
|
237 |
if hooks_dir not in sys.path: |
|
238 |
sys.path.insert(0, hooks_dir) |
|
239 |
for name in utils.ListVisibleFiles(hooks_dir): |
|
240 |
if name.endswith('.py'): |
|
241 |
# Load and instanciate hook |
|
242 |
print "Loading hook %s" % name |
|
243 |
_hooks.append(__import__(name[:-3], None, None, ['']).hook()) |
|
244 |
|
|
245 |
|
|
246 |
class QaHookContext: |
|
247 |
"""Definition of context passed to hooks. |
|
248 |
|
|
249 |
""" |
|
250 |
name = None |
|
251 |
phase = None |
|
252 |
success = None |
|
253 |
args = None |
|
254 |
kwargs = None |
|
255 |
|
|
256 |
|
|
257 |
def _CallHooks(ctx): |
|
258 |
"""Calls all hooks with the given context. |
|
259 |
|
|
260 |
""" |
|
261 |
if not _hooks: |
|
262 |
return |
|
263 |
|
|
264 |
name = "%s-%s" % (ctx.phase, ctx.name) |
|
265 |
if ctx.success is not None: |
|
266 |
msg = "%s (success=%s)" % (name, ctx.success) |
|
267 |
else: |
|
268 |
msg = name |
|
269 |
print FormatInfo("Begin %s" % msg) |
|
270 |
for hook in _hooks: |
|
271 |
hook.run(ctx) |
|
272 |
print FormatInfo("End %s" % name) |
|
273 |
|
|
274 |
|
|
275 |
def DefineHook(name): |
|
276 |
"""Wraps a function with calls to hooks. |
|
277 |
|
|
278 |
Usage: prefix function with @qa_utils.DefineHook(...) |
|
279 |
|
|
280 |
This is based on PEP 318, "Decorators for Functions and Methods". |
|
281 |
|
|
282 |
""" |
|
283 |
def wrapper(fn): |
|
284 |
def new_f(*args, **kwargs): |
|
285 |
# Create context |
|
286 |
ctx = QaHookContext() |
|
287 |
ctx.name = name |
|
288 |
ctx.phase = 'pre' |
|
289 |
ctx.args = args |
|
290 |
ctx.kwargs = kwargs |
|
291 |
|
|
292 |
_CallHooks(ctx) |
|
293 |
try: |
|
294 |
ctx.phase = 'post' |
|
295 |
ctx.success = True |
|
296 |
try: |
|
297 |
# Call real function |
|
298 |
return fn(*args, **kwargs) |
|
299 |
except: |
|
300 |
ctx.success = False |
|
301 |
raise |
|
302 |
finally: |
|
303 |
_CallHooks(ctx) |
|
304 |
|
|
305 |
# Override function metadata |
|
306 |
new_f.func_name = fn.func_name |
|
307 |
new_f.func_doc = fn.func_doc |
|
308 |
|
|
309 |
return new_f |
|
310 |
|
|
311 |
return wrapper |
Also available in: Unified diff