Merge lp:~javier.collado/utah/bug1178367 into lp:utah
- bug1178367
- Merge into dev
Proposed by
Javier Collado
Status: | Merged |
---|---|
Merged at revision: | 904 |
Proposed branch: | lp:~javier.collado/utah/bug1178367 |
Merge into: | lp:utah |
Diff against target: |
680 lines (+78/-348) 6 files modified
debian/changelog (+2/-0) debian/control (+1/-9) debian/rules (+1/-9) examples/run_utah_tests.py (+2/-108) tests/test_parser.py (+72/-0) utah/parser.py (+0/-222) |
To merge this branch: | bzr merge lp:~javier.collado/utah/bug1178367 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Andy Doan (community) | Approve | ||
Review via email: mp+163339@code.launchpad.net |
Commit message
Description of the change
This branch fixes the parsing of the gigabytes option and adds a few test cases
to verify this.
Besides this, the `utah.parser` module and the `utah-parser` package are
removed since they aren't used anymore. The `utah.parser` module is now used to
have there the parser for the utah server script since that makes unit testing
easier.
To post a comment you must log in.
Revision history for this message
Andy Doan (doanac) : | # |
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'debian/changelog' |
2 | --- debian/changelog 2013-05-09 23:36:07 +0000 |
3 | +++ debian/changelog 2013-05-10 16:56:25 +0000 |
4 | @@ -8,6 +8,8 @@ |
5 | * Apply retry strategy to install UTAH client package (LP: #1175732) |
6 | * Added phoenix manpage (LP: #1067704) |
7 | * Apply all overrides in tslist.run to the test cases (LP: #1178238) |
8 | + * Set disksizes default directly instead of via argparse (LP: |
9 | + #1178367) |
10 | |
11 | -- Javier Collado <javier.collado@canonical.com> Tue, 07 May 2013 16:06:48 +0200 |
12 | |
13 | |
14 | === modified file 'debian/control' |
15 | --- debian/control 2013-05-08 14:45:47 +0000 |
16 | +++ debian/control 2013-05-10 16:56:25 +0000 |
17 | @@ -23,8 +23,7 @@ |
18 | |
19 | Package: utah-all |
20 | Architecture: all |
21 | -Depends: ${misc:Depends}, ${python:Depends}, utah-bamboofeeder, utah-cobbler, |
22 | - utah-parser |
23 | +Depends: ${misc:Depends}, ${python:Depends}, utah-bamboofeeder, utah-cobbler |
24 | Description: Ubuntu Test Automation Harness Complete Package |
25 | Automation framework for testing in Ubuntu, all sections |
26 | |
27 | @@ -59,10 +58,3 @@ |
28 | Depends: ${misc:Depends}, ${python:Depends} |
29 | Description: Ubuntu Test Automation Harness Common Files |
30 | Automation framework for testing in Ubuntu, common files |
31 | - |
32 | -Package: utah-parser |
33 | -Architecture: all |
34 | -Depends: ${misc:Depends}, ${python:Depends}, |
35 | - python-jsonschema (>= 1.3~), python-yaml, utah-common |
36 | -Description: Ubuntu Test Automation Harness Parser |
37 | - Automation framework for testing in Ubuntu, result parser |
38 | |
39 | === modified file 'debian/rules' |
40 | --- debian/rules 2013-05-08 13:28:00 +0000 |
41 | +++ debian/rules 2013-05-10 16:56:25 +0000 |
42 | @@ -34,18 +34,14 @@ |
43 | |
44 | override_dh_auto_install: |
45 | # utah and utah-client both live in the utah directory |
46 | - # utah-parser lives in that tree as well |
47 | # utah should only install the provisioning subdirectory, and utah-client should install everything else |
48 | - # except parser.py, which is now its own package |
49 | - # and __init__.py, which is now in the common package |
50 | + # except __init__.py, which is now in the common package |
51 | # The baremetal subdirectory in the provisioning directory is now 3 packages |
52 | # If we just use dh_auto_install, all packages will get everything |
53 | # We start by building the whole thing |
54 | set -e && for pyvers in $(PYVERS); do python$$pyvers setup.py install --install-layout=deb --root=$(CURDIR); done |
55 | # Next, we move the built provisioning directory aside for later use |
56 | mv build/*/utah/provisioning . |
57 | - # Same with parser.py |
58 | - mv build/*/utah/parser.py . |
59 | # And __init__.py |
60 | mv build/*/utah/__init__.py . |
61 | # Now we install into the utah-client directory, since provisioning is removed, using --skip-build to not rebuild it |
62 | @@ -58,10 +54,6 @@ |
63 | mv build/*/utah/provisioning/baremetal . |
64 | # Now we install just the provisioning directory, again using --skip-build into the utah package tree |
65 | set -e && for pyvers in $(PYVERS); do python$$pyvers setup.py install --skip-build --install-layout=deb --root=$(CURDIR)/debian/utah; done |
66 | - # And now we put back the parser and install that |
67 | - rm -r build/*/utah/* |
68 | - mv parser.py build/*/utah |
69 | - set -e && for pyvers in $(PYVERS); do python$$pyvers setup.py install --skip-build --install-layout=deb --root=$(CURDIR)/debian/utah-parser; done |
70 | # And now we put back the init file and install that |
71 | rm -r build/*/utah/* |
72 | mv __init__.py build/*/utah |
73 | |
74 | === modified file 'examples/run_utah_tests.py' |
75 | --- examples/run_utah_tests.py 2013-05-01 23:57:13 +0000 |
76 | +++ examples/run_utah_tests.py 2013-05-10 16:56:25 +0000 |
77 | @@ -17,8 +17,6 @@ |
78 | |
79 | """Provision a machine a run a test.""" |
80 | |
81 | - |
82 | -import argparse |
83 | import logging |
84 | import os |
85 | import sys |
86 | @@ -31,16 +29,15 @@ |
87 | from utah.cleanup import cleanup |
88 | from utah.exceptions import UTAHException |
89 | from utah.group import check_user_group, print_group_error_message |
90 | +from utah.parser import get_parser, parse_args # NOQA |
91 | from utah.provisioning.ssh import ProvisionedMachine |
92 | from utah.provisioning.vm import TinySQLiteInventory |
93 | from utah.run import ( |
94 | configure_logging, |
95 | - master_runlist_argument, |
96 | run_tests, |
97 | ReturnCodes, |
98 | ) |
99 | from utah.timeout import timeout, UTAHTimeout |
100 | -from utah.url import url_argument |
101 | |
102 | |
103 | MISSING = [] |
104 | @@ -59,108 +56,6 @@ |
105 | MISSING.append('baremetal') |
106 | |
107 | |
108 | -def get_parser(): |
109 | - parser = argparse.ArgumentParser( |
110 | - description=('Provision a machine ' |
111 | - 'and run one or more UTAH runlists there.\n\n' |
112 | - 'The appropriate run_*.py script will be called, ' |
113 | - 'depending on the parameters passed.'), |
114 | - epilog=("For example:\n" |
115 | - "Provision a VM using a precise server image " |
116 | - "with i386 architecture and run the given runlist\n" |
117 | - "\t%(prog)s -s precise -t server -a i386 \\\n" |
118 | - "\t\t/usr/share/utah/client/examples/master.run"), |
119 | - formatter_class=argparse.RawDescriptionHelpFormatter) |
120 | - parser.add_argument('-m', '--machinetype', metavar='MACHINETYPE', |
121 | - choices=('physical', 'virtual'), |
122 | - default=config.machinetype, |
123 | - help='Type of machine to provision (%(choices)s) ' |
124 | - '(Default is %(default)s)') |
125 | - parser.add_argument('-v', '--variant', |
126 | - default=config.variant, |
127 | - help='Variant of architecture, i.e., armel, armhf') |
128 | - parser.add_argument('--skip-provisioning', action='store_true', |
129 | - help='Reuse a system that is already provisioned ' |
130 | - '(name argument must be passed)') |
131 | - parser.add_argument('runlist', metavar='runlist', |
132 | - type=master_runlist_argument, |
133 | - help='URLs of runlist files to run') |
134 | - parser.add_argument('-s', '--series', metavar='SERIES', |
135 | - choices=config.serieschoices, |
136 | - default=config.series, |
137 | - help='Series to use for installation (%(choices)s) ' |
138 | - '(Default is %(default)s)') |
139 | - parser.add_argument('-t', '--type', metavar='TYPE', |
140 | - choices=('desktop', 'server', 'mini', 'alternate'), |
141 | - default=config.installtype, |
142 | - help='Install type to use for installation ' |
143 | - '(%(choices)s) (Default is %(default)s)') |
144 | - parser.add_argument('-a', '--arch', metavar='ARCH', |
145 | - choices=('i386', 'amd64', 'arm'), |
146 | - default=config.arch, |
147 | - help='Architecture to use for installation ' |
148 | - '(%(choices)s) (Default is %(default)s)') |
149 | - parser.add_argument('-n', '--no-destroy', action='store_true', |
150 | - help='Preserve VM after tests have run') |
151 | - parser.add_argument('-d', '--debug', action='store_true', |
152 | - help='Enable debug logging') |
153 | - parser.add_argument('-j', '--json', action='store_true', |
154 | - help='Enable json logging (default is YAML)') |
155 | - parser.add_argument('-f', '--files', action='append', |
156 | - help='File or directory to copy from test system ') |
157 | - parser.add_argument('-o', '--outdir', |
158 | - help=('Directory to store locally copied files ' |
159 | - '(Default is {}/machine-name)' |
160 | - .format(config.logpath))) |
161 | - parser.add_argument('--dumplogs', action='store_true', |
162 | - help='Write client output logs to standard out') |
163 | - parser.add_argument('--outputpreseed', action='store_true', |
164 | - help='Copy preseed to logs directory and list as ' |
165 | - 'log file in output') |
166 | - parser.add_argument('-i', '--image', type=url_argument, |
167 | - default=config.image, |
168 | - help='Image/ISO file to use for installation') |
169 | - parser.add_argument('-p', '--preseed', type=url_argument, |
170 | - default=config.preseed, |
171 | - help='Preseed file to use for installation') |
172 | - parser.add_argument('-b', '--boot', |
173 | - default=config.boot, |
174 | - help='Boot arguments for initial installation') |
175 | - parser.add_argument('--rewrite', |
176 | - choices=('all', 'minimal', 'casperonly', 'none'), |
177 | - default=config.rewrite, |
178 | - help='Set level of automatic configuration rewriting ' |
179 | - '(Default is %(default)s)') |
180 | - parser.add_argument('-k', '--kernel', type=url_argument, |
181 | - default=config.kernel, |
182 | - help='Kernel file to use for installation') |
183 | - parser.add_argument('-r', '--initrd', type=url_argument, |
184 | - default=config.initrd, |
185 | - help='InitRD file to use for installation') |
186 | - parser.add_argument('--name', |
187 | - default=config.name, |
188 | - help='Name of machine to provision') |
189 | - parser.add_argument('-e', '--emulator', |
190 | - default=config.emulator, |
191 | - help='Emulator to use (kvm and qemu are supported, ' |
192 | - 'kvm will be favored if available)') |
193 | - parser.add_argument('-x', '--xml', type=url_argument, |
194 | - default=config.xml, |
195 | - help='XML VM definition file ' |
196 | - '(Default is %(default)s)') |
197 | - parser.add_argument('-g', '--gigabytes', action='append', |
198 | - default=config.disksizes, |
199 | - help='Size in gigabytes of virtual disk, ' |
200 | - 'specify more than once for multiple disks ' |
201 | - '(Default is %(default)s)') |
202 | - parser.add_argument('--diskbus', metavar='DISKBUS', |
203 | - choices=('virtio', 'sata', 'ide'), |
204 | - default=config.diskbus, |
205 | - help='Disk bus to use for customvm installation ' |
206 | - '(%(choices)s) (Default is %(default)s)') |
207 | - return parser |
208 | - |
209 | - |
210 | def _get_machine(args): |
211 | if args.skip_provisioning: |
212 | # TBD: Inventory should be used to verify machine |
213 | @@ -210,8 +105,7 @@ |
214 | |
215 | |
216 | def run_utah_tests(args=None): |
217 | - if args is None: |
218 | - args = get_parser().parse_args() |
219 | + args = parse_args() |
220 | |
221 | if not check_user_group(): |
222 | print_group_error_message(__file__) |
223 | |
224 | === added file 'tests/test_parser.py' |
225 | --- tests/test_parser.py 1970-01-01 00:00:00 +0000 |
226 | +++ tests/test_parser.py 2013-05-10 16:56:25 +0000 |
227 | @@ -0,0 +1,72 @@ |
228 | +# Ubuntu Testing Automation Harness |
229 | +# Copyright 2013 Canonical Ltd. |
230 | + |
231 | +# This program is free software: you can redistribute it and/or modify it |
232 | +# under the terms of the GNU General Public License version 3, as published |
233 | +# by the Free Software Foundation. |
234 | + |
235 | +# This program is distributed in the hope that it will be useful, but |
236 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
237 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
238 | +# PURPOSE. See the GNU General Public License for more details. |
239 | + |
240 | +# You should have received a copy of the GNU General Public License along |
241 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
242 | + |
243 | +"""Unit tests for the utah.parser module.""" |
244 | + |
245 | +import unittest |
246 | + |
247 | +from mock import patch, DEFAULT |
248 | + |
249 | +from utah import config |
250 | +from utah.parser import parse_args |
251 | + |
252 | + |
253 | +class TestParser(unittest.TestCase): |
254 | + |
255 | + """Tests that command line parsing works as expected.""" |
256 | + |
257 | + def parse_args_wrapper(self, argv): |
258 | + """A wrapper to ensure that runlist argument passes validation. |
259 | + |
260 | + :param argv: Command line arguments to be tested |
261 | + :type argv: list |
262 | + :returns: Parse arguments |
263 | + :rtype: `argparse.Namespace` |
264 | + |
265 | + """ |
266 | + with patch.multiple('utah.run', |
267 | + url_argument=DEFAULT, |
268 | + parse_yaml_file=DEFAULT) as patches: |
269 | + patches['url_argument'].return_value = '<local_runlist_file>' |
270 | + patches['parse_yaml_file'].return_value = { |
271 | + 'testsuites': [ |
272 | + {'name': 'test_suite_name', |
273 | + 'fetch_method': 'dev', |
274 | + 'fetch_location': '<fetch_location>', |
275 | + }, |
276 | + ] |
277 | + } |
278 | + return parse_args(argv) |
279 | + |
280 | + def test_gigabytes_default(self): |
281 | + """Verify that gigabytes is set to default value if not passed.""" |
282 | + args = self.parse_args_wrapper(['<runlist_file>']) |
283 | + self.assertEqual(args.gigabytes, config.disksizes) |
284 | + |
285 | + def test_gigabytes_one_argument(self): |
286 | + """Verify that gigabytes is set to the argument passed.""" |
287 | + gigabytes = '3' |
288 | + args = self.parse_args_wrapper(['--gigabytes', gigabytes, |
289 | + '<runlist_file>']) |
290 | + self.assertEqual(args.gigabytes, [gigabytes]) |
291 | + |
292 | + def test_gigabytes_multiple_arguments(self): |
293 | + """Verify that gigabytes is set to the arguments passed.""" |
294 | + gigabytes = ['3', '5', '7'] |
295 | + args = self.parse_args_wrapper(['--gigabytes', gigabytes[0], |
296 | + '--gigabytes', gigabytes[1], |
297 | + '--gigabytes', gigabytes[2], |
298 | + '<runlist_file>']) |
299 | + self.assertEqual(args.gigabytes, gigabytes) |
300 | |
301 | === added file 'utah/parser.py' |
302 | --- utah/parser.py 1970-01-01 00:00:00 +0000 |
303 | +++ utah/parser.py 2013-05-10 16:56:25 +0000 |
304 | @@ -0,0 +1,149 @@ |
305 | +# Ubuntu Testing Automation Harness |
306 | +# Copyright 2012 Canonical Ltd. |
307 | + |
308 | +# This program is free software: you can redistribute it and/or modify it |
309 | +# under the terms of the GNU General Public License version 3, as published |
310 | +# by the Free Software Foundation. |
311 | + |
312 | +# This program is distributed in the hope that it will be useful, but |
313 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
314 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
315 | +# PURPOSE. See the GNU General Public License for more details. |
316 | + |
317 | +# You should have received a copy of the GNU General Public License along |
318 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
319 | + |
320 | +"""Command line parser for the utah server script.""" |
321 | + |
322 | +import argparse |
323 | +import sys |
324 | + |
325 | +from utah import config |
326 | +from utah.run import master_runlist_argument |
327 | +from utah.url import url_argument |
328 | + |
329 | + |
330 | +def parse_args(argv=None): |
331 | + """Parse command line arguments. |
332 | + |
333 | + :param argv: Command line arguments to be parsed |
334 | + :type argv: list |
335 | + :returns: Parse arguments |
336 | + :rtype: `argparse.Namespace` |
337 | + |
338 | + """ |
339 | + |
340 | + if argv is None: |
341 | + argv = sys.argv[1:] |
342 | + |
343 | + args = get_parser().parse_args(argv) |
344 | + if args.gigabytes is None: |
345 | + args.gigabytes = config.disksizes |
346 | + return args |
347 | + |
348 | + |
349 | +def get_parser(): |
350 | + """Get command line parser. |
351 | + |
352 | + :returns: Parser object |
353 | + :rtype: `argparse.ArgumentParser` |
354 | + |
355 | + """ |
356 | + parser = argparse.ArgumentParser( |
357 | + description=('Provision a machine ' |
358 | + 'and run one or more UTAH runlists there.\n\n' |
359 | + 'The appropriate run_*.py script will be called, ' |
360 | + 'depending on the parameters passed.'), |
361 | + epilog=("For example:\n" |
362 | + "Provision a VM using a precise server image " |
363 | + "with i386 architecture and run the given runlist\n" |
364 | + "\t%(prog)s -s precise -t server -a i386 \\\n" |
365 | + "\t\t/usr/share/utah/client/examples/master.run"), |
366 | + formatter_class=argparse.RawDescriptionHelpFormatter) |
367 | + parser.add_argument('-m', '--machinetype', metavar='MACHINETYPE', |
368 | + choices=('physical', 'virtual'), |
369 | + default=config.machinetype, |
370 | + help='Type of machine to provision (%(choices)s) ' |
371 | + '(Default is %(default)s)') |
372 | + parser.add_argument('-v', '--variant', |
373 | + default=config.variant, |
374 | + help='Variant of architecture, i.e., armel, armhf') |
375 | + parser.add_argument('--skip-provisioning', action='store_true', |
376 | + help='Reuse a system that is already provisioned ' |
377 | + '(name argument must be passed)') |
378 | + parser.add_argument('runlist', metavar='runlist', |
379 | + type=master_runlist_argument, |
380 | + help='URLs of runlist files to run') |
381 | + parser.add_argument('-s', '--series', metavar='SERIES', |
382 | + choices=config.serieschoices, |
383 | + default=config.series, |
384 | + help='Series to use for installation (%(choices)s) ' |
385 | + '(Default is %(default)s)') |
386 | + parser.add_argument('-t', '--type', metavar='TYPE', |
387 | + choices=('desktop', 'server', 'mini', 'alternate'), |
388 | + default=config.installtype, |
389 | + help='Install type to use for installation ' |
390 | + '(%(choices)s) (Default is %(default)s)') |
391 | + parser.add_argument('-a', '--arch', metavar='ARCH', |
392 | + choices=('i386', 'amd64', 'arm'), |
393 | + default=config.arch, |
394 | + help='Architecture to use for installation ' |
395 | + '(%(choices)s) (Default is %(default)s)') |
396 | + parser.add_argument('-n', '--no-destroy', action='store_true', |
397 | + help='Preserve VM after tests have run') |
398 | + parser.add_argument('-d', '--debug', action='store_true', |
399 | + help='Enable debug logging') |
400 | + parser.add_argument('-j', '--json', action='store_true', |
401 | + help='Enable json logging (default is YAML)') |
402 | + parser.add_argument('-f', '--files', action='append', |
403 | + help='File or directory to copy from test system ') |
404 | + parser.add_argument('-o', '--outdir', |
405 | + help=('Directory to store locally copied files ' |
406 | + '(Default is {}/machine-name)' |
407 | + .format(config.logpath))) |
408 | + parser.add_argument('--dumplogs', action='store_true', |
409 | + help='Write client output logs to standard out') |
410 | + parser.add_argument('--outputpreseed', action='store_true', |
411 | + help='Copy preseed to logs directory and list as ' |
412 | + 'log file in output') |
413 | + parser.add_argument('-i', '--image', type=url_argument, |
414 | + default=config.image, |
415 | + help='Image/ISO file to use for installation') |
416 | + parser.add_argument('-p', '--preseed', type=url_argument, |
417 | + default=config.preseed, |
418 | + help='Preseed file to use for installation') |
419 | + parser.add_argument('-b', '--boot', |
420 | + default=config.boot, |
421 | + help='Boot arguments for initial installation') |
422 | + parser.add_argument('--rewrite', |
423 | + choices=('all', 'minimal', 'casperonly', 'none'), |
424 | + default=config.rewrite, |
425 | + help='Set level of automatic configuration rewriting ' |
426 | + '(Default is %(default)s)') |
427 | + parser.add_argument('-k', '--kernel', type=url_argument, |
428 | + default=config.kernel, |
429 | + help='Kernel file to use for installation') |
430 | + parser.add_argument('-r', '--initrd', type=url_argument, |
431 | + default=config.initrd, |
432 | + help='InitRD file to use for installation') |
433 | + parser.add_argument('--name', |
434 | + default=config.name, |
435 | + help='Name of machine to provision') |
436 | + parser.add_argument('-e', '--emulator', |
437 | + default=config.emulator, |
438 | + help='Emulator to use (kvm and qemu are supported, ' |
439 | + 'kvm will be favored if available)') |
440 | + parser.add_argument('-x', '--xml', type=url_argument, |
441 | + default=config.xml, |
442 | + help='XML VM definition file ' |
443 | + '(Default is %(default)s)') |
444 | + parser.add_argument('-g', '--gigabytes', action='append', |
445 | + help='Size in gigabytes of virtual disk, ' |
446 | + 'specify more than once for multiple disks ' |
447 | + '(Default is {})'.format(config.disksizes)) |
448 | + parser.add_argument('--diskbus', metavar='DISKBUS', |
449 | + choices=('virtio', 'sata', 'ide'), |
450 | + default=config.diskbus, |
451 | + help='Disk bus to use for customvm installation ' |
452 | + '(%(choices)s) (Default is %(default)s)') |
453 | + return parser |
454 | |
455 | === removed file 'utah/parser.py' |
456 | --- utah/parser.py 2013-04-03 21:17:26 +0000 |
457 | +++ utah/parser.py 1970-01-01 00:00:00 +0000 |
458 | @@ -1,222 +0,0 @@ |
459 | -# Ubuntu Testing Automation Harness |
460 | -# Copyright 2012 Canonical Ltd. |
461 | - |
462 | -# This program is free software: you can redistribute it and/or modify it |
463 | -# under the terms of the GNU General Public License version 3, as published |
464 | -# by the Free Software Foundation. |
465 | - |
466 | -# This program is distributed in the hope that it will be useful, but |
467 | -# WITHOUT ANY WARRANTY; without even the implied warranties of |
468 | -# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
469 | -# PURPOSE. See the GNU General Public License for more details. |
470 | - |
471 | -# You should have received a copy of the GNU General Public License along |
472 | -# with this program. If not, see <http://www.gnu.org/licenses/>. |
473 | - |
474 | -"""UTAH Client log parser.""" |
475 | - |
476 | - |
477 | -import argparse |
478 | -import jsonschema |
479 | -import logging |
480 | -import urllib2 |
481 | -import yaml |
482 | - |
483 | - |
484 | -class ParserError(Exception): |
485 | - |
486 | - """Module level parse error exception.""" |
487 | - |
488 | - pass |
489 | - |
490 | - |
491 | -class UTAHParser(object): |
492 | - |
493 | - """UTAH Client result parser class.""" |
494 | - |
495 | - COMMAND_SCHEMA = { |
496 | - 'type': 'object', |
497 | - 'properties': { |
498 | - 'cmd_type': {'type': 'string'}, |
499 | - 'command': {'type': 'string'}, |
500 | - 'returncode': {'type': 'integer'}, |
501 | - 'start_time': {'type': 'string'}, |
502 | - 'stderr': {'type': 'string'}, |
503 | - 'stdout': {'type': 'string'}, |
504 | - 'testcase': {'type': 'string'}, |
505 | - 'testsuite': {'type': 'string'}, |
506 | - 'time_delta': {'type': 'string'}, |
507 | - 'user': {'type': 'string'}, |
508 | - }, |
509 | - } |
510 | - |
511 | - CLIENT_OUTPUT_SCHEMA = { |
512 | - 'type': 'object', |
513 | - 'properties': { |
514 | - 'runlist': { |
515 | - 'type': 'string', |
516 | - 'required': True, |
517 | - }, |
518 | - 'ran_at': { |
519 | - 'type': 'string', |
520 | - 'required': True, |
521 | - }, |
522 | - 'commands': { |
523 | - 'type': 'array', |
524 | - 'items': {'type': COMMAND_SCHEMA}, |
525 | - 'required': True, |
526 | - }, |
527 | - 'fetch_errors': { |
528 | - 'type': 'integer', |
529 | - 'required': True, |
530 | - }, |
531 | - 'errors': { |
532 | - 'type': 'integer', |
533 | - 'required': True, |
534 | - }, |
535 | - 'failures': { |
536 | - 'type': 'integer', |
537 | - 'required': True, |
538 | - }, |
539 | - 'passes': { |
540 | - 'type': 'integer', |
541 | - 'required': True, |
542 | - }, |
543 | - 'uname': { |
544 | - 'type': 'array', |
545 | - 'items': {'type': 'string'}, |
546 | - 'required': True, |
547 | - }, |
548 | - 'media-info': { |
549 | - 'type': 'string', |
550 | - 'required': True, |
551 | - }, |
552 | - 'install_type': { |
553 | - 'type': 'string', |
554 | - 'required': True, |
555 | - }, |
556 | - 'arch': { |
557 | - 'type': 'string', |
558 | - 'required': True, |
559 | - }, |
560 | - 'release': { |
561 | - 'type': 'string', |
562 | - 'required': True, |
563 | - }, |
564 | - 'build_number': { |
565 | - 'type': 'string', |
566 | - 'required': True, |
567 | - }, |
568 | - }, |
569 | - } |
570 | - |
571 | - def parse(self, logdata, as_string=False): |
572 | - """Parse utah client results. |
573 | - |
574 | - :param logdata: |
575 | - should be either a filename or a handle to a file object. |
576 | - |
577 | - :returns: the parsed yaml data or None. |
578 | - |
579 | - :raises: ParserError on exceptions. |
580 | - |
581 | - """ |
582 | - |
583 | - if as_string: |
584 | - return self._parse_string(logdata) |
585 | - elif isinstance(logdata, str): |
586 | - return self._parse_logfile(logdata) |
587 | - else: |
588 | - return self._parse_stream(logdata) |
589 | - |
590 | - def _parse_stream(self, stream): |
591 | - """Parse client output from stream. |
592 | - |
593 | - :returns: validated decoded YAML data. |
594 | - |
595 | - :raises: ParseError |
596 | - |
597 | - """ |
598 | - try: |
599 | - data = yaml.load(stream) |
600 | - except yaml.YAMLError as e: |
601 | - logging.error(e) |
602 | - raise ParserError(e.message) |
603 | - |
604 | - # Allow empty yaml files |
605 | - if data is None: |
606 | - return data |
607 | - |
608 | - try: |
609 | - jsonschema.validate(data, self.CLIENT_OUTPUT_SCHEMA) |
610 | - except jsonschema.ValidationError as e: |
611 | - logging.error(e) |
612 | - raise ParserError(e.message) |
613 | - |
614 | - return data |
615 | - |
616 | - def _parse_logfile(self, logfile): |
617 | - """Parse client output log. |
618 | - |
619 | - :returns: validated decoded YAML data. |
620 | - |
621 | - :raises: ParseError |
622 | - |
623 | - """ |
624 | - data = None |
625 | - |
626 | - if logfile.startswith('http'): |
627 | - try: |
628 | - fp = urllib2.urlopen(logfile) |
629 | - except IOError as err: |
630 | - raise ParserError( |
631 | - 'IOError when downloading {}: {}' |
632 | - .format(logfile, err)) |
633 | - except urllib2.ContentTooShortError as err: |
634 | - raise ParserError( |
635 | - 'Error when downloading {} (probably interrupted): {}' |
636 | - .format(logfile, err)) |
637 | - data = self._parse_stream(fp) |
638 | - else: |
639 | - with open(logfile, 'r') as fp: |
640 | - data = self._parse_stream(fp) |
641 | - |
642 | - return data |
643 | - |
644 | - def _parse_string(self, log_data): |
645 | - """Parse client data from a string. |
646 | - |
647 | - :returns: validated decoded YAML data. |
648 | - |
649 | - :raises: ParseError |
650 | - |
651 | - """ |
652 | - try: |
653 | - data = yaml.load(log_data) |
654 | - |
655 | - # Allow empty yaml files |
656 | - if data is None: |
657 | - return data |
658 | - except yaml.YAMLError as e: |
659 | - logging.error(e) |
660 | - raise ParserError(e.message) |
661 | - |
662 | - try: |
663 | - jsonschema.validate(data, self.CLIENT_OUTPUT_SCHEMA) |
664 | - except jsonschema.ValidationError as e: |
665 | - logging.error(e) |
666 | - raise ParserError(e.message) |
667 | - |
668 | - return data |
669 | - |
670 | - |
671 | -if __name__ == "__main__": |
672 | - arg_parser = argparse.ArgumentParser(description='phoenix bootstrapper') |
673 | - arg_parser.add_argument('logfile', metavar='LOGFILE', type=str, |
674 | - help='log file to parse') |
675 | - |
676 | - args = arg_parser.parse_args() |
677 | - |
678 | - parser = UTAHParser() |
679 | - data = parser.parse(args.logfile) |
680 | - print(data) |