Status: | Merged |
---|---|
Merge reported by: | Vincent Ladeuil |
Merged at revision: | not available |
Proposed branch: | lp:~vila/uci-vms/py2 |
Merge into: | lp:uci-vms |
Diff against target: |
1424 lines (+279/-146) 30 files modified
NEWS.rst (+6/-0) TODO.rst (+2/-0) debian/changelog (+6/-0) debian/control (+16/-3) debian/copyright (+4/-1) debian/python-uci-vms.install (+2/-0) debian/python3-uci-vms.install (+2/-0) debian/rules (+2/-1) debian/tests/control (+4/-0) debian/tests/upstream2 (+2/-0) setup.py (+12/-3) uci-vms2 (+24/-0) ucivms/__init__.py (+1/-1) ucivms/commands.py (+14/-12) ucivms/config.py (+15/-7) ucivms/errors.py (+11/-11) ucivms/logs.py (+1/-1) ucivms/monitors.py (+3/-3) ucivms/subprocesses.py (+2/-2) ucivms/tests/features.py (+2/-2) ucivms/tests/test_commands.py (+27/-26) ucivms/tests/test_config.py (+11/-10) ucivms/tests/test_logs.py (+3/-3) ucivms/tests/test_monitors.py (+3/-4) ucivms/tests/test_ssh.py (+7/-5) ucivms/tests/test_subprocesses.py (+19/-8) ucivms/tests/test_timeouts.py (+16/-6) ucivms/tests/test_vms.py (+23/-18) ucivms/timeouts.py (+17/-9) ucivms/vms.py (+22/-10) |
To merge this branch: | bzr merge lp:~vila/uci-vms/py2 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Leo Arias (community) | Needs Fixing | ||
Review via email:
|
Commit message
Restore python2 support
Description of the change
Restore python2 support as a pre-requisite for supporting the nova class (novaclient may be available for python3 in wily at best).
In the mean time... uci-vms needs to support both python2 and python3...
To post a comment you must log in.
Revision history for this message
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Vincent Ladeuil (vila) wrote : | # |
Thanks for the review ! All typos fixed where needed, see inline answers.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'NEWS.rst' |
2 | --- NEWS.rst 2015-07-11 15:44:56 +0000 |
3 | +++ NEWS.rst 2015-07-22 17:15:37 +0000 |
4 | @@ -4,6 +4,12 @@ |
5 | |
6 | Overview of changes to uci-vms in reverse chronological order. |
7 | |
8 | +dev |
9 | +=== |
10 | + |
11 | +* Since timeouts are used in a 'try/sleep' loop, force the last value to be |
12 | + zero since there is no point waiting it no further attempt is to be made. |
13 | + |
14 | 0.1.5 |
15 | ===== |
16 | |
17 | |
18 | === modified file 'TODO.rst' |
19 | --- TODO.rst 2015-07-10 22:25:55 +0000 |
20 | +++ TODO.rst 2015-07-22 17:15:37 +0000 |
21 | @@ -1,3 +1,5 @@ |
22 | +* The error when vm.release is not set is obscure. |
23 | + |
24 | * Ensure that vms can be created/used without any vm.ssh_keys at all. With |
25 | vm.ssh_opts set to ignore host checking and using /dev/null for |
26 | known_hosts it's now possible to let ssh create new keys as it see fit. |
27 | |
28 | === modified file 'debian/changelog' |
29 | --- debian/changelog 2015-07-11 15:44:56 +0000 |
30 | +++ debian/changelog 2015-07-22 17:15:37 +0000 |
31 | @@ -1,3 +1,9 @@ |
32 | +uci-vms (0.1.6) unstable; urgency=medium |
33 | + |
34 | + * Restore python2 support. |
35 | + |
36 | + -- Vincent Ladeuil <vila+qa@canonical.com> Wed, 22 Jul 2015 14:22:27 +0200 |
37 | + |
38 | uci-vms (0.1.5) unstable; urgency=medium |
39 | |
40 | * Fix systemd support (from vivid onwards) by picking an appropriate message |
41 | |
42 | === modified file 'debian/control' |
43 | --- debian/control 2015-07-01 11:43:33 +0000 |
44 | +++ debian/control 2015-07-22 17:15:37 +0000 |
45 | @@ -6,17 +6,30 @@ |
46 | Build-Depends: debhelper (>= 9), |
47 | dh-python, |
48 | openssh-client, |
49 | + python-all, |
50 | + python-setuptools, |
51 | + python-uci-config, |
52 | + python-uci-tests, |
53 | + python-yaml, |
54 | + python3-all, |
55 | + python3-setuptools, |
56 | python3-uci-config, |
57 | python3-uci-tests, |
58 | - python3-all, |
59 | python3-yaml |
60 | Standards-Version: 3.9.4 |
61 | |
62 | +Package: python-uci-vms |
63 | +Architecture: all |
64 | +Depends: openssh-client, |
65 | + python-uci-config, |
66 | + python-yaml, |
67 | + ${misc:Depends} |
68 | +Description: Ubuntu Continuous Integration virtual machine tools. |
69 | + |
70 | Package: python3-uci-vms |
71 | Architecture: all |
72 | Depends: openssh-client, |
73 | python3-uci-config, |
74 | python3-yaml, |
75 | - ${misc:Depends}, |
76 | - ${python3:Depends} |
77 | + ${misc:Depends} |
78 | Description: Ubuntu Continuous Integration virtual machine tools. |
79 | |
80 | === modified file 'debian/copyright' |
81 | --- debian/copyright 2014-04-15 08:26:27 +0000 |
82 | +++ debian/copyright 2015-07-22 17:15:37 +0000 |
83 | @@ -3,7 +3,7 @@ |
84 | Source: http://launchpad.net/uci-vms |
85 | |
86 | Files: * |
87 | -Copyright: 2013-2014 Canonical Ltd. |
88 | +Copyright: 2013-2015 Canonical Ltd. |
89 | License: GPL-3 |
90 | This program is free software: you can redistribute it and/or modify it under |
91 | the terms of the GNU General Public License version 3, as published by the |
92 | @@ -16,3 +16,6 @@ |
93 | . |
94 | You should have received a copy of the GNU General Public License along |
95 | with this program. If not, see <http://www.gnu.org/licenses/>. |
96 | + . |
97 | + The full text of the GPL is distributed as in |
98 | + /usr/share/common-licenses/GPL-3 on Debian systems. |
99 | |
100 | === added file 'debian/python-uci-vms.install' |
101 | --- debian/python-uci-vms.install 1970-01-01 00:00:00 +0000 |
102 | +++ debian/python-uci-vms.install 2015-07-22 17:15:37 +0000 |
103 | @@ -0,0 +1,2 @@ |
104 | +usr/lib/python2* |
105 | +usr/bin/uci-vms2 /usr/bin/ |
106 | |
107 | === added file 'debian/python3-uci-vms.install' |
108 | --- debian/python3-uci-vms.install 1970-01-01 00:00:00 +0000 |
109 | +++ debian/python3-uci-vms.install 2015-07-22 17:15:37 +0000 |
110 | @@ -0,0 +1,2 @@ |
111 | +usr/lib/python3* |
112 | +usr/bin/uci-vms /usr/bin/ |
113 | |
114 | === modified file 'debian/rules' |
115 | --- debian/rules 2015-05-12 15:23:59 +0000 |
116 | +++ debian/rules 2015-07-22 17:15:37 +0000 |
117 | @@ -2,7 +2,8 @@ |
118 | #export DH_VERBOSE=1 |
119 | |
120 | %: |
121 | - dh "$@" --with python3 --buildsystem=pybuild |
122 | + dh "$@" --with python2,python3 --buildsystem=pybuild |
123 | |
124 | override_dh_auto_test: |
125 | + PYTHONPATH=. uci-run-tests2 |
126 | PYTHONPATH=. uci-run-tests |
127 | |
128 | === modified file 'debian/tests/control' |
129 | --- debian/tests/control 2015-05-12 15:23:59 +0000 |
130 | +++ debian/tests/control 2015-07-22 17:15:37 +0000 |
131 | @@ -1,3 +1,7 @@ |
132 | Tests: upstream |
133 | Depends: @, |
134 | python3-uci-tests |
135 | + |
136 | +Tests: upstream2 |
137 | +Depends: @, |
138 | + python-uci-tests |
139 | |
140 | === added file 'debian/tests/upstream2' |
141 | --- debian/tests/upstream2 1970-01-01 00:00:00 +0000 |
142 | +++ debian/tests/upstream2 2015-07-22 17:15:37 +0000 |
143 | @@ -0,0 +1,2 @@ |
144 | +#!/bin/sh -e |
145 | +uci-run-tests2 -m ucivms |
146 | |
147 | === modified file 'setup.py' |
148 | --- setup.py 2015-06-17 09:31:49 +0000 |
149 | +++ setup.py 2015-07-22 17:15:37 +0000 |
150 | @@ -17,12 +17,21 @@ |
151 | # this program. If not, see <http://www.gnu.org/licenses/>. |
152 | |
153 | |
154 | -from distutils import core |
155 | +import setuptools |
156 | +import sys |
157 | + |
158 | |
159 | import ucivms |
160 | |
161 | |
162 | -core.setup( |
163 | +def get_scripts(): |
164 | + if sys.version_info < (3,): |
165 | + return ['uci-vms2'] |
166 | + else: |
167 | + return ['uci-vms'] |
168 | + |
169 | + |
170 | +setuptools.setup( |
171 | name='ucivms', |
172 | version='.'.join(str(c) for c in ucivms.__version__[0:3]), |
173 | description=('Ubuntu Continuous Integration virtual machine tools.'), |
174 | @@ -32,5 +41,5 @@ |
175 | license='GPLv3', |
176 | install_requires=['uciconfig'], |
177 | packages=['ucivms', 'ucivms.tests'], |
178 | - scripts=['uci-vms'], |
179 | + scripts=get_scripts(), |
180 | ) |
181 | |
182 | === added file 'uci-vms2' |
183 | --- uci-vms2 1970-01-01 00:00:00 +0000 |
184 | +++ uci-vms2 2015-07-22 17:15:37 +0000 |
185 | @@ -0,0 +1,24 @@ |
186 | +#!/usr/bin/env python |
187 | +# -*- Mode: python -*- |
188 | +# This file is part of the Ubuntu Continuous Integration virtual machine tools |
189 | +# |
190 | +# Copyright 2015 Canonical Ltd. |
191 | +# |
192 | +# This program is free software: you can redistribute it and/or modify it under |
193 | +# the terms of the GNU General Public License version 3, as published by the |
194 | +# Free Software Foundation. |
195 | +# |
196 | +# This program is distributed in the hope that it will be useful, but WITHOUT |
197 | +# ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
198 | +# SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
199 | +# General Public License for more details. |
200 | +# |
201 | +# You should have received a copy of the GNU General Public License along with |
202 | +# this program. If not, see <http://www.gnu.org/licenses/>. |
203 | + |
204 | +from ucivms import commands |
205 | + |
206 | + |
207 | +if __name__ == '__main__': |
208 | + # All commands call sys.exit() |
209 | + commands.run() |
210 | |
211 | === modified file 'ucivms/__init__.py' |
212 | --- ucivms/__init__.py 2015-07-11 15:44:56 +0000 |
213 | +++ ucivms/__init__.py 2015-07-22 17:15:37 +0000 |
214 | @@ -19,4 +19,4 @@ |
215 | # the release level is 'dev' or 'final'. The |
216 | # version_info value corresponding to the ucivms version 2.0 is (2, 0, 0, |
217 | # 'final', 0). |
218 | -__version__ = (0, 1, 5, 'final', 0) |
219 | +__version__ = (0, 1, 6, 'dev', 0) |
220 | |
221 | === modified file 'ucivms/commands.py' |
222 | --- ucivms/commands.py 2015-07-10 17:03:33 +0000 |
223 | +++ ucivms/commands.py 2015-07-22 17:15:37 +0000 |
224 | @@ -13,7 +13,7 @@ |
225 | # |
226 | # You should have received a copy of the GNU General Public License along with |
227 | # this program. If not, see <http://www.gnu.org/licenses/>. |
228 | - |
229 | +from __future__ import unicode_literals |
230 | import argparse |
231 | import re |
232 | import sys |
233 | @@ -44,8 +44,9 @@ |
234 | """A parser for the uci-vms script.""" |
235 | |
236 | def __init__(self, name, description): |
237 | - super().__init__(prog='uci-vms {}'.format(name), |
238 | - description=description) |
239 | + # FIXME: uci-vms2 if running python2 ? -- vila 2015-07-21 |
240 | + super(ArgParser, self).__init__(prog='uci-vms {}'.format(name), |
241 | + description=description) |
242 | |
243 | def parse_args(self, args=None, out=None, err=None): |
244 | """Parse arguments, overridding stdout/stderr if provided. |
245 | @@ -65,7 +66,7 @@ |
246 | sys.stdout = out |
247 | if err is not None: |
248 | sys.stderr = err |
249 | - return super().parse_args(args) |
250 | + return super(ArgParser, self).parse_args(args) |
251 | finally: |
252 | sys.stdout = out_orig |
253 | sys.stderr = err_orig |
254 | @@ -88,7 +89,7 @@ |
255 | sys.stdout = out |
256 | if err is not None: |
257 | sys.stderr = err |
258 | - return super().parse_known_args(args) |
259 | + return super(ArgParser, self).parse_known_args(args) |
260 | finally: |
261 | sys.stdout = out_orig |
262 | sys.stderr = err_orig |
263 | @@ -98,7 +99,8 @@ |
264 | """A registry specialized for commands.""" |
265 | |
266 | def register(self, cmd): |
267 | - super().register(cmd.name, cmd, help_string=cmd.description) |
268 | + super(CommandRegistry, self).register( |
269 | + cmd.name, cmd, help_string=cmd.description) |
270 | |
271 | |
272 | # All commands are registered here, defining what run() supports |
273 | @@ -139,7 +141,7 @@ |
274 | description = 'Describe uci-vms commands.' |
275 | |
276 | def __init__(self, **kwargs): |
277 | - super().__init__(**kwargs) |
278 | + super(Help, self).__init__(**kwargs) |
279 | self.parser.add_argument( |
280 | 'commands', metavar='COMMAND', nargs='*', |
281 | help='Display help for each command.' |
282 | @@ -177,13 +179,13 @@ |
283 | """ |
284 | |
285 | def __init__(self, **kwargs): |
286 | - super().__init__(**kwargs) |
287 | + super(VmCommand, self).__init__(**kwargs) |
288 | self.parser.add_argument( |
289 | 'vm_name', |
290 | help='Virtual machine section in the configuration file.') |
291 | |
292 | def parse_args(self, args): |
293 | - super().parse_args(args) |
294 | + super(VmCommand, self).parse_args(args) |
295 | self.parse_vm_arg() |
296 | return self.options |
297 | |
298 | @@ -229,7 +231,7 @@ |
299 | # --remove NAME remove the option definition. |
300 | |
301 | def __init__(self, **kwargs): |
302 | - super().__init__(**kwargs) |
303 | + super(Config, self).__init__(**kwargs) |
304 | self.parser.add_argument( |
305 | 'name', nargs='?', help='''The option name.''') |
306 | self.parser.add_argument( |
307 | @@ -337,7 +339,7 @@ |
308 | description = 'Setup a virtual machine.' |
309 | |
310 | def __init__(self, **kwargs): |
311 | - super().__init__(**kwargs) |
312 | + super(Setup, self).__init__(**kwargs) |
313 | self.parser.add_argument( |
314 | '--download', '-d', action="store_true", |
315 | help='Force download of the required image.') |
316 | @@ -412,7 +414,7 @@ |
317 | description = 'Run a command on an existing virtual machine.' |
318 | |
319 | def __init__(self, **kwargs): |
320 | - super().__init__(**kwargs) |
321 | + super(Shell, self).__init__(**kwargs) |
322 | self.parser.add_argument( |
323 | 'command', help='The command to run on the vm.', nargs='?') |
324 | self.parser.add_argument( |
325 | |
326 | === modified file 'ucivms/config.py' |
327 | --- ucivms/config.py 2015-07-10 17:08:05 +0000 |
328 | +++ ucivms/config.py 2015-07-22 17:15:37 +0000 |
329 | @@ -13,6 +13,8 @@ |
330 | # |
331 | # You should have received a copy of the GNU General Public License along with |
332 | # this program. If not, see <http://www.gnu.org/licenses/>. |
333 | +from __future__ import unicode_literals |
334 | +import errno |
335 | import os |
336 | |
337 | from uciconfig import ( |
338 | @@ -31,7 +33,7 @@ |
339 | """ |
340 | |
341 | def __init__(self, store, name): |
342 | - super().__init__(store) |
343 | + super(StartingNameMatcher, self).__init__(store) |
344 | self.name = name |
345 | |
346 | def get_sections(self): |
347 | @@ -107,7 +109,8 @@ |
348 | spath = os.path.join(system_config_dir(), config_file_basename()) |
349 | self.system_store = self.get_shared_store(VmStore(spath)) |
350 | section_getters.append(VmMatcher(self.system_store, name).get_sections) |
351 | - super().__init__(section_getters, user_store, mutable_section_id=name) |
352 | + super(VmStack, self).__init__( |
353 | + section_getters, user_store, mutable_section_id=name) |
354 | |
355 | |
356 | def path_from_unicode(path_string): |
357 | @@ -121,7 +124,7 @@ |
358 | |
359 | This possibly expands the user home directory. |
360 | """ |
361 | - super().__init__( |
362 | + super(PathOption, self).__init__( |
363 | *args, from_unicode=path_from_unicode, **kwargs) |
364 | |
365 | |
366 | @@ -134,10 +137,11 @@ |
367 | def __init__(self, *args, **kwargs): |
368 | # Foce invalid values to be an error (and forbids overriding it) to |
369 | # catch invalid file names |
370 | - super().__init__(*args, invalid='error', **kwargs) |
371 | + super(PackageListOption, self).__init__( |
372 | + *args, invalid='error', **kwargs) |
373 | |
374 | def from_unicode(self, string): |
375 | - values = super().from_unicode(string) |
376 | + values = super(PackageListOption, self).from_unicode(string) |
377 | if not values: |
378 | return values |
379 | converted = [] |
380 | @@ -153,8 +157,12 @@ |
381 | with open(v[1:]) as f: |
382 | for package in f: |
383 | converted.append(package.strip()) |
384 | - except FileNotFoundError: |
385 | - raise ValueError('{} does not exist'.format(v[1:])) |
386 | + except IOError as e: |
387 | + # python2 does not provide FileNotFoundError |
388 | + if e.errno == errno.ENOENT: |
389 | + raise ValueError('{} does not exist'.format(v[1:])) |
390 | + else: |
391 | + raise |
392 | else: |
393 | converted.append(v) |
394 | return converted |
395 | |
396 | === modified file 'ucivms/errors.py' |
397 | --- ucivms/errors.py 2015-06-17 12:45:53 +0000 |
398 | +++ ucivms/errors.py 2015-07-22 17:15:37 +0000 |
399 | @@ -36,7 +36,7 @@ |
400 | class UciVmsError(BaseError): |
401 | |
402 | def __init__(self, fmt, **kwargs): |
403 | - super().__init__(**kwargs) |
404 | + super(UciVmsError, self).__init__(**kwargs) |
405 | self.fmt = fmt |
406 | |
407 | |
408 | @@ -45,7 +45,7 @@ |
409 | fmt = '"{name}" is unknown.' |
410 | |
411 | def __init__(self, name): |
412 | - super().__init__(name=name) |
413 | + super(VmUnknown, self).__init__(name=name) |
414 | |
415 | |
416 | class InvalidVmClass(BaseError): |
417 | @@ -53,7 +53,7 @@ |
418 | fmt = 'vm.class "{value}" is not valid for "{name}".' |
419 | |
420 | def __init__(self, name, value): |
421 | - super().__init__(name=name, value=value) |
422 | + super(InvalidVmClass, self).__init__(name=name, value=value) |
423 | |
424 | |
425 | class VmRunning(BaseError): |
426 | @@ -61,7 +61,7 @@ |
427 | fmt = '"{name}" is running.' |
428 | |
429 | def __init__(self, name): |
430 | - super().__init__(name=name) |
431 | + super(VmRunning, self).__init__(name=name) |
432 | |
433 | |
434 | class VmNotRunning(BaseError): |
435 | @@ -69,7 +69,7 @@ |
436 | fmt = '"{name}" is not running.' |
437 | |
438 | def __init__(self, name): |
439 | - super().__init__(name=name) |
440 | + super(VmNotRunning, self).__init__(name=name) |
441 | |
442 | |
443 | class CommandError(BaseError): |
444 | @@ -82,8 +82,8 @@ |
445 | ''' |
446 | |
447 | def __init__(self, cmd, retcode, out, err): |
448 | - super().__init__(joined_cmd=' '.join(cmd), |
449 | - retcode=retcode, err=err, out=out) |
450 | + super(CommandError, self).__init__(joined_cmd=' '.join(cmd), |
451 | + retcode=retcode, err=err, out=out) |
452 | |
453 | |
454 | class ConfigOptionNotFound(BaseError): |
455 | @@ -91,7 +91,7 @@ |
456 | fmt = 'Option "{name}" does not exist.' |
457 | |
458 | def __init__(self, name): |
459 | - super().__init__(name=name) |
460 | + super(ConfigOptionNotFound, self).__init__(name=name) |
461 | |
462 | |
463 | class ConfigValueError(BaseError): |
464 | @@ -99,7 +99,7 @@ |
465 | fmt = 'Bad value "{value}" for option "{name}".' |
466 | |
467 | def __init__(self, name, value): |
468 | - super().__init__(name=name, value=value) |
469 | + super(ConfigValueError, self).__init__(name=name, value=value) |
470 | |
471 | |
472 | class ConfigPathNotFound(BaseError): |
473 | @@ -107,7 +107,7 @@ |
474 | fmt = 'No such file: {path} from {name}' |
475 | |
476 | def __init__(self, path, name): |
477 | - super().__init__(path=path, name=name) |
478 | + super(ConfigPathNotFound, self).__init__(path=path, name=name) |
479 | |
480 | |
481 | class ConsoleEOFError(BaseError): |
482 | @@ -120,4 +120,4 @@ |
483 | fmt = 'cloud-init reported: {line} check your config' |
484 | |
485 | def __init__(self, line): |
486 | - super().__init__(line=line) |
487 | + super(CloudInitError, self).__init__(line=line) |
488 | |
489 | === modified file 'ucivms/logs.py' |
490 | --- ucivms/logs.py 2015-06-17 12:45:53 +0000 |
491 | +++ ucivms/logs.py 2015-07-22 17:15:37 +0000 |
492 | @@ -81,7 +81,7 @@ |
493 | class InterfaceRegexp(Regexp): |
494 | |
495 | def __init__(self, iface, flags=0): |
496 | - super().__init__(None, flags=flags) |
497 | + super(InterfaceRegexp, self).__init__(None, flags=flags) |
498 | self.iface = iface |
499 | |
500 | def ensure_re(self): |
501 | |
502 | === modified file 'ucivms/monitors.py' |
503 | --- ucivms/monitors.py 2015-07-10 09:59:07 +0000 |
504 | +++ ucivms/monitors.py 2015-07-22 17:15:37 +0000 |
505 | @@ -26,7 +26,7 @@ |
506 | """Monitor a console to identify known events.""" |
507 | |
508 | def __init__(self, stream): |
509 | - super().__init__() |
510 | + super(ConsoleMonitor, self).__init__() |
511 | self.stream = stream |
512 | |
513 | def scan(self): |
514 | @@ -81,7 +81,7 @@ |
515 | if offset is not None: |
516 | cmd += ['--bytes', '+{}'.format(offset)] |
517 | proc = subprocesses.pipe(cmd) |
518 | - super().__init__(proc.stdout) |
519 | + super(TailMonitor, self).__init__(proc.stdout) |
520 | self.path = path |
521 | self.cmd = cmd |
522 | self.proc = proc |
523 | @@ -89,7 +89,7 @@ |
524 | |
525 | def scan(self): |
526 | try: |
527 | - for line in super().scan(): |
528 | + for line in super(TailMonitor, self).scan(): |
529 | # FIXME: Arguably we should decode line from an utf8 encoding |
530 | # as subprocesses.pipe() merges stderr into stdout and utf8 |
531 | # error messages have been observed in real life: 'tail: cannot |
532 | |
533 | === modified file 'ucivms/subprocesses.py' |
534 | --- ucivms/subprocesses.py 2015-06-18 14:07:34 +0000 |
535 | +++ ucivms/subprocesses.py 2015-07-22 17:15:37 +0000 |
536 | @@ -34,8 +34,8 @@ |
537 | stdout=subprocess.PIPE, |
538 | stderr=subprocess.PIPE) |
539 | out, err = proc.communicate() |
540 | - out = out.decode() |
541 | - err = err.decode() |
542 | + out = out.decode('utf8') |
543 | + err = err.decode('utf8') |
544 | if proc.returncode: |
545 | raise errors.CommandError(args, proc.returncode, out, err) |
546 | return proc.returncode, out, err |
547 | |
548 | === modified file 'ucivms/tests/features.py' |
549 | --- ucivms/tests/features.py 2015-06-18 11:34:09 +0000 |
550 | +++ ucivms/tests/features.py 2015-07-22 17:15:37 +0000 |
551 | @@ -57,11 +57,11 @@ |
552 | class _SshFeature(features.ExecutableFeature): |
553 | |
554 | def __init__(self): |
555 | - super().__init__('ssh') |
556 | + super(_SshFeature, self).__init__('ssh') |
557 | self.version = None |
558 | |
559 | def _probe(self): |
560 | - exists = super()._probe() |
561 | + exists = super(_SshFeature, self)._probe() |
562 | if exists: |
563 | try: |
564 | proc = subprocess.Popen(['ssh', '-V'], |
565 | |
566 | === modified file 'ucivms/tests/test_commands.py' |
567 | --- ucivms/tests/test_commands.py 2015-07-10 16:57:26 +0000 |
568 | +++ ucivms/tests/test_commands.py 2015-07-22 17:15:37 +0000 |
569 | @@ -13,6 +13,7 @@ |
570 | # |
571 | # You should have received a copy of the GNU General Public License along with |
572 | # this program. If not, see <http://www.gnu.org/licenses/>. |
573 | +from __future__ import unicode_literals |
574 | import io |
575 | import os |
576 | import unittest |
577 | @@ -39,7 +40,7 @@ |
578 | class TestHelpOptions(unittest.TestCase): |
579 | |
580 | def setUp(self): |
581 | - super().setUp() |
582 | + super(TestHelpOptions, self).setUp() |
583 | self.out = io.StringIO() |
584 | self.err = io.StringIO() |
585 | |
586 | @@ -63,7 +64,7 @@ |
587 | class TestHelp(unittest.TestCase): |
588 | |
589 | def setUp(self): |
590 | - super().setUp() |
591 | + super(TestHelp, self).setUp() |
592 | self.out = io.StringIO() |
593 | self.err = io.StringIO() |
594 | |
595 | @@ -109,7 +110,7 @@ |
596 | """A fake VM for tests that doesn't trigger dangerous or costly calls.""" |
597 | |
598 | def __init__(self, conf, vm_states=None): |
599 | - super().__init__(conf) |
600 | + super(FakeVM, self).__init__(conf) |
601 | self.states = vm_states |
602 | self.install_called = False |
603 | self.start_called = False |
604 | @@ -164,7 +165,7 @@ |
605 | class TestVmCommandOptions(unittest.TestCase): |
606 | |
607 | def setUp(self): |
608 | - super().setUp() |
609 | + super(TestVmCommandOptions, self).setUp() |
610 | setup_fake_vm(self) |
611 | self.out = io.StringIO() |
612 | self.err = io.StringIO() |
613 | @@ -179,13 +180,13 @@ |
614 | |
615 | def test_defaults(self): |
616 | ns = self.parse_args(['foo']) |
617 | - self.assertEquals('foo', ns.vm_name) |
618 | + self.assertEqual('foo', ns.vm_name) |
619 | |
620 | |
621 | class TestVmCommand(unittest.TestCase): |
622 | |
623 | def setUp(self): |
624 | - super().setUp() |
625 | + super(TestVmCommand, self).setUp() |
626 | setup_fake_vm(self) |
627 | |
628 | def run_cmd(self, args): |
629 | @@ -207,7 +208,7 @@ |
630 | class TestConfigOptions(unittest.TestCase): |
631 | |
632 | def setUp(self): |
633 | - super().setUp() |
634 | + super(TestConfigOptions, self).setUp() |
635 | setup_fake_vm(self) |
636 | self.out = io.StringIO() |
637 | self.err = io.StringIO() |
638 | @@ -222,7 +223,7 @@ |
639 | |
640 | def test_defaults(self): |
641 | ns = self.parse_args(['foo']) |
642 | - self.assertEquals('foo', ns.vm_name) |
643 | + self.assertEqual('foo', ns.vm_name) |
644 | self.assertIs(None, ns.name) |
645 | self.assertFalse(ns.all) |
646 | self.assertFalse(ns.remove) |
647 | @@ -248,25 +249,25 @@ |
648 | with self.assertRaises(errors.UciVmsError) as cm: |
649 | self.parse_args(['foo', '--remove']) |
650 | self.assertEqual('--remove expects an option to remove.', |
651 | - str(cm.exception)) |
652 | + '{}'.format(cm.exception)) |
653 | |
654 | def test_remove_all_fails(self): |
655 | with self.assertRaises(errors.UciVmsError) as cm: |
656 | self.parse_args(['foo', '--remove', '--all']) |
657 | self.assertEqual('--remove and --all are mutually exclusive.', |
658 | - str(cm.exception)) |
659 | + '{}'.format(cm.exception)) |
660 | |
661 | def test_set_only_one_option(self): |
662 | with self.assertRaises(errors.UciVmsError) as cm: |
663 | self.parse_args(['foo', 'bar=baz', '--all']) |
664 | self.assertEqual('Only one option can be set.', |
665 | - str(cm.exception)) |
666 | + '{}'.format(cm.exception)) |
667 | |
668 | |
669 | class TestConfig(unittest.TestCase): |
670 | |
671 | def setUp(self): |
672 | - super().setUp() |
673 | + super(TestConfig, self).setUp() |
674 | setup_fake_vm(self) |
675 | self.out = io.StringIO() |
676 | self.err = io.StringIO() |
677 | @@ -386,7 +387,7 @@ |
678 | class TestSetupOptions(unittest.TestCase): |
679 | |
680 | def setUp(self): |
681 | - super().setUp() |
682 | + super(TestSetupOptions, self).setUp() |
683 | setup_fake_vm(self) |
684 | self.out = io.StringIO() |
685 | self.err = io.StringIO() |
686 | @@ -402,19 +403,19 @@ |
687 | |
688 | def test_defaults(self): |
689 | ns = self.parse_args(['foo']) |
690 | - self.assertEquals('foo', ns.vm_name) |
691 | + self.assertEqual('foo', ns.vm_name) |
692 | self.assertFalse(ns.download) |
693 | self.assertFalse(ns.ssh_keygen) |
694 | |
695 | def test_download(self): |
696 | ns = self.parse_args(['foo', '--download']) |
697 | - self.assertEquals('foo', ns.vm_name) |
698 | + self.assertEqual('foo', ns.vm_name) |
699 | self.assertTrue(ns.download) |
700 | self.assertFalse(ns.ssh_keygen) |
701 | |
702 | def test_ssh_keygen(self): |
703 | ns = self.parse_args(['foo', '--ssh-keygen']) |
704 | - self.assertEquals('foo', ns.vm_name) |
705 | + self.assertEqual('foo', ns.vm_name) |
706 | self.assertFalse(ns.download) |
707 | self.assertTrue(ns.ssh_keygen) |
708 | |
709 | @@ -422,7 +423,7 @@ |
710 | class TestSetup(unittest.TestCase): |
711 | |
712 | def setUp(self): |
713 | - super().setUp() |
714 | + super(TestSetup, self).setUp() |
715 | setup_fake_vm(self) |
716 | |
717 | def run_setup(self, args): |
718 | @@ -450,7 +451,7 @@ |
719 | class TestStatus(unittest.TestCase): |
720 | |
721 | def setUp(self): |
722 | - super().setUp() |
723 | + super(TestStatus, self).setUp() |
724 | setup_fake_vm(self) |
725 | self.out = io.StringIO() |
726 | self.err = io.StringIO() |
727 | @@ -480,7 +481,7 @@ |
728 | class TestStart(unittest.TestCase): |
729 | |
730 | def setUp(self): |
731 | - super().setUp() |
732 | + super(TestStart, self).setUp() |
733 | setup_fake_vm(self) |
734 | |
735 | def run_start(self, args): |
736 | @@ -510,7 +511,7 @@ |
737 | class TestShellOptions(unittest.TestCase): |
738 | |
739 | def setUp(self): |
740 | - super().setUp() |
741 | + super(TestShellOptions, self).setUp() |
742 | setup_fake_vm(self) |
743 | self.out = io.StringIO() |
744 | self.err = io.StringIO() |
745 | @@ -522,19 +523,19 @@ |
746 | |
747 | def test_defaults(self): |
748 | ns = self.parse_args(['foo']) |
749 | - self.assertEquals('foo', ns.vm_name) |
750 | + self.assertEqual('foo', ns.vm_name) |
751 | self.assertIsNone(ns.command) |
752 | self.assertEqual([], ns.args) |
753 | |
754 | def test_command_without_arguments(self): |
755 | ns = self.parse_args(['foo', 'doit']) |
756 | - self.assertEquals('foo', ns.vm_name) |
757 | + self.assertEqual('foo', ns.vm_name) |
758 | self.assertEqual('doit', ns.command) |
759 | self.assertEqual([], ns.args) |
760 | |
761 | def test_command_with_arguments(self): |
762 | ns = self.parse_args(['foo', 'doit', '-a', 'b', 'c']) |
763 | - self.assertEquals('foo', ns.vm_name) |
764 | + self.assertEqual('foo', ns.vm_name) |
765 | self.assertEqual('doit', ns.command) |
766 | self.assertEqual(['-a', 'b', 'c'], ns.args) |
767 | |
768 | @@ -542,7 +543,7 @@ |
769 | class TestShell(unittest.TestCase): |
770 | |
771 | def setUp(self): |
772 | - super().setUp() |
773 | + super(TestShell, self).setUp() |
774 | setup_fake_vm(self) |
775 | |
776 | def run_shell(self, args): |
777 | @@ -583,7 +584,7 @@ |
778 | class TestStop(unittest.TestCase): |
779 | |
780 | def setUp(self): |
781 | - super().setUp() |
782 | + super(TestStop, self).setUp() |
783 | setup_fake_vm(self) |
784 | |
785 | def run_stop(self): |
786 | @@ -616,7 +617,7 @@ |
787 | class TestTeardown(unittest.TestCase): |
788 | |
789 | def setUp(self): |
790 | - super().setUp() |
791 | + super(TestTeardown, self).setUp() |
792 | setup_fake_vm(self) |
793 | |
794 | def run_teardown(self, args): |
795 | |
796 | === modified file 'ucivms/tests/test_config.py' |
797 | --- ucivms/tests/test_config.py 2015-06-26 09:16:14 +0000 |
798 | +++ ucivms/tests/test_config.py 2015-07-22 17:15:37 +0000 |
799 | @@ -13,6 +13,7 @@ |
800 | # |
801 | # You should have received a copy of the GNU General Public License along with |
802 | # this program. If not, see <http://www.gnu.org/licenses/>. |
803 | +from __future__ import unicode_literals |
804 | import os |
805 | import unittest |
806 | |
807 | @@ -28,7 +29,7 @@ |
808 | class TestVmMatcher(unittest.TestCase): |
809 | |
810 | def setUp(self): |
811 | - super().setUp() |
812 | + super(TestVmMatcher, self).setUp() |
813 | fixtures.isolate_from_disk(self) |
814 | self.store = config.VmStore('foo.conf') |
815 | self.matcher = config.VmMatcher(self.store, 'test') |
816 | @@ -55,7 +56,7 @@ |
817 | class TestVmStackOrdering(unittest.TestCase): |
818 | |
819 | def setUp(self): |
820 | - super().setUp() |
821 | + super(TestVmStackOrdering, self).setUp() |
822 | fixtures.isolate_from_disk(self) |
823 | self.conf = config.VmStack('foo') |
824 | |
825 | @@ -82,7 +83,7 @@ |
826 | """Test config option values.""" |
827 | |
828 | def setUp(self): |
829 | - super().setUp() |
830 | + super(TestVmStack, self).setUp() |
831 | fixtures.isolate_from_disk(self) |
832 | self.conf = config.VmStack('foo') |
833 | self.conf.store._load_from_string(''' |
834 | @@ -132,12 +133,12 @@ |
835 | class TestPathOption(unittest.TestCase): |
836 | |
837 | def setUp(self): |
838 | - super().setUp() |
839 | + super(TestPathOption, self).setUp() |
840 | fixtures.isolate_from_disk(self) |
841 | |
842 | def assertConverted(self, expected, value): |
843 | option = config.PathOption('foo', help_string='A path.') |
844 | - self.assertEquals(expected, option.convert_from_unicode(None, value)) |
845 | + self.assertEqual(expected, option.convert_from_unicode(None, value)) |
846 | |
847 | def test_absolute_path(self): |
848 | self.assertConverted('/test/path', '/test/path') |
849 | @@ -153,12 +154,12 @@ |
850 | class TestPackageListOption(unittest.TestCase): |
851 | |
852 | def setUp(self): |
853 | - super().setUp() |
854 | + super(TestPackageListOption, self).setUp() |
855 | fixtures.isolate_from_disk(self) |
856 | |
857 | def assertConverted(self, expected, value): |
858 | option = config.PackageListOption('foo', help_string='A package list.') |
859 | - self.assertEquals(expected, option.convert_from_unicode(None, value)) |
860 | + self.assertEqual(expected, option.convert_from_unicode(None, value)) |
861 | |
862 | def test_empty(self): |
863 | self.assertConverted(None, None) |
864 | @@ -180,7 +181,7 @@ |
865 | class TestVmClass(unittest.TestCase): |
866 | |
867 | def setUp(self): |
868 | - super().setUp() |
869 | + super(TestVmClass, self).setUp() |
870 | fixtures.isolate_from_disk(self) |
871 | |
872 | def test_class_mandatory(self): |
873 | @@ -213,7 +214,7 @@ |
874 | class TestStartingNameMatcher(unittest.TestCase): |
875 | |
876 | def setUp(self): |
877 | - super().setUp() |
878 | + super(TestStartingNameMatcher, self).setUp() |
879 | fixtures.isolate_from_disk(self) |
880 | # Any simple store is good enough |
881 | self.store = config.VmStore('foo.conf') |
882 | @@ -278,7 +279,7 @@ |
883 | class TestVmName(unittest.TestCase): |
884 | |
885 | def setUp(self): |
886 | - super().setUp() |
887 | + super(TestVmName, self).setUp() |
888 | fixtures.isolate_from_disk(self) |
889 | self.config_dir = os.path.join(self.uniq_dir, 'config') |
890 | |
891 | |
892 | === modified file 'ucivms/tests/test_logs.py' |
893 | --- ucivms/tests/test_logs.py 2015-06-17 12:45:53 +0000 |
894 | +++ ucivms/tests/test_logs.py 2015-07-22 17:15:37 +0000 |
895 | @@ -23,7 +23,7 @@ |
896 | class TestIpAddrRegexp(unittest.TestCase): |
897 | |
898 | def setUp(self): |
899 | - super().setUp() |
900 | + super(TestIpAddrRegexp, self).setUp() |
901 | self.re = logs.ip_address_re |
902 | |
903 | def assertMatches(self, ip_addr): |
904 | @@ -49,7 +49,7 @@ |
905 | class TestMacAddrRegexp(unittest.TestCase): |
906 | |
907 | def setUp(self): |
908 | - super().setUp() |
909 | + super(TestMacAddrRegexp, self).setUp() |
910 | self.re = logs.mac_address_re |
911 | |
912 | def assertMatches(self, mac_addr): |
913 | @@ -82,7 +82,7 @@ |
914 | class TestIfaceRegexp(unittest.TestCase): |
915 | |
916 | def setUp(self): |
917 | - super().setUp() |
918 | + super(TestIfaceRegexp, self).setUp() |
919 | self.re = logs.InterfaceRegexp('eth0') |
920 | |
921 | def assertMatches(self, expected, line): |
922 | |
923 | === modified file 'ucivms/tests/test_monitors.py' |
924 | --- ucivms/tests/test_monitors.py 2015-06-17 12:45:53 +0000 |
925 | +++ ucivms/tests/test_monitors.py 2015-07-22 17:15:37 +0000 |
926 | @@ -66,14 +66,13 @@ |
927 | [ 33.204755] Power down. |
928 | ''') |
929 | # We stop as soon as we get the final message and ignore the rest |
930 | - self.assertEquals(' * Will now halt\n', |
931 | - lines[-1]) |
932 | + self.assertEqual(' * Will now halt\n', lines[-1]) |
933 | |
934 | |
935 | class TestConsoleParsingWithFile(unittest.TestCase): |
936 | |
937 | def setUp(self): |
938 | - super().setUp() |
939 | + super(TestConsoleParsingWithFile, self).setUp() |
940 | vms_fixtures.isolate_from_disk(self) |
941 | |
942 | def _scan_file_monitor(self, content): |
943 | @@ -118,7 +117,7 @@ |
944 | class TestActualFileSize(unittest.TestCase): |
945 | |
946 | def setUp(self): |
947 | - super().setUp() |
948 | + super(TestActualFileSize, self).setUp() |
949 | fixtures.set_uniq_cwd(self) |
950 | |
951 | def assertSize(self, expected, path): |
952 | |
953 | === modified file 'ucivms/tests/test_ssh.py' |
954 | --- ucivms/tests/test_ssh.py 2015-06-18 14:07:34 +0000 |
955 | +++ ucivms/tests/test_ssh.py 2015-07-22 17:15:37 +0000 |
956 | @@ -68,7 +68,7 @@ |
957 | upper_type='EC'))] |
958 | |
959 | def setUp(self): |
960 | - super().setUp() |
961 | + super(TestKeyGen, self).setUp() |
962 | vms_fixtures.isolate_from_disk(self) |
963 | |
964 | def keygen(self, ssh_type, upper_type): |
965 | @@ -77,8 +77,10 @@ |
966 | self.assertTrue(os.path.exists(private_path)) |
967 | public_path = private_path + '.pub' |
968 | self.assertTrue(os.path.exists(public_path)) |
969 | - public = open(public_path).read() |
970 | - private = open(private_path).read() |
971 | + with open(public_path) as f: |
972 | + public = f.read() |
973 | + with open(private_path) as f: |
974 | + private = f.read() |
975 | self.assertTrue( |
976 | private.startswith('-----BEGIN %s PRIVATE KEY-----\n' |
977 | % (upper_type,))) |
978 | @@ -92,11 +94,11 @@ |
979 | self.assertTrue(public.startswith(self.prefix)) |
980 | |
981 | |
982 | -@features.requires(vms_features.ssh_feature) |
983 | +@features.requires(vms_features.use_sudo_for_tests_feature) |
984 | class TestSsh(unittest.TestCase): |
985 | |
986 | def setUp(self): |
987 | - super().setUp() |
988 | + super(TestSsh, self).setUp() |
989 | vms_features.requires_existing_vm(self, 'uci-vms-tests-trusty') |
990 | vms_fixtures.isolate_from_disk(self) |
991 | # To isolate tests from each other, created vms needs a unique name. To |
992 | |
993 | === modified file 'ucivms/tests/test_subprocesses.py' |
994 | --- ucivms/tests/test_subprocesses.py 2015-06-18 08:16:55 +0000 |
995 | +++ ucivms/tests/test_subprocesses.py 2015-07-22 17:15:37 +0000 |
996 | @@ -15,6 +15,7 @@ |
997 | # this program. If not, see <http://www.gnu.org/licenses/>. |
998 | |
999 | import errno |
1000 | +import sys |
1001 | import unittest |
1002 | |
1003 | from ucitests import fixtures |
1004 | @@ -27,7 +28,7 @@ |
1005 | class TestRun(unittest.TestCase): |
1006 | |
1007 | def setUp(self): |
1008 | - super().setUp() |
1009 | + super(TestRun, self).setUp() |
1010 | fixtures.set_uniq_cwd(self) |
1011 | |
1012 | def test_success(self): |
1013 | @@ -46,17 +47,22 @@ |
1014 | cm.exception.err) |
1015 | |
1016 | def test_error(self): |
1017 | - with self.assertRaises(FileNotFoundError) as cm: |
1018 | + # python doesn't have FileNotFoundError |
1019 | + with self.assertRaises(OSError) as cm: |
1020 | subprocesses.run(['I-dont-exist']) |
1021 | self.assertEqual(errno.ENOENT, cm.exception.errno) |
1022 | - self.assertEqual("No such file or directory: 'I-dont-exist'", |
1023 | - cm.exception.strerror) |
1024 | + if sys.version_info[0] < 3: |
1025 | + self.assertEqual("No such file or directory", |
1026 | + cm.exception.strerror) |
1027 | + else: |
1028 | + self.assertEqual("No such file or directory: 'I-dont-exist'", |
1029 | + cm.exception.strerror) |
1030 | |
1031 | |
1032 | class TestPipe(unittest.TestCase): |
1033 | |
1034 | def setUp(self): |
1035 | - super().setUp() |
1036 | + super(TestPipe, self).setUp() |
1037 | fixtures.set_uniq_cwd(self) |
1038 | |
1039 | def test_success(self): |
1040 | @@ -72,11 +78,16 @@ |
1041 | self.assertIs(None, proc.stderr) |
1042 | |
1043 | def test_error(self): |
1044 | - with self.assertRaises(FileNotFoundError) as cm: |
1045 | + # python doesn't have FileNotFoundError |
1046 | + with self.assertRaises(OSError) as cm: |
1047 | subprocesses.pipe(['I-dont-exist']) |
1048 | self.assertEqual(errno.ENOENT, cm.exception.errno) |
1049 | - self.assertEqual("No such file or directory: 'I-dont-exist'", |
1050 | - cm.exception.strerror) |
1051 | + if sys.version_info[0] < 3: |
1052 | + self.assertEqual("No such file or directory", |
1053 | + cm.exception.strerror) |
1054 | + else: |
1055 | + self.assertEqual("No such file or directory: 'I-dont-exist'", |
1056 | + cm.exception.strerror) |
1057 | |
1058 | |
1059 | # MISSINGTESTS: |
1060 | |
1061 | === modified file 'ucivms/tests/test_timeouts.py' |
1062 | --- ucivms/tests/test_timeouts.py 2015-06-26 09:16:14 +0000 |
1063 | +++ ucivms/tests/test_timeouts.py 2015-07-22 17:15:37 +0000 |
1064 | @@ -25,14 +25,24 @@ |
1065 | |
1066 | def test_no_timeouts(self): |
1067 | timo = timeouts.ExponentialBackoff(1, 2, 0) |
1068 | - assertions.assertLength(self, 0, list(iter(timo))) |
1069 | + assertions.assertLength(self, 0, list(timo)) |
1070 | + |
1071 | + def test_single_retry(self): |
1072 | + eb = timeouts.ExponentialBackoff(0, 2, 1) |
1073 | + timo = list(eb) |
1074 | + assertions.assertLength(self, 2, timo) |
1075 | + |
1076 | + def test_two_retries(self): |
1077 | + eb = timeouts.ExponentialBackoff(0, 2, 2) |
1078 | + timo = list(eb) |
1079 | + assertions.assertLength(self, 3, timo) |
1080 | |
1081 | def test_up_to_5mins(self): |
1082 | - timo = timeouts.ExponentialBackoff(0, 300, 10) |
1083 | - values = list(iter(timo)) |
1084 | - # There is as many timeouts than retries |
1085 | - assertions.assertLength(self, 10, values) |
1086 | + timo = timeouts.ExponentialBackoff(12, 300, 10) |
1087 | + values = list(timo) |
1088 | + # There is or more timeouts than retries |
1089 | + assertions.assertLength(self, 11, values) |
1090 | # The first duration is explicit |
1091 | - self.assertEqual(0, values[0]) |
1092 | + self.assertEqual(12, values[0]) |
1093 | # The sum of wait times is equal to up_to |
1094 | self.assertEqual(300, sum(values)) |
1095 | |
1096 | === modified file 'ucivms/tests/test_vms.py' |
1097 | --- ucivms/tests/test_vms.py 2015-07-03 10:09:27 +0000 |
1098 | +++ ucivms/tests/test_vms.py 2015-07-22 17:15:37 +0000 |
1099 | @@ -13,8 +13,10 @@ |
1100 | # |
1101 | # You should have received a copy of the GNU General Public License along with |
1102 | # this program. If not, see <http://www.gnu.org/licenses/>. |
1103 | +from __future__ import unicode_literals |
1104 | import io |
1105 | import os |
1106 | +import sys |
1107 | import unittest |
1108 | import yaml |
1109 | |
1110 | @@ -80,7 +82,7 @@ |
1111 | def setUp(self): |
1112 | # Downloading real isos or images is too long for tests, instead, we |
1113 | # fake it by downloading a small but known to exist file: MD5SUMS |
1114 | - super().setUp() |
1115 | + super(TestDownload, self).setUp() |
1116 | vms_fixtures.isolate_from_disk(self) |
1117 | download_cache = os.path.join(self.uniq_dir, 'downloads') |
1118 | os.mkdir(download_cache) |
1119 | @@ -137,7 +139,7 @@ |
1120 | class TestMetaData(unittest.TestCase): |
1121 | |
1122 | def setUp(self): |
1123 | - super().setUp() |
1124 | + super(TestMetaData, self).setUp() |
1125 | vms_fixtures.isolate_from_disk(self) |
1126 | self.conf = config.VmStack('foo') |
1127 | self.vm = vms.Kvm(self.conf) |
1128 | @@ -210,7 +212,7 @@ |
1129 | class TestLaunchpadAccess(unittest.TestCase): |
1130 | |
1131 | def setUp(self): |
1132 | - super().setUp() |
1133 | + super(TestLaunchpadAccess, self).setUp() |
1134 | vms_fixtures.isolate_from_disk(self) |
1135 | self.conf = config.VmStack('foo') |
1136 | self.vm = vms.Kvm(self.conf) |
1137 | @@ -252,7 +254,7 @@ |
1138 | class TestCIUserData(unittest.TestCase): |
1139 | |
1140 | def setUp(self): |
1141 | - super().setUp() |
1142 | + super(TestCIUserData, self).setUp() |
1143 | vms_fixtures.isolate_from_disk(self) |
1144 | self.conf = config.VmStack('foo') |
1145 | self.ci_data = vms.CIUserData(self.conf) |
1146 | @@ -275,12 +277,12 @@ |
1147 | def test_password(self): |
1148 | self.conf.store._load_from_string('vm.password = tagada') |
1149 | self.ci_data.populate() |
1150 | - self.assertEquals('tagada', self.ci_data.cloud_config['password']) |
1151 | + self.assertEqual('tagada', self.ci_data.cloud_config['password']) |
1152 | |
1153 | def test_apt_proxy(self): |
1154 | self.conf.store._load_from_string('vm.apt_proxy = tagada') |
1155 | self.ci_data.populate() |
1156 | - self.assertEquals('tagada', self.ci_data.cloud_config['apt_proxy']) |
1157 | + self.assertEqual('tagada', self.ci_data.cloud_config['apt_proxy']) |
1158 | |
1159 | def test_final_message_precise(self): |
1160 | self.conf.store._load_from_string('vm.release = precise') |
1161 | @@ -347,7 +349,10 @@ |
1162 | if content is None: |
1163 | content = '{}\ncontent\n'.format(path) |
1164 | with open(path, 'wb') as f: |
1165 | - f.write(bytes(content, 'utf8')) |
1166 | + if sys.version_info[0] < 3: |
1167 | + f.write(content) |
1168 | + else: |
1169 | + f.write(bytes(content, 'utf8')) |
1170 | |
1171 | def test_good_ssh_keys(self): |
1172 | paths = ('rsa', 'rsa.pub', 'dsa', 'dsa.pub', 'ecdsa', 'ecdsa.pub') |
1173 | @@ -492,7 +497,7 @@ |
1174 | class TestCreateUserData(unittest.TestCase): |
1175 | |
1176 | def setUp(self): |
1177 | - super().setUp() |
1178 | + super(TestCreateUserData, self).setUp() |
1179 | vms_fixtures.isolate_from_disk(self) |
1180 | self.conf = config.VmStack('foo') |
1181 | self.vm = vms.Kvm(self.conf) |
1182 | @@ -516,7 +521,7 @@ |
1183 | class TestSeedData(unittest.TestCase): |
1184 | |
1185 | def setUp(self): |
1186 | - super().setUp() |
1187 | + super(TestSeedData, self).setUp() |
1188 | vms_fixtures.isolate_from_disk(self) |
1189 | self.conf = config.VmStack('foo') |
1190 | self.vm = vms.VM(self.conf) |
1191 | @@ -544,7 +549,7 @@ |
1192 | class TestSeedImage(unittest.TestCase): |
1193 | |
1194 | def setUp(self): |
1195 | - super().setUp() |
1196 | + super(TestSeedImage, self).setUp() |
1197 | vms_fixtures.isolate_from_disk(self) |
1198 | self.conf = config.VmStack('foo') |
1199 | self.vm = vms.Kvm(self.conf) |
1200 | @@ -570,7 +575,7 @@ |
1201 | class TestImageFromCloud(unittest.TestCase): |
1202 | |
1203 | def setUp(self): |
1204 | - super().setUp() |
1205 | + super(TestImageFromCloud, self).setUp() |
1206 | vms_fixtures.isolate_from_disk(self) |
1207 | self.conf = config.VmStack('foo') |
1208 | self.vm = vms.Kvm(self.conf) |
1209 | @@ -607,7 +612,7 @@ |
1210 | (download_cache_dir, |
1211 | reference_cloud_image_name, |
1212 | images_dir) = requires_known_reference_image(self) |
1213 | - super().setUp() |
1214 | + super(TestImageWithBacking, self).setUp() |
1215 | vms_fixtures.isolate_from_disk(self) |
1216 | # Create a shared config |
1217 | conf = config.VmStack(None) |
1218 | @@ -702,7 +707,7 @@ |
1219 | (download_cache, |
1220 | reference_cloud_image_name, |
1221 | images_dir) = requires_known_reference_image(self) |
1222 | - super().setUp() |
1223 | + super(TestInstallWithSeed, self).setUp() |
1224 | vms_fixtures.isolate_from_disk(self) |
1225 | # We need to allow other users to read this dir |
1226 | os.chmod(self.uniq_dir, 0o755) |
1227 | @@ -746,7 +751,7 @@ |
1228 | (download_cache_dir, |
1229 | reference_cloud_image_name, |
1230 | images_dir) = requires_known_reference_image(self) |
1231 | - super().setUp() |
1232 | + super(TestInstallWithBacking, self).setUp() |
1233 | vms_fixtures.isolate_from_disk(self) |
1234 | # We need to allow other users to read this dir |
1235 | os.chmod(self.uniq_dir, 0o755) |
1236 | @@ -798,7 +803,7 @@ |
1237 | class TestKeyGen(unittest.TestCase): |
1238 | |
1239 | def setUp(self): |
1240 | - super().setUp() |
1241 | + super(TestKeyGen, self).setUp() |
1242 | vms_fixtures.isolate_from_disk(self) |
1243 | self.conf = config.VmStack(None) |
1244 | self.vm = vms.VM(self.conf) |
1245 | @@ -862,7 +867,7 @@ |
1246 | class TestSSH(unittest.TestCase): |
1247 | |
1248 | def setUp(self): |
1249 | - super().setUp() |
1250 | + super(TestSSH, self).setUp() |
1251 | vms_fixtures.isolate_from_disk(self) |
1252 | self.conf = config.VmStack(None) |
1253 | self.vm = vms.VM(self.conf) |
1254 | @@ -895,7 +900,7 @@ |
1255 | class TestEmptyConsole(unittest.TestCase): |
1256 | |
1257 | def setUp(self): |
1258 | - super().setUp() |
1259 | + super(TestEmptyConsole, self).setUp() |
1260 | vms_fixtures.isolate_from_disk(self) |
1261 | # To isolate tests from each other, created vms needs a unique name. To |
1262 | # keep those names legal and still user-readable we use the class name |
1263 | @@ -953,7 +958,7 @@ |
1264 | class TestEphemeralLXC(unittest.TestCase): |
1265 | |
1266 | def setUp(self): |
1267 | - super().setUp() |
1268 | + super(TestEphemeralLXC, self).setUp() |
1269 | vms_features.requires_existing_vm(self, 'uci-vms-tests-trusty') |
1270 | vms_fixtures.isolate_from_disk(self) |
1271 | # To isolate tests from each other, created vms needs a unique name. To |
1272 | |
1273 | === modified file 'ucivms/timeouts.py' |
1274 | --- ucivms/timeouts.py 2015-06-26 09:16:14 +0000 |
1275 | +++ ucivms/timeouts.py 2015-07-22 17:15:37 +0000 |
1276 | @@ -27,10 +27,11 @@ |
1277 | until it succeeds up to a specified limit. The returned values are the |
1278 | succesive wait times and their total equals ``up_to``. |
1279 | |
1280 | - :note: ``retries`` + 1 values are returned, the last values may end up |
1281 | - being repeated and equal to zero. I.e. the caller decides how many |
1282 | - retries will be attempted and ``up_to`` is the upper limit for |
1283 | - total. This mimics manual retries by a user re-trying randomly but |
1284 | + :note: To simplify the use, one more value is returned that callers will |
1285 | + ignore (if the last retry fails, there is little point to wait. So the |
1286 | + last value will always be zero so that callers can still call |
1287 | + time.sleep(0.0)). The total of the returned times will be |
1288 | + ``up_to``. This mimics manual retries by a user re-trying randomly but |
1289 | giving up after a limit. |
1290 | """ |
1291 | |
1292 | @@ -41,16 +42,23 @@ |
1293 | |
1294 | def __iter__(self): |
1295 | attempts = 1 |
1296 | - backoff = self.first |
1297 | - cumulated = backoff |
1298 | + cumulated = backoff = self.first |
1299 | + if self.retries: |
1300 | + # First wait is specified by the user |
1301 | + yield self.first |
1302 | # Yield the time to wait between retries |
1303 | - while attempts < self.retries: |
1304 | + while attempts + 1 < self.retries: |
1305 | if cumulated + backoff > self.up_to: |
1306 | backoff = 0 |
1307 | else: |
1308 | cumulated += backoff |
1309 | yield backoff |
1310 | - backoff = (2 ** attempts) * random.random() |
1311 | + backoff = self.first + (2 ** attempts) * random.random() |
1312 | attempts += 1 |
1313 | - if self.retries: |
1314 | + if self.retries > 1: |
1315 | + # We need at least two retry to reach ``up_to`` since ``first`` is |
1316 | + # specified by the user |
1317 | yield (self.up_to - cumulated) |
1318 | + if self.retries: |
1319 | + # Waiting after the last failure is useless |
1320 | + yield 0.0 |
1321 | |
1322 | === modified file 'ucivms/vms.py' |
1323 | --- ucivms/vms.py 2015-07-03 14:02:32 +0000 |
1324 | +++ ucivms/vms.py 2015-07-22 17:15:37 +0000 |
1325 | @@ -19,11 +19,15 @@ |
1326 | Note: Most of the operations requires root access and this script uses ``sudo`` |
1327 | to get them. |
1328 | """ |
1329 | +from __future__ import unicode_literals |
1330 | import io |
1331 | import errno |
1332 | import os |
1333 | import time |
1334 | -from urllib import parse as urlparse |
1335 | +try: |
1336 | + import urlparse # python2 |
1337 | +except: |
1338 | + from urllib import parse as urlparse |
1339 | |
1340 | |
1341 | import yaml |
1342 | @@ -46,7 +50,7 @@ |
1343 | """ |
1344 | |
1345 | def __init__(self, conf): |
1346 | - super().__init__() |
1347 | + super(CIUserData, self).__init__() |
1348 | self.conf = conf |
1349 | # The objects we will populate before creating a yaml encoding as a |
1350 | # cloud-config-archive file |
1351 | @@ -414,7 +418,12 @@ |
1352 | return False |
1353 | |
1354 | def ensure_dir(self, path): |
1355 | - os.makedirs(path, exist_ok=True) |
1356 | + try: |
1357 | + os.makedirs(path) |
1358 | + except OSError as e: |
1359 | + # python2 doesn't provide the exist_ok=True to makedirs |
1360 | + if e.errno != errno.EEXIST: |
1361 | + raise |
1362 | |
1363 | def config_dir_path(self): |
1364 | return self.conf.get('vm.config_dir') |
1365 | @@ -434,9 +443,10 @@ |
1366 | # The console may end up being owned by root, delete it first |
1367 | try: |
1368 | os.remove(console_path) |
1369 | - except FileNotFoundError: |
1370 | + except OSError as e: # python2 doesn't provide FileNotFoundError |
1371 | # It doesn't exist ? Job done. |
1372 | - pass |
1373 | + if e.errno != errno.ENOENT: |
1374 | + raise |
1375 | # Create the file so we get access to it (otherwise it may be owned by |
1376 | # root). |
1377 | open(console_path, 'w').close() |
1378 | @@ -501,7 +511,8 @@ |
1379 | content = f.read() |
1380 | ip, mask, mac = content.split() |
1381 | return ip, mask, mac |
1382 | - except OSError as e: |
1383 | + except IOError as e: |
1384 | + # python2 does not provide FileNotFoundError |
1385 | if e.errno == errno.ENOENT: |
1386 | # Unknown interface |
1387 | return None |
1388 | @@ -573,7 +584,8 @@ |
1389 | # We're done |
1390 | pass |
1391 | |
1392 | - def get_ssh_command(self, command, *args, ip=None): |
1393 | + def get_ssh_command(self, command, *args, **kwargs): |
1394 | + ip = kwargs.pop('ip', None) |
1395 | user = 'ubuntu' |
1396 | # Unless the home is bound |
1397 | if self.conf.get('vm.bind_home'): |
1398 | @@ -624,7 +636,7 @@ |
1399 | class Kvm(VM): |
1400 | |
1401 | def __init__(self, conf): |
1402 | - super().__init__(conf) |
1403 | + super(Kvm, self).__init__(conf) |
1404 | # Disk paths |
1405 | self._disk_image_path = None |
1406 | self._seed_path = None |
1407 | @@ -728,7 +740,7 @@ |
1408 | # sudo and can't be killed anymore. |
1409 | subprocesses.run(['sudo', 'chmod', '0644', self.console_path()]) |
1410 | # While `virt-install` is running, let's connect to the console |
1411 | - super().scan_console_during_install(console_size, cmd) |
1412 | + super(Kvm, self).scan_console_during_install(console_size, cmd) |
1413 | |
1414 | def install(self): |
1415 | # Create a kvm, relying on cloud-init to customize the base image. |
1416 | @@ -881,7 +893,7 @@ |
1417 | class Lxc(VM): |
1418 | |
1419 | def __init__(self, conf): |
1420 | - super().__init__(conf) |
1421 | + super(Lxc, self).__init__(conf) |
1422 | self._guest_seed_path = None |
1423 | self._fstab_path = None |
1424 | self._lxc_base_path = None |
I left some comments about typos in comments, mostly.
After you fix that, feel free to approve.