Merge lp:~vila/uci-vms/py2 into lp:uci-vms

Proposed by Vincent Ladeuil
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
Reviewer Review Type Date Requested Status
Leo Arias (community) Needs Fixing
Review via email: mp+265576@code.launchpad.net

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
Leo Arias (elopio) wrote :

I left some comments about typos in comments, mostly.
After you fix that, feel free to approve.

review: Needs Fixing
Revision history for this message
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

Subscribers

People subscribed via source and target branches