Merge lp:~mvo/unattended-upgrades/minimal-step-paranonia-lp1020680 into lp:~mvo/unattended-upgrades/debian-sid-mirror
- minimal-step-paranonia-lp1020680
- Merge into debian-sid-mirror
Proposed by
Michael Vogt
Status: | Needs review |
---|---|
Proposed branch: | lp:~mvo/unattended-upgrades/minimal-step-paranonia-lp1020680 |
Merge into: | lp:~mvo/unattended-upgrades/debian-sid-mirror |
Diff against target: |
1929 lines (+450/-271) 23 files modified
.bzrignore (+2/-0) debian/changelog (+23/-2) debian/control (+5/-4) debian/rules (+13/-11) debian/tests/control (+2/-0) debian/tests/run-tests (+4/-0) debian/unattended-upgrades.init (+1/-1) pm/sleep.d/10_unattended-upgrades-hibernate (+1/-1) setup.py (+4/-3) test/Makefile (+9/-2) test/create_debug_lock.py (+2/-1) test/test_against_real_archive.py (+14/-4) test/test_conffile.py (+4/-4) test/test_in_chroot.py (+41/-34) test/test_logdir.py (+3/-2) test/test_mail.py (+33/-16) test/test_minimal_partitions.py (+10/-10) test/test_origin_pattern.py (+31/-15) test/test_pep8.py (+17/-0) test/test_pyflakes.py (+4/-2) test/test_substitute.py (+2/-7) unattended-upgrade (+222/-149) unattended-upgrade-shutdown (+3/-3) |
To merge this branch: | bzr merge lp:~mvo/unattended-upgrades/minimal-step-paranonia-lp1020680 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Michael Vogt | Pending | ||
Review via email:
|
Commit message
Description of the change
Add extra paranoia in the minimal upgade mode to ensure we are not hit by #1020680
To post a comment you must log in.
Unmerged revisions
- 304. By Michael Vogt
-
pass the blacklist to upgrade_
in_minimal_ steps() as the conffile checking code may expand it - 303. By Michael Vogt
-
add a additional check_changes_
for_sanity( ) into upgrade_ in_minimal_ steps() code - 302. By Michael Vogt
-
test/Makefile: fix cleanup
- 301. By Michael Vogt
-
debian/
tests/run- tests: add run-test script - 300. By Michael Vogt
-
add dep8 tests
- 299. By Michael Vogt
-
Fixed debug output when a package has no candidates (LP: #1046438)
- 298. By Michael Vogt
-
releasing version 0.79.3ubuntu1
- 297. By Michael Vogt
-
fully pep8 clean (yeah!)
- 296. By Michael Vogt
-
add pyflakes/pep8 tests
- 295. By Michael Vogt
-
add py2 compatiblity back for easier backporting and run the tests in both py2/py3 and also run python-coverage
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === added file '.bzrignore' | |||
2 | --- .bzrignore 1970-01-01 00:00:00 +0000 | |||
3 | +++ .bzrignore 2012-10-08 16:08:26 +0000 | |||
4 | @@ -0,0 +1,2 @@ | |||
5 | 1 | __pycache__ | ||
6 | 2 | build | ||
7 | 0 | 3 | ||
8 | === modified file 'debian/changelog' | |||
9 | --- debian/changelog 2012-08-14 13:04:45 +0000 | |||
10 | +++ debian/changelog 2012-10-08 16:08:26 +0000 | |||
11 | @@ -1,3 +1,24 @@ | |||
12 | 1 | unattended-upgrades (0.79.3ubuntu2) quantal; urgency=low | ||
13 | 2 | |||
14 | 3 | [ Marc Tardif ] | ||
15 | 4 | * Fixed debug output when a package has no candidates (LP: #1046438) | ||
16 | 5 | |||
17 | 6 | [ Michael Vogt ] | ||
18 | 7 | * debian/test/: | ||
19 | 8 | - add dep8 tests | ||
20 | 9 | |||
21 | 10 | -- Marc Tardif <marc@ubuntu.com> Thu, 13 Sep 2012 16:16:04 -0400 | ||
22 | 11 | |||
23 | 12 | unattended-upgrades (0.79.3ubuntu1) quantal; urgency=low | ||
24 | 13 | |||
25 | 14 | [ Thomas Kluyver ] | ||
26 | 15 | * Port to Python 3 | ||
27 | 16 | |||
28 | 17 | [ Brian Murray ] | ||
29 | 18 | * unattended-upgrade: fix typo in debugging output | ||
30 | 19 | |||
31 | 20 | -- Michael Vogt <michael.vogt@ubuntu.com> Mon, 10 Sep 2012 09:55:19 +0200 | ||
32 | 21 | |||
33 | 1 | unattended-upgrades (0.79.4) UNRELEASED; urgency=low | 22 | unattended-upgrades (0.79.4) UNRELEASED; urgency=low |
34 | 2 | 23 | ||
35 | 3 | * data/50unattended-upgrades.{Debian,Ubuntu}: | 24 | * data/50unattended-upgrades.{Debian,Ubuntu}: |
36 | @@ -63,7 +84,7 @@ | |||
37 | 63 | - added, thanks to Pedro Ribeiro, closes: #678738 | 84 | - added, thanks to Pedro Ribeiro, closes: #678738 |
38 | 64 | * po/sk.po: | 85 | * po/sk.po: |
39 | 65 | - added, thanks to helix84, closes: #677471 | 86 | - added, thanks to helix84, closes: #677471 |
41 | 66 | 87 | ||
42 | 67 | [ Teodor MICU ] | 88 | [ Teodor MICU ] |
43 | 68 | * debian/unattended-upgrades.init: | 89 | * debian/unattended-upgrades.init: |
44 | 69 | - fixes new style lsb-init output, closes: #678030 | 90 | - fixes new style lsb-init output, closes: #678030 |
45 | @@ -93,7 +114,7 @@ | |||
46 | 93 | - updated, thanks to Joe Dalton, closes: #677804 | 114 | - updated, thanks to Joe Dalton, closes: #677804 |
47 | 94 | * po/de.po: | 115 | * po/de.po: |
48 | 95 | - updated, thanks to Chris Leick (closes: #678204) | 116 | - updated, thanks to Chris Leick (closes: #678204) |
50 | 96 | 117 | ||
51 | 97 | [ Teodor MICU ] | 118 | [ Teodor MICU ] |
52 | 98 | * debian/unattended-upgrades.init: | 119 | * debian/unattended-upgrades.init: |
53 | 99 | - use new style lsb-init output, closes: #678030 | 120 | - use new style lsb-init output, closes: #678030 |
54 | 100 | 121 | ||
55 | === modified file 'debian/control' | |||
56 | --- debian/control 2012-07-13 18:51:00 +0000 | |||
57 | +++ debian/control 2012-10-08 16:08:26 +0000 | |||
58 | @@ -3,14 +3,15 @@ | |||
59 | 3 | Priority: optional | 3 | Priority: optional |
60 | 4 | Maintainer: Michael Vogt <michael.vogt@ubuntu.com> | 4 | Maintainer: Michael Vogt <michael.vogt@ubuntu.com> |
61 | 5 | Build-Depends: debhelper (>= 7.0.50~), po-debconf, lsb-release | 5 | Build-Depends: debhelper (>= 7.0.50~), po-debconf, lsb-release |
64 | 6 | Build-Depends-Indep: python (>= 2.6.6-3~), python-distutils-extra | 6 | Build-Depends-Indep: python3, python3-distutils-extra |
65 | 7 | Standards-Version: 3.8.3 | 7 | Standards-Version: 3.9.3 |
66 | 8 | Vcs-Bzr: http://code.launchpad.net/~ubuntu-core-dev/unattended-upgrades/ubuntu/ | 8 | Vcs-Bzr: http://code.launchpad.net/~ubuntu-core-dev/unattended-upgrades/ubuntu/ |
67 | 9 | XS-Testsuite: autopkgtest | ||
68 | 9 | 10 | ||
69 | 10 | Package: unattended-upgrades | 11 | Package: unattended-upgrades |
70 | 11 | Architecture: all | 12 | Architecture: all |
73 | 12 | Depends: ${shlibs:Depends}, ${misc:Depends}, debconf, python, | 13 | Depends: ${shlibs:Depends}, ${misc:Depends}, debconf, python3, |
74 | 13 | python-apt (>= 0.7.90), apt-utils, apt, ucf, lsb-release, | 14 | python3-apt (>= 0.7.90), apt-utils, apt, ucf, lsb-release, |
75 | 14 | lsb-base (>= 3.2-14) | 15 | lsb-base (>= 3.2-14) |
76 | 15 | Suggests: bsd-mailx, mail-transport-agent | 16 | Suggests: bsd-mailx, mail-transport-agent |
77 | 16 | Description: automatic installation of security upgrades | 17 | Description: automatic installation of security upgrades |
78 | 17 | 18 | ||
79 | === modified file 'debian/rules' | |||
80 | --- debian/rules 2011-11-09 19:20:50 +0000 | |||
81 | +++ debian/rules 2012-10-08 16:08:26 +0000 | |||
82 | @@ -3,24 +3,26 @@ | |||
83 | 3 | DIST=$(shell /usr/bin/lsb_release -i -s) | 3 | DIST=$(shell /usr/bin/lsb_release -i -s) |
84 | 4 | 4 | ||
85 | 5 | %: | 5 | %: |
87 | 6 | dh $@ --with python2 | 6 | dh $@ --with python3 |
88 | 7 | 7 | ||
89 | 8 | override_dh_auto_build: | 8 | override_dh_auto_build: |
90 | 9 | # copy the right template into place | 9 | # copy the right template into place |
91 | 10 | cp data/50unattended-upgrades.$(DIST) data/50unattended-upgrades | 10 | cp data/50unattended-upgrades.$(DIST) data/50unattended-upgrades |
93 | 11 | dh_auto_build | 11 | python3 setup.py build |
94 | 12 | |||
95 | 13 | override_dh_auto_install: | ||
96 | 14 | python3 setup.py install \ | ||
97 | 15 | --root=$(CURDIR)/debian/unattended-upgrades \ | ||
98 | 16 | --install-layout=deb | ||
99 | 12 | 17 | ||
100 | 13 | override_dh_auto_clean: | 18 | override_dh_auto_clean: |
101 | 14 | # Sanity-check before upload. | 19 | # Sanity-check before upload. |
111 | 15 | set -e; if [ -e /usr/lib/python$(PYVER)/py_compile.py ]; then \ | 20 | set -e; for f in unattended-upgrade unattended-upgrade-shutdown; do \ |
112 | 16 | for f in unattended-upgrade unattended-upgrade-shutdown; do \ | 21 | ln -nsf $$f $$f.py; \ |
113 | 17 | ln -nsf $$f $$f.py; \ | 22 | py3compile $$f.py; \ |
114 | 18 | python$(PYVER) /usr/lib/python$(PYVER)/py_compile.py \ | 23 | rm -f $$f.py; \ |
115 | 19 | $$f.py; \ | 24 | done |
116 | 20 | rm -f $$f.py; \ | 25 | python3 setup.py clean -a |
108 | 21 | done; \ | ||
109 | 22 | fi | ||
110 | 23 | dh_auto_clean | ||
117 | 24 | 26 | ||
118 | 25 | override_dh_installinit: | 27 | override_dh_installinit: |
119 | 26 | # we do not want to run the init script in the postinst/prerm, its | 28 | # we do not want to run the init script in the postinst/prerm, its |
120 | 27 | 29 | ||
121 | === added directory 'debian/tests' | |||
122 | === added file 'debian/tests/control' | |||
123 | --- debian/tests/control 1970-01-01 00:00:00 +0000 | |||
124 | +++ debian/tests/control 2012-10-08 16:08:26 +0000 | |||
125 | @@ -0,0 +1,2 @@ | |||
126 | 1 | Tests: run-tests | ||
127 | 2 | Depends: @, make, python-dev, python3-dev, python-coverage | ||
128 | 0 | 3 | ||
129 | === added file 'debian/tests/run-tests' | |||
130 | --- debian/tests/run-tests 1970-01-01 00:00:00 +0000 | |||
131 | +++ debian/tests/run-tests 2012-10-08 16:08:26 +0000 | |||
132 | @@ -0,0 +1,4 @@ | |||
133 | 1 | #!/bin/sh | ||
134 | 2 | |||
135 | 3 | cd test | ||
136 | 4 | make | ||
137 | 0 | 5 | ||
138 | === modified file 'debian/unattended-upgrades.init' | |||
139 | --- debian/unattended-upgrades.init 2012-06-29 08:09:25 +0000 | |||
140 | +++ debian/unattended-upgrades.init 2012-10-08 16:08:26 +0000 | |||
141 | @@ -33,7 +33,7 @@ | |||
142 | 33 | stop) | 33 | stop) |
143 | 34 | if [ -e $SHUTDOWN_HELPER ]; then | 34 | if [ -e $SHUTDOWN_HELPER ]; then |
144 | 35 | [ "$VERBOSE" != "no" ] && log_action_begin_msg "Checking for running $DESC" | 35 | [ "$VERBOSE" != "no" ] && log_action_begin_msg "Checking for running $DESC" |
146 | 36 | python $SHUTDOWN_HELPER | 36 | python3 $SHUTDOWN_HELPER |
147 | 37 | [ "$VERBOSE" != "no" ] && log_action_end_msg $? "$NAME" | 37 | [ "$VERBOSE" != "no" ] && log_action_end_msg $? "$NAME" |
148 | 38 | fi | 38 | fi |
149 | 39 | ;; | 39 | ;; |
150 | 40 | 40 | ||
151 | === modified file 'pm/sleep.d/10_unattended-upgrades-hibernate' | |||
152 | --- pm/sleep.d/10_unattended-upgrades-hibernate 2011-11-08 16:56:58 +0000 | |||
153 | +++ pm/sleep.d/10_unattended-upgrades-hibernate 2012-10-08 16:08:26 +0000 | |||
154 | @@ -17,7 +17,7 @@ | |||
155 | 17 | case "${1}" in | 17 | case "${1}" in |
156 | 18 | hibernate) | 18 | hibernate) |
157 | 19 | if [ -e $SHUTDOWN_HELPER ]; then | 19 | if [ -e $SHUTDOWN_HELPER ]; then |
159 | 20 | python $SHUTDOWN_HELPER | 20 | python3 $SHUTDOWN_HELPER |
160 | 21 | fi | 21 | fi |
161 | 22 | ;; | 22 | ;; |
162 | 23 | resume|thaw) | 23 | resume|thaw) |
163 | 24 | 24 | ||
164 | === modified file 'setup.py' | |||
165 | --- setup.py 2011-10-24 10:20:18 +0000 | |||
166 | +++ setup.py 2012-10-08 16:08:26 +0000 | |||
167 | @@ -1,9 +1,10 @@ | |||
168 | 1 | #!/usr/bin/env python | 1 | #!/usr/bin/env python |
169 | 2 | 2 | ||
170 | 3 | from distutils.core import setup | 3 | from distutils.core import setup |
174 | 4 | from DistUtilsExtra.command import * | 4 | from DistUtilsExtra.command import ( |
175 | 5 | import glob | 5 | build_extra, |
176 | 6 | import os | 6 | build_i18n, |
177 | 7 | ) | ||
178 | 7 | 8 | ||
179 | 8 | 9 | ||
180 | 9 | setup(name='unattended-upgrades', version='0.1', | 10 | setup(name='unattended-upgrades', version='0.1', |
181 | 10 | 11 | ||
182 | === modified file 'test/Makefile' | |||
183 | --- test/Makefile 2011-10-07 09:22:19 +0000 | |||
184 | +++ test/Makefile 2012-10-08 16:08:26 +0000 | |||
185 | @@ -3,12 +3,15 @@ | |||
186 | 3 | all: check | 3 | all: check |
187 | 4 | 4 | ||
188 | 5 | check: | 5 | check: |
189 | 6 | # test with both py2 and py3 for now and also use coverage for the py2 | ||
190 | 6 | set -e; \ | 7 | set -e; \ |
191 | 7 | find . -name 'test_*.py' | \ | 8 | find . -name 'test_*.py' | \ |
192 | 8 | while read file; do \ | 9 | while read file; do \ |
193 | 9 | echo "Running $$file"; \ | ||
194 | 10 | if [ -x $$file ]; then \ | 10 | if [ -x $$file ]; then \ |
196 | 11 | python $$file ; \ | 11 | echo "Running $$file with python3"; \ |
197 | 12 | python3 $$file ; \ | ||
198 | 13 | echo "Running $$file with python"; \ | ||
199 | 14 | python-coverage run -a $$file; \ | ||
200 | 12 | fi \ | 15 | fi \ |
201 | 13 | done | 16 | done |
202 | 14 | 17 | ||
203 | @@ -16,4 +19,8 @@ | |||
204 | 16 | rm -rf ./aptroot/var/cache/ | 19 | rm -rf ./aptroot/var/cache/ |
205 | 17 | rm -rf ./aptroot/var/lib/apt | 20 | rm -rf ./aptroot/var/lib/apt |
206 | 18 | rm -rf ./aptroot/var/run | 21 | rm -rf ./aptroot/var/run |
207 | 22 | find .. -type d -name __pycache__ | xargs rm -rf | ||
208 | 19 | 23 | ||
209 | 24 | coverage-html: | ||
210 | 25 | echo "output in htmlcov/ | ||
211 | 26 | python-coverage html | ||
212 | 20 | \ No newline at end of file | 27 | \ No newline at end of file |
213 | 21 | 28 | ||
214 | === modified file 'test/create_debug_lock.py' | |||
215 | --- test/create_debug_lock.py 2011-06-16 07:10:07 +0000 | |||
216 | +++ test/create_debug_lock.py 2012-10-08 16:08:26 +0000 | |||
217 | @@ -1,4 +1,4 @@ | |||
219 | 1 | #!/usr/bin/python | 1 | #!/usr/bin/python3 |
220 | 2 | # | 2 | # |
221 | 3 | # create a lock file so that unattended-upgrades-shutdown pauses | 3 | # create a lock file so that unattended-upgrades-shutdown pauses |
222 | 4 | # on shutdown -- useful for testing | 4 | # on shutdown -- useful for testing |
223 | @@ -7,6 +7,7 @@ | |||
224 | 7 | import os | 7 | import os |
225 | 8 | import time | 8 | import time |
226 | 9 | 9 | ||
227 | 10 | |||
228 | 10 | pid = os.fork() | 11 | pid = os.fork() |
229 | 11 | if pid == 0: | 12 | if pid == 0: |
230 | 12 | os.setsid() | 13 | os.setsid() |
231 | 13 | 14 | ||
232 | === modified file 'test/test_against_real_archive.py' (properties changed: +x to -x) | |||
233 | --- test/test_against_real_archive.py 2012-02-28 10:48:18 +0000 | |||
234 | +++ test/test_against_real_archive.py 2012-10-08 16:08:26 +0000 | |||
235 | @@ -1,22 +1,31 @@ | |||
237 | 1 | #!/usr/bin/python | 1 | #!/usr/bin/python3 |
238 | 2 | """Test unattended_upgrades against the real archive in a chroot. | ||
239 | 3 | |||
240 | 4 | Note that this test is not run by the makefile in this folder, as it requires | ||
241 | 5 | network access, and it fails in some situations (unclear which). | ||
242 | 6 | """ | ||
243 | 2 | 7 | ||
244 | 3 | import apt | 8 | import apt |
245 | 4 | import apt_pkg | 9 | import apt_pkg |
246 | 5 | import glob | 10 | import glob |
247 | 11 | import logging | ||
248 | 6 | import os | 12 | import os |
249 | 7 | import re | 13 | import re |
250 | 8 | import unittest | 14 | import unittest |
251 | 9 | 15 | ||
252 | 10 | import unattended_upgrade | 16 | import unattended_upgrade |
253 | 11 | 17 | ||
254 | 18 | |||
255 | 12 | apt_pkg.config.set("APT::Architecture", "amd64") | 19 | apt_pkg.config.set("APT::Architecture", "amd64") |
256 | 13 | 20 | ||
257 | 21 | |||
258 | 14 | class MockOptions(): | 22 | class MockOptions(): |
259 | 15 | def __init__(self, debug=True, dry_run=True): | 23 | def __init__(self, debug=True, dry_run=True): |
260 | 16 | self.debug = debug | 24 | self.debug = debug |
261 | 17 | self.dry_run = dry_run | 25 | self.dry_run = dry_run |
262 | 18 | self.minimal_upgrade_steps = False | 26 | self.minimal_upgrade_steps = False |
263 | 19 | 27 | ||
264 | 28 | |||
265 | 20 | class TestAgainstRealArchive(unittest.TestCase): | 29 | class TestAgainstRealArchive(unittest.TestCase): |
266 | 21 | 30 | ||
267 | 22 | def setUp(self): | 31 | def setUp(self): |
268 | @@ -40,11 +49,13 @@ | |||
269 | 40 | apt_pkg.config.set("APT::UnattendedUpgrades::LogDir", logdir) | 49 | apt_pkg.config.set("APT::UnattendedUpgrades::LogDir", logdir) |
270 | 41 | unattended_upgrade.DISTRO_CODENAME = "lucid" | 50 | unattended_upgrade.DISTRO_CODENAME = "lucid" |
271 | 42 | res = unattended_upgrade.main(options, os.path.abspath("./aptroot")) | 51 | res = unattended_upgrade.main(options, os.path.abspath("./aptroot")) |
272 | 52 | logging.debug(res) | ||
273 | 43 | # check if the log file exists | 53 | # check if the log file exists |
274 | 44 | self.assertTrue(os.path.exists(logfile)) | 54 | self.assertTrue(os.path.exists(logfile)) |
276 | 45 | log = open(logfile).read() | 55 | with open(logfile) as fp: |
277 | 56 | log = fp.read() | ||
278 | 46 | # check that stuff worked | 57 | # check that stuff worked |
280 | 47 | self.assertFalse(" ERROR " in log) | 58 | self.assertFalse(" ERROR " in log, log) |
281 | 48 | # check if we actually have the expected ugprade in it | 59 | # check if we actually have the expected ugprade in it |
282 | 49 | self.assertTrue( | 60 | self.assertTrue( |
283 | 50 | re.search("INFO Packages that are upgraded:.*awstats", log)) | 61 | re.search("INFO Packages that are upgraded:.*awstats", log)) |
284 | @@ -59,4 +70,3 @@ | |||
285 | 59 | 70 | ||
286 | 60 | if __name__ == "__main__": | 71 | if __name__ == "__main__": |
287 | 61 | unittest.main() | 72 | unittest.main() |
288 | 62 | |||
289 | 63 | 73 | ||
290 | === modified file 'test/test_conffile.py' | |||
291 | --- test/test_conffile.py 2012-06-28 20:06:37 +0000 | |||
292 | +++ test/test_conffile.py 2012-10-08 16:08:26 +0000 | |||
293 | @@ -1,12 +1,13 @@ | |||
295 | 1 | #!/usr/bin/python | 1 | #!/usr/bin/python3 |
296 | 2 | 2 | ||
297 | 3 | import apt_pkg | 3 | import apt_pkg |
298 | 4 | import logging | 4 | import logging |
299 | 5 | import unittest | 5 | import unittest |
301 | 6 | import sys | 6 | |
302 | 7 | 7 | ||
303 | 8 | from unattended_upgrade import conffile_prompt | 8 | from unattended_upgrade import conffile_prompt |
304 | 9 | 9 | ||
305 | 10 | |||
306 | 10 | class ConffilePromptTestCase(unittest.TestCase): | 11 | class ConffilePromptTestCase(unittest.TestCase): |
307 | 11 | 12 | ||
308 | 12 | def setUp(self): | 13 | def setUp(self): |
309 | @@ -19,7 +20,7 @@ | |||
310 | 19 | test_pkg = "./packages/conf-test-package_1.1.deb" | 20 | test_pkg = "./packages/conf-test-package_1.1.deb" |
311 | 20 | self.assertTrue(conffile_prompt(test_pkg, prefix="./root.conffile"), | 21 | self.assertTrue(conffile_prompt(test_pkg, prefix="./root.conffile"), |
312 | 21 | "conffile prompt detection incorrect") | 22 | "conffile prompt detection incorrect") |
314 | 22 | 23 | ||
315 | 23 | def test_will_not_prompt(self): | 24 | def test_will_not_prompt(self): |
316 | 24 | # conf-test 0.9 is installed, 1.0 gets installed | 25 | # conf-test 0.9 is installed, 1.0 gets installed |
317 | 25 | # they both have the same config files | 26 | # they both have the same config files |
318 | @@ -57,4 +58,3 @@ | |||
319 | 57 | if __name__ == "__main__": | 58 | if __name__ == "__main__": |
320 | 58 | logging.basicConfig(level=logging.DEBUG) | 59 | logging.basicConfig(level=logging.DEBUG) |
321 | 59 | unittest.main() | 60 | unittest.main() |
322 | 60 | |||
323 | 61 | 61 | ||
324 | === modified file 'test/test_in_chroot.py' | |||
325 | --- test/test_in_chroot.py 2012-06-28 20:06:37 +0000 | |||
326 | +++ test/test_in_chroot.py 2012-10-08 16:08:26 +0000 | |||
327 | @@ -1,4 +1,4 @@ | |||
329 | 1 | #!/usr/bin/python | 1 | #!/usr/bin/python3 |
330 | 2 | 2 | ||
331 | 3 | import apt | 3 | import apt |
332 | 4 | import logging | 4 | import logging |
333 | @@ -15,7 +15,8 @@ | |||
334 | 15 | #SOURCES_LIST=""" | 15 | #SOURCES_LIST=""" |
335 | 16 | #deb http://ftp.de.debian.org/debian squeeze main contrib non-free | 16 | #deb http://ftp.de.debian.org/debian squeeze main contrib non-free |
336 | 17 | #deb http://ftp.de.debian.org/debian squeeze-updates main contrib non-free | 17 | #deb http://ftp.de.debian.org/debian squeeze-updates main contrib non-free |
338 | 18 | #deb http://ftp.de.debian.org/debian squeeze-proposed-updates main contrib non-f#ree | 18 | #deb http://ftp.de.debian.org/debian squeeze-proposed-updates main contrib \ |
339 | 19 | # non-free | ||
340 | 19 | #deb http://security.debian.org squeeze/updates main contrib non-free | 20 | #deb http://security.debian.org squeeze/updates main contrib non-free |
341 | 20 | #""" | 21 | #""" |
342 | 21 | #DISTRO="squeeze" | 22 | #DISTRO="squeeze" |
343 | @@ -27,7 +28,7 @@ | |||
344 | 27 | 28 | ||
345 | 28 | 29 | ||
346 | 29 | # ubuntu | 30 | # ubuntu |
348 | 30 | SOURCES_LIST=""" | 31 | SOURCES_LIST = """ |
349 | 31 | deb http://archive.ubuntu.com/ubuntu/ lucid main restricted | 32 | deb http://archive.ubuntu.com/ubuntu/ lucid main restricted |
350 | 32 | deb-src http://archive.ubuntu.com/ubuntu/ lucid main restricted | 33 | deb-src http://archive.ubuntu.com/ubuntu/ lucid main restricted |
351 | 33 | 34 | ||
352 | @@ -37,35 +38,39 @@ | |||
353 | 37 | deb http://security.ubuntu.com/ubuntu/ lucid-security main restricted | 38 | deb http://security.ubuntu.com/ubuntu/ lucid-security main restricted |
354 | 38 | deb-src http://security.ubuntu.com/ubuntu/ lucid-security main restricted | 39 | deb-src http://security.ubuntu.com/ubuntu/ lucid-security main restricted |
355 | 39 | """ | 40 | """ |
362 | 40 | DISTRO="lucid" | 41 | DISTRO = "lucid" |
363 | 41 | ARCH="i386" | 42 | ARCH = "i386" |
364 | 42 | TARBALL="%s-%s.tgz" % (DISTRO, ARCH) | 43 | TARBALL = "%s-%s.tgz" % (DISTRO, ARCH) |
365 | 43 | MIRROR="http://archive.ubuntu.com/ubuntu" | 44 | MIRROR = "http://archive.ubuntu.com/ubuntu" |
366 | 44 | APT_CONF="""APT::Architecture "%s";""" % ARCH | 45 | APT_CONF = """APT::Architecture "%s";""" % ARCH |
367 | 45 | ORIGINS_PATTERN="origin=Ubuntu,archive=lucid-security" | 46 | ORIGINS_PATTERN = "origin=Ubuntu,archive=lucid-security" |
368 | 46 | 47 | ||
369 | 47 | apt.apt_pkg.config.set("APT::Architecture", ARCH) | 48 | apt.apt_pkg.config.set("APT::Architecture", ARCH) |
370 | 48 | sys.path.insert(0, "..") | 49 | sys.path.insert(0, "..") |
371 | 49 | import unattended_upgrade | 50 | import unattended_upgrade |
372 | 50 | 51 | ||
373 | 52 | |||
374 | 51 | class MockOptions(object): | 53 | class MockOptions(object): |
375 | 52 | debug = True | 54 | debug = True |
376 | 53 | dry_run = False | 55 | dry_run = False |
377 | 54 | minimal_upgrade_steps = False | 56 | minimal_upgrade_steps = False |
378 | 55 | 57 | ||
379 | 58 | |||
380 | 56 | class TestUnattendedUpgrade(unittest.TestCase): | 59 | class TestUnattendedUpgrade(unittest.TestCase): |
381 | 57 | 60 | ||
382 | 58 | def _create_new_debootstrap_tarball(self, tarball, target): | 61 | def _create_new_debootstrap_tarball(self, tarball, target): |
384 | 59 | print "creating initial test tarball, this is needed only once" | 62 | print("creating initial test tarball, this is needed only once") |
385 | 60 | # force i386 | 63 | # force i386 |
394 | 61 | subprocess.call(["debootstrap", | 64 | subprocess.call( |
395 | 62 | "--arch=%s" % ARCH, | 65 | ["debootstrap", |
396 | 63 | # smaller version of the minimal system | 66 | "--arch=%s" % ARCH, |
397 | 64 | "--variant=minbase", | 67 | # smaller version of the minimal system |
398 | 65 | "--include=python-apt,apt-utils,gpgv,ubuntu-keyring,ca-certificates", | 68 | "--variant=minbase", |
399 | 66 | DISTRO, | 69 | "--include=python-apt,apt-utils,gpgv,ubuntu-keyring," |
400 | 67 | target, | 70 | "ca-certificates", |
401 | 68 | MIRROR]) | 71 | DISTRO, |
402 | 72 | target, | ||
403 | 73 | MIRROR]) | ||
404 | 69 | subprocess.call(["chroot", target, "apt-get", "clean"]) | 74 | subprocess.call(["chroot", target, "apt-get", "clean"]) |
405 | 70 | subprocess.call(["tar", "czf", tarball, target]) | 75 | subprocess.call(["tar", "czf", tarball, target]) |
406 | 71 | 76 | ||
407 | @@ -73,7 +78,7 @@ | |||
408 | 73 | subprocess.call(["tar", "xzf", tarball]) | 78 | subprocess.call(["tar", "xzf", tarball]) |
409 | 74 | 79 | ||
410 | 75 | def test_normal_upgrade(self): | 80 | def test_normal_upgrade(self): |
412 | 76 | print "Running normal unattended upgrade in chroot" | 81 | print("Running normal unattended upgrade in chroot") |
413 | 77 | options = MockOptions() | 82 | options = MockOptions() |
414 | 78 | options.minimal_upgrade_steps = False | 83 | options.minimal_upgrade_steps = False |
415 | 79 | # run it | 84 | # run it |
416 | @@ -82,7 +87,7 @@ | |||
417 | 82 | self.assertTrue(self._verify_install_log_in_real_chroot(target)) | 87 | self.assertTrue(self._verify_install_log_in_real_chroot(target)) |
418 | 83 | 88 | ||
419 | 84 | def test_minimal_steps_upgrade(self): | 89 | def test_minimal_steps_upgrade(self): |
421 | 85 | print "Running minimal steps unattended upgrade in chroot" | 90 | print("Running minimal steps unattended upgrade in chroot") |
422 | 86 | options = MockOptions() | 91 | options = MockOptions() |
423 | 87 | options.minimal_upgrade_steps = True | 92 | options.minimal_upgrade_steps = True |
424 | 88 | # run it | 93 | # run it |
425 | @@ -91,14 +96,15 @@ | |||
426 | 91 | self.assertTrue(self._verify_install_log_in_real_chroot(target)) | 96 | self.assertTrue(self._verify_install_log_in_real_chroot(target)) |
427 | 92 | 97 | ||
428 | 93 | def test_upgrade_on_shutdown_upgrade(self): | 98 | def test_upgrade_on_shutdown_upgrade(self): |
430 | 94 | print "Running unattended upgrade on shutdown (download and install) in chroot" | 99 | print("Running unattended upgrade on shutdown (download and install) " |
431 | 100 | "in chroot") | ||
432 | 95 | # ensure that it actually installs in shutdown env mode | 101 | # ensure that it actually installs in shutdown env mode |
433 | 96 | options = MockOptions() | 102 | options = MockOptions() |
434 | 97 | os.environ["UNATTENDED_UPGRADES_FORCE_INSTALL_ON_SHUTDOWN"] = "1" | 103 | os.environ["UNATTENDED_UPGRADES_FORCE_INSTALL_ON_SHUTDOWN"] = "1" |
435 | 98 | apt.apt_pkg.config.set("Unattended-Upgrade::InstallOnShutdown", "1") | 104 | apt.apt_pkg.config.set("Unattended-Upgrade::InstallOnShutdown", "1") |
436 | 99 | target = self._run_upgrade_test_in_real_chroot(options) | 105 | target = self._run_upgrade_test_in_real_chroot(options) |
437 | 100 | self.assertTrue(self._verify_install_log_in_real_chroot(target)) | 106 | self.assertTrue(self._verify_install_log_in_real_chroot(target)) |
439 | 101 | 107 | ||
440 | 102 | def _get_lockfile_location(self, target): | 108 | def _get_lockfile_location(self, target): |
441 | 103 | return os.path.join( | 109 | return os.path.join( |
442 | 104 | target, "var/log/unattended-upgrades/unattended-upgrades.log") | 110 | target, "var/log/unattended-upgrades/unattended-upgrades.log") |
443 | @@ -114,14 +120,13 @@ | |||
444 | 114 | open(os.path.join(target, "etc/apt/apt.conf"), "w").write(APT_CONF) | 120 | open(os.path.join(target, "etc/apt/apt.conf"), "w").write(APT_CONF) |
445 | 115 | open(os.path.join(target, "etc/apt/sources.list"), "w").write( | 121 | open(os.path.join(target, "etc/apt/sources.list"), "w").write( |
446 | 116 | SOURCES_LIST) | 122 | SOURCES_LIST) |
447 | 117 | |||
448 | 118 | 123 | ||
449 | 119 | def _run_upgrade_test_in_real_chroot(self, options, clean_chroot=True): | 124 | def _run_upgrade_test_in_real_chroot(self, options, clean_chroot=True): |
450 | 120 | """ helper that runs the unattended-upgrade in a chroot | 125 | """ helper that runs the unattended-upgrade in a chroot |
451 | 121 | and does some basic verifications | 126 | and does some basic verifications |
452 | 122 | """ | 127 | """ |
453 | 123 | if os.getuid() != 0: | 128 | if os.getuid() != 0: |
455 | 124 | print "Skipping because uid != 0" | 129 | print("Skipping because uid != 0") |
456 | 125 | return | 130 | return |
457 | 126 | 131 | ||
458 | 127 | # clear to avoid pollution in the chroot | 132 | # clear to avoid pollution in the chroot |
459 | @@ -130,7 +135,7 @@ | |||
460 | 130 | # create chroot | 135 | # create chroot |
461 | 131 | target = "./test-chroot.%s" % DISTRO | 136 | target = "./test-chroot.%s" % DISTRO |
462 | 132 | 137 | ||
464 | 133 | # setup chroot if needed | 138 | # setup chroot if needed |
465 | 134 | if clean_chroot: | 139 | if clean_chroot: |
466 | 135 | self._setup_chroot(target) | 140 | self._setup_chroot(target) |
467 | 136 | 141 | ||
468 | @@ -143,7 +148,7 @@ | |||
469 | 143 | if not os.path.exists("/var/log/unattended-upgrades/"): | 148 | if not os.path.exists("/var/log/unattended-upgrades/"): |
470 | 144 | os.makedirs("/var/log/unattended-upgrades/") | 149 | os.makedirs("/var/log/unattended-upgrades/") |
471 | 145 | # make sure we are up-to-date | 150 | # make sure we are up-to-date |
473 | 146 | subprocess.call(["apt-get","update", "-q", "-q"]) | 151 | subprocess.call(["apt-get", "update", "-q", "-q"]) |
474 | 147 | # run it | 152 | # run it |
475 | 148 | apt.apt_pkg.config.clear("Unattended-Upgrade::Allowed-Origins") | 153 | apt.apt_pkg.config.clear("Unattended-Upgrade::Allowed-Origins") |
476 | 149 | apt.apt_pkg.config.clear("Unattended-Upgrade::Origins-Pattern") | 154 | apt.apt_pkg.config.clear("Unattended-Upgrade::Origins-Pattern") |
477 | @@ -153,7 +158,7 @@ | |||
478 | 153 | unattended_upgrade.main(options) | 158 | unattended_upgrade.main(options) |
479 | 154 | os._exit(0) | 159 | os._exit(0) |
480 | 155 | else: | 160 | else: |
482 | 156 | has_progress=False | 161 | has_progress = False |
483 | 157 | all_progress = "" | 162 | all_progress = "" |
484 | 158 | last_progress = "" | 163 | last_progress = "" |
485 | 159 | progress_log = os.path.join( | 164 | progress_log = os.path.join( |
486 | @@ -171,9 +176,9 @@ | |||
487 | 171 | if pid == apid: | 176 | if pid == apid: |
488 | 172 | ret = os.WEXITSTATUS(status) | 177 | ret = os.WEXITSTATUS(status) |
489 | 173 | break | 178 | break |
491 | 174 | #print "*******************", all_progress | 179 | #print("*******************", all_progress) |
492 | 175 | self.assertEqual(ret, 0) | 180 | self.assertEqual(ret, 0) |
494 | 176 | # this number is a bit random, we just want to be sure we have | 181 | # this number is a bit random, we just want to be sure we have |
495 | 177 | # progress data | 182 | # progress data |
496 | 178 | self.assertTrue(has_progress, True) | 183 | self.assertTrue(has_progress, True) |
497 | 179 | self.assertTrue(len(all_progress) > 5) | 184 | self.assertTrue(len(all_progress) > 5) |
498 | @@ -183,11 +188,12 @@ | |||
499 | 183 | # examine log | 188 | # examine log |
500 | 184 | log = self._get_lockfile_location(target) | 189 | log = self._get_lockfile_location(target) |
501 | 185 | logfile = open(log).read() | 190 | logfile = open(log).read() |
504 | 186 | #print logfile | 191 | #print(logfile) |
505 | 187 | NEEDLE_PKG="ca-certificates" | 192 | NEEDLE_PKG = "ca-certificates" |
506 | 188 | if not re.search( | 193 | if not re.search( |
507 | 189 | "Packages that are upgraded:.*%s" % NEEDLE_PKG, logfile): | 194 | "Packages that are upgraded:.*%s" % NEEDLE_PKG, logfile): |
509 | 190 | logging.warn("Can not find expected %s upgrade in log" % NEEDLE_PKG) | 195 | logging.warn("Can not find expected %s upgrade in log" % |
510 | 196 | NEEDLE_PKG) | ||
511 | 191 | return False | 197 | return False |
512 | 192 | if "ERROR Installing the upgrades failed" in logfile: | 198 | if "ERROR Installing the upgrades failed" in logfile: |
513 | 193 | logging.warn("Got a ERROR in the logfile") | 199 | logging.warn("Got a ERROR in the logfile") |
514 | @@ -196,9 +202,10 @@ | |||
515 | 196 | target, "var/log/unattended-upgrades/*-dpkg*.log") | 202 | target, "var/log/unattended-upgrades/*-dpkg*.log") |
516 | 197 | dpkg_logfile = open(glob.glob(dpkg_log)[0]).read() | 203 | dpkg_logfile = open(glob.glob(dpkg_log)[0]).read() |
517 | 198 | if not "Preparing to replace %s" % NEEDLE_PKG in dpkg_logfile: | 204 | if not "Preparing to replace %s" % NEEDLE_PKG in dpkg_logfile: |
519 | 199 | logging.warn("Did not find %s upgrade in the dpkg.log" % NEEDLE_PKG) | 205 | logging.warn("Did not find %s upgrade in the dpkg.log" % |
520 | 206 | NEEDLE_PKG) | ||
521 | 200 | return False | 207 | return False |
523 | 201 | #print dpkg_logfile | 208 | #print(dpkg_logfile) |
524 | 202 | return True | 209 | return True |
525 | 203 | 210 | ||
526 | 204 | 211 | ||
527 | 205 | 212 | ||
528 | === modified file 'test/test_logdir.py' | |||
529 | --- test/test_logdir.py 2012-06-29 07:08:35 +0000 | |||
530 | +++ test/test_logdir.py 2012-10-08 16:08:26 +0000 | |||
531 | @@ -1,9 +1,8 @@ | |||
533 | 1 | #!/usr/bin/python | 1 | #!/usr/bin/python3 |
534 | 2 | 2 | ||
535 | 3 | import apt_pkg | 3 | import apt_pkg |
536 | 4 | import logging | 4 | import logging |
537 | 5 | import os | 5 | import os |
538 | 6 | import mock | ||
539 | 7 | import sys | 6 | import sys |
540 | 8 | import tempfile | 7 | import tempfile |
541 | 9 | import unittest | 8 | import unittest |
542 | @@ -11,10 +10,12 @@ | |||
543 | 11 | sys.path.insert(0, "..") | 10 | sys.path.insert(0, "..") |
544 | 12 | from unattended_upgrade import _setup_logging | 11 | from unattended_upgrade import _setup_logging |
545 | 13 | 12 | ||
546 | 13 | |||
547 | 14 | class MockOptions: | 14 | class MockOptions: |
548 | 15 | dry_run = False | 15 | dry_run = False |
549 | 16 | debug = False | 16 | debug = False |
550 | 17 | 17 | ||
551 | 18 | |||
552 | 18 | class TestLogdir(unittest.TestCase): | 19 | class TestLogdir(unittest.TestCase): |
553 | 19 | 20 | ||
554 | 20 | def setUp(self): | 21 | def setUp(self): |
555 | 21 | 22 | ||
556 | === modified file 'test/test_mail.py' | |||
557 | --- test/test_mail.py 2012-07-13 12:20:03 +0000 | |||
558 | +++ test/test_mail.py 2012-10-08 16:08:26 +0000 | |||
559 | @@ -1,11 +1,14 @@ | |||
561 | 1 | #!/usr/bin/python | 1 | #!/usr/bin/python3 |
562 | 2 | # -*- coding: utf-8 -*- | 2 | # -*- coding: utf-8 -*- |
563 | 3 | from __future__ import unicode_literals | ||
564 | 4 | |||
565 | 3 | import apt_pkg | 5 | import apt_pkg |
566 | 4 | import os | 6 | import os |
567 | 7 | import sys | ||
568 | 5 | import unittest | 8 | import unittest |
569 | 6 | 9 | ||
570 | 10 | from io import StringIO | ||
571 | 7 | from email.parser import Parser | 11 | from email.parser import Parser |
572 | 8 | from StringIO import StringIO | ||
573 | 9 | 12 | ||
574 | 10 | import unattended_upgrade | 13 | import unattended_upgrade |
575 | 11 | from unattended_upgrade import send_summary_mail, setup_apt_listchanges | 14 | from unattended_upgrade import send_summary_mail, setup_apt_listchanges |
576 | @@ -40,9 +43,10 @@ | |||
577 | 40 | res = successful | 43 | res = successful |
578 | 41 | pkgs_kept_back = [] | 44 | pkgs_kept_back = [] |
579 | 42 | # include some unicode chars here for good measure | 45 | # include some unicode chars here for good measure |
581 | 43 | mem_log = StringIO(u"mem_log text üöä") | 46 | mem_log = StringIO("mem_log text üöä") |
582 | 44 | logfile_dpkg = "./apt-term.log" | 47 | logfile_dpkg = "./apt-term.log" |
584 | 45 | open("./apt-term.log", "w").write("logfile_dpkg text") | 48 | with open("./apt-term.log", "w") as fp: |
585 | 49 | fp.write("logfile_dpkg text") | ||
586 | 46 | return (pkgs, res, pkgs_kept_back, mem_log, logfile_dpkg) | 50 | return (pkgs, res, pkgs_kept_back, mem_log, logfile_dpkg) |
587 | 47 | 51 | ||
588 | 48 | def _verify_common_mail_content(self, mail_txt): | 52 | def _verify_common_mail_content(self, mail_txt): |
589 | @@ -50,47 +54,55 @@ | |||
590 | 50 | self.assertTrue(expected_string in mail_txt) | 54 | self.assertTrue(expected_string in mail_txt) |
591 | 51 | 55 | ||
592 | 52 | def test_summary_mail_reboot(self): | 56 | def test_summary_mail_reboot(self): |
594 | 53 | open("./reboot-required","w").write("") | 57 | with open("./reboot-required", "w") as fp: |
595 | 58 | fp.write("") | ||
596 | 54 | send_summary_mail(*self._return_mock_data()) | 59 | send_summary_mail(*self._return_mock_data()) |
597 | 55 | os.unlink("./reboot-required") | 60 | os.unlink("./reboot-required") |
599 | 56 | mail_txt = open("mail.txt").read() | 61 | # this is used for py2 compat for py3 only we can do |
600 | 62 | # remove the "rb" and the subsequent '.decode("utf-8")' | ||
601 | 63 | with open("mail.txt", "rb") as fp: | ||
602 | 64 | mail_txt = fp.read().decode("utf-8") | ||
603 | 57 | self.assertTrue("[reboot required]" in mail_txt) | 65 | self.assertTrue("[reboot required]" in mail_txt) |
604 | 58 | self._verify_common_mail_content(mail_txt) | 66 | self._verify_common_mail_content(mail_txt) |
606 | 59 | 67 | ||
607 | 60 | def test_summary_mail_no_reboot(self): | 68 | def test_summary_mail_no_reboot(self): |
608 | 61 | send_summary_mail(*self._return_mock_data()) | 69 | send_summary_mail(*self._return_mock_data()) |
610 | 62 | mail_txt = open("mail.txt").read() | 70 | with open("mail.txt", "rb") as fp: |
611 | 71 | mail_txt = fp.read().decode("utf-8") | ||
612 | 63 | self.assertFalse("[reboot required]" in mail_txt) | 72 | self.assertFalse("[reboot required]" in mail_txt) |
613 | 64 | self._verify_common_mail_content(mail_txt) | 73 | self._verify_common_mail_content(mail_txt) |
615 | 65 | 74 | ||
616 | 66 | def test_summary_mail_only_on_error(self): | 75 | def test_summary_mail_only_on_error(self): |
617 | 67 | # default is to always send mail, ensure this is correct | 76 | # default is to always send mail, ensure this is correct |
618 | 68 | # for both success and failure | 77 | # for both success and failure |
619 | 69 | apt_pkg.config.set("Unattended-Upgrade::MailOnlyOnError", "false") | 78 | apt_pkg.config.set("Unattended-Upgrade::MailOnlyOnError", "false") |
620 | 70 | send_summary_mail(*self._return_mock_data(successful=True)) | 79 | send_summary_mail(*self._return_mock_data(successful=True)) |
622 | 71 | self._verify_common_mail_content(open("mail.txt").read()) | 80 | with open("mail.txt", "rb") as fp: |
623 | 81 | self._verify_common_mail_content(fp.read().decode("utf-8")) | ||
624 | 72 | os.remove("mail.txt") | 82 | os.remove("mail.txt") |
625 | 73 | # now with a simulated failure | 83 | # now with a simulated failure |
626 | 74 | send_summary_mail(*self._return_mock_data(successful=False)) | 84 | send_summary_mail(*self._return_mock_data(successful=False)) |
628 | 75 | self._verify_common_mail_content(open("mail.txt").read()) | 85 | with open("mail.txt", "rb") as fp: |
629 | 86 | self._verify_common_mail_content(fp.read().decode("utf-8")) | ||
630 | 76 | os.remove("mail.txt") | 87 | os.remove("mail.txt") |
631 | 77 | # now test with "MailOnlyOnError" | 88 | # now test with "MailOnlyOnError" |
632 | 78 | apt_pkg.config.set("Unattended-Upgrade::MailOnlyOnError", "true") | 89 | apt_pkg.config.set("Unattended-Upgrade::MailOnlyOnError", "true") |
633 | 79 | send_summary_mail(*self._return_mock_data(successful=True)) | 90 | send_summary_mail(*self._return_mock_data(successful=True)) |
634 | 80 | self.assertFalse(os.path.exists("mail.txt")) | 91 | self.assertFalse(os.path.exists("mail.txt")) |
635 | 81 | send_summary_mail(*self._return_mock_data(successful=False)) | 92 | send_summary_mail(*self._return_mock_data(successful=False)) |
637 | 82 | mail_txt = open("mail.txt").read() | 93 | with open("mail.txt", "rb") as fp: |
638 | 94 | mail_txt = fp.read().decode("utf-8") | ||
639 | 83 | self._verify_common_mail_content(mail_txt) | 95 | self._verify_common_mail_content(mail_txt) |
640 | 84 | self.assertTrue("Unattended upgrade returned: False" in mail_txt) | 96 | self.assertTrue("Unattended upgrade returned: False" in mail_txt) |
641 | 85 | self.assertTrue(os.path.exists("mail.txt")) | 97 | self.assertTrue(os.path.exists("mail.txt")) |
642 | 86 | 98 | ||
643 | 87 | def test_apt_listchanges(self): | 99 | def test_apt_listchanges(self): |
644 | 88 | # test with sendmail available | 100 | # test with sendmail available |
646 | 89 | unattended_upgrade.SENDMAIL_BINARY="/bin/true" | 101 | unattended_upgrade.SENDMAIL_BINARY = "/bin/true" |
647 | 90 | setup_apt_listchanges("./data/listchanges.conf.mail") | 102 | setup_apt_listchanges("./data/listchanges.conf.mail") |
648 | 91 | self.assertEqual(os.environ["APT_LISTCHANGES_FRONTEND"], "mail") | 103 | self.assertEqual(os.environ["APT_LISTCHANGES_FRONTEND"], "mail") |
649 | 92 | # test without sendmail | 104 | # test without sendmail |
651 | 93 | unattended_upgrade.SENDMAIL_BINARY="/bin/not-here-xxxxxxxxx" | 105 | unattended_upgrade.SENDMAIL_BINARY = "/bin/not-here-xxxxxxxxx" |
652 | 94 | setup_apt_listchanges("./data/listchanges.conf.pager") | 106 | setup_apt_listchanges("./data/listchanges.conf.pager") |
653 | 95 | self.assertEqual(os.environ["APT_LISTCHANGES_FRONTEND"], "none") | 107 | self.assertEqual(os.environ["APT_LISTCHANGES_FRONTEND"], "none") |
654 | 96 | 108 | ||
655 | @@ -108,6 +120,7 @@ | |||
656 | 108 | # we don't accidently try | 120 | # we don't accidently try |
657 | 109 | self.assertFalse('text/plain; charset="utf-8"' in mail_txt) | 121 | self.assertFalse('text/plain; charset="utf-8"' in mail_txt) |
658 | 110 | 122 | ||
659 | 123 | |||
660 | 111 | class SendmailTestCase(CommonTestsForMailxAndSendmail, unittest.TestCase): | 124 | class SendmailTestCase(CommonTestsForMailxAndSendmail, unittest.TestCase): |
661 | 112 | 125 | ||
662 | 113 | def setUp(self): | 126 | def setUp(self): |
663 | @@ -117,10 +130,15 @@ | |||
664 | 117 | def _verify_common_mail_content(self, mail_txt): | 130 | def _verify_common_mail_content(self, mail_txt): |
665 | 118 | CommonTestsForMailxAndSendmail._verify_common_mail_content( | 131 | CommonTestsForMailxAndSendmail._verify_common_mail_content( |
666 | 119 | self, mail_txt) | 132 | self, mail_txt) |
667 | 133 | |||
668 | 134 | # python2 needs this as utf8 encoded string (not unicode) | ||
669 | 135 | if sys.version < '3': | ||
670 | 136 | mail_txt = mail_txt.encode("utf-8") | ||
671 | 137 | |||
672 | 120 | msg = Parser().parsestr(mail_txt) | 138 | msg = Parser().parsestr(mail_txt) |
673 | 121 | content_type = msg["Content-Type"] | 139 | content_type = msg["Content-Type"] |
674 | 122 | self.assertEqual(content_type, 'text/plain; charset="utf-8"') | 140 | self.assertEqual(content_type, 'text/plain; charset="utf-8"') |
676 | 123 | 141 | ||
677 | 124 | 142 | ||
678 | 125 | class SendmailAndMailxTestCase(SendmailTestCase): | 143 | class SendmailAndMailxTestCase(SendmailTestCase): |
679 | 126 | 144 | ||
680 | @@ -132,4 +150,3 @@ | |||
681 | 132 | if __name__ == "__main__": | 150 | if __name__ == "__main__": |
682 | 133 | #logging.basicConfig(level=logging.DEBUG) | 151 | #logging.basicConfig(level=logging.DEBUG) |
683 | 134 | unittest.main() | 152 | unittest.main() |
684 | 135 | |||
685 | 136 | 153 | ||
686 | === modified file 'test/test_minimal_partitions.py' | |||
687 | --- test/test_minimal_partitions.py 2011-11-18 10:46:15 +0000 | |||
688 | +++ test/test_minimal_partitions.py 2012-10-08 16:08:26 +0000 | |||
689 | @@ -1,33 +1,32 @@ | |||
691 | 1 | #!/usr/bin/python | 1 | #!/usr/bin/python3 |
692 | 2 | 2 | ||
693 | 3 | import apt | 3 | import apt |
694 | 4 | import apt_pkg | 4 | import apt_pkg |
695 | 5 | import os | 5 | import os |
696 | 6 | import logging | ||
697 | 7 | import unittest | 6 | import unittest |
698 | 8 | import sys | ||
699 | 9 | import time | ||
700 | 10 | 7 | ||
701 | 11 | import unattended_upgrade | 8 | import unattended_upgrade |
702 | 12 | 9 | ||
703 | 10 | |||
704 | 13 | class LogInstallProgressMock(unattended_upgrade.LogInstallProgress): | 11 | class LogInstallProgressMock(unattended_upgrade.LogInstallProgress): |
705 | 14 | 12 | ||
706 | 15 | # klass data so that we can veriy in the test as the actual | 13 | # klass data so that we can veriy in the test as the actual |
707 | 16 | # object is destroyed | 14 | # object is destroyed |
708 | 17 | DATA = [] | 15 | DATA = [] |
710 | 18 | 16 | ||
711 | 19 | # overwrite to log the data | 17 | # overwrite to log the data |
712 | 20 | def status_change(self, pkg, percent, status): | 18 | def status_change(self, pkg, percent, status): |
714 | 21 | print pkg, percent | 19 | print(pkg, percent) |
715 | 22 | self.DATA.append([pkg, percent]) | 20 | self.DATA.append([pkg, percent]) |
716 | 23 | 21 | ||
717 | 22 | |||
718 | 24 | class TestMinimalPartitions(unittest.TestCase): | 23 | class TestMinimalPartitions(unittest.TestCase): |
719 | 25 | 24 | ||
720 | 26 | def setUp(self): | 25 | def setUp(self): |
721 | 27 | # setup dry-run mode for apt | 26 | # setup dry-run mode for apt |
722 | 28 | apt_pkg.config.set("Dir::Cache", "/tmp") | 27 | apt_pkg.config.set("Dir::Cache", "/tmp") |
725 | 29 | apt_pkg.config.set("Debug::NoLocking","1") | 28 | apt_pkg.config.set("Debug::NoLocking", "1") |
726 | 30 | apt_pkg.config.set("Debug::pkgDPkgPM","1") | 29 | apt_pkg.config.set("Debug::pkgDPkgPM", "1") |
727 | 31 | apt_pkg.config.set("Dir::State::extended_states", "./extended_states") | 30 | apt_pkg.config.set("Dir::State::extended_states", "./extended_states") |
728 | 32 | apt_pkg.config.clear("Dpkg::Post-Invoke") | 31 | apt_pkg.config.clear("Dpkg::Post-Invoke") |
729 | 33 | apt_pkg.config.clear("Dpkg::Pre-Install-Pkgs") | 32 | apt_pkg.config.clear("Dpkg::Pre-Install-Pkgs") |
730 | @@ -40,10 +39,11 @@ | |||
731 | 40 | def test_upgrade_in_minimal_steps(self): | 39 | def test_upgrade_in_minimal_steps(self): |
732 | 41 | self.cache.upgrade(True) | 40 | self.cache.upgrade(True) |
733 | 42 | pkgs_to_upgrade = [pkg.name for pkg in self.cache.get_changes()] | 41 | pkgs_to_upgrade = [pkg.name for pkg in self.cache.get_changes()] |
735 | 43 | unattended_upgrade.PROGRESS_LOG="./aptroot/var/run/unatteded-upgrades.progress" | 42 | unattended_upgrade.PROGRESS_LOG = \ |
736 | 43 | "./aptroot/var/run/unatteded-upgrades.progress" | ||
737 | 44 | unattended_upgrade.LogInstallProgress = LogInstallProgressMock | 44 | unattended_upgrade.LogInstallProgress = LogInstallProgressMock |
738 | 45 | unattended_upgrade.upgrade_in_minimal_steps( | 45 | unattended_upgrade.upgrade_in_minimal_steps( |
740 | 46 | self.cache, pkgs_to_upgrade) | 46 | self.cache, pkgs_to_upgrade, "", []) |
741 | 47 | # ensure we count upwarts | 47 | # ensure we count upwarts |
742 | 48 | last_percent = -1 | 48 | last_percent = -1 |
743 | 49 | for (pkg, percent) in LogInstallProgressMock.DATA: | 49 | for (pkg, percent) in LogInstallProgressMock.DATA: |
744 | 50 | 50 | ||
745 | === modified file 'test/test_origin_pattern.py' | |||
746 | --- test/test_origin_pattern.py 2012-08-14 11:55:21 +0000 | |||
747 | +++ test/test_origin_pattern.py 2012-10-08 16:08:26 +0000 | |||
748 | @@ -1,4 +1,4 @@ | |||
750 | 1 | #!/usr/bin/python | 1 | #!/usr/bin/python3 |
751 | 2 | 2 | ||
752 | 3 | import apt_pkg | 3 | import apt_pkg |
753 | 4 | import logging | 4 | import logging |
754 | @@ -12,49 +12,63 @@ | |||
755 | 12 | UnknownMatcherError, | 12 | UnknownMatcherError, |
756 | 13 | ) | 13 | ) |
757 | 14 | 14 | ||
758 | 15 | |||
759 | 15 | class MockOrigin(): | 16 | class MockOrigin(): |
760 | 16 | pass | 17 | pass |
761 | 18 | |||
762 | 19 | |||
763 | 17 | class MockCandidate(): | 20 | class MockCandidate(): |
764 | 18 | pass | 21 | pass |
765 | 22 | |||
766 | 23 | |||
767 | 19 | class MockPackage(): | 24 | class MockPackage(): |
768 | 20 | pass | 25 | pass |
769 | 26 | |||
770 | 27 | |||
771 | 21 | class MockCache(list): | 28 | class MockCache(list): |
772 | 22 | pass | 29 | pass |
773 | 30 | |||
774 | 31 | |||
775 | 23 | class MockDepCache(): | 32 | class MockDepCache(): |
776 | 24 | pass | 33 | pass |
777 | 25 | 34 | ||
778 | 35 | |||
779 | 26 | class TestOriginPatern(unittest.TestCase): | 36 | class TestOriginPatern(unittest.TestCase): |
780 | 27 | 37 | ||
781 | 28 | def setUp(self): | 38 | def setUp(self): |
782 | 29 | pass | 39 | pass |
783 | 40 | |||
784 | 30 | def tearDown(self): | 41 | def tearDown(self): |
785 | 31 | pass | 42 | pass |
786 | 43 | |||
787 | 32 | def test_match_whitelist_string(self): | 44 | def test_match_whitelist_string(self): |
788 | 33 | origin = self._get_mock_origin( | 45 | origin = self._get_mock_origin( |
789 | 34 | "OriginUbuntu", "LabelUbuntu", "ArchiveUbuntu", | 46 | "OriginUbuntu", "LabelUbuntu", "ArchiveUbuntu", |
790 | 35 | "archive.ubuntu.com", "main") | 47 | "archive.ubuntu.com", "main") |
791 | 36 | # good | 48 | # good |
793 | 37 | s="o=OriginUbuntu" | 49 | s = "o=OriginUbuntu" |
794 | 38 | self.assertTrue(match_whitelist_string(s, origin)) | 50 | self.assertTrue(match_whitelist_string(s, origin)) |
796 | 39 | s="o=OriginUbuntu,l=LabelUbuntu,a=ArchiveUbuntu,site=archive.ubuntu.com" | 51 | s = "o=OriginUbuntu,l=LabelUbuntu,a=ArchiveUbuntu," \ |
797 | 52 | "site=archive.ubuntu.com" | ||
798 | 40 | self.assertTrue(match_whitelist_string(s, origin)) | 53 | self.assertTrue(match_whitelist_string(s, origin)) |
799 | 41 | # bad | 54 | # bad |
805 | 42 | s="" | 55 | s = "" |
806 | 43 | self.assertFalse(match_whitelist_string(s, origin)) | 56 | self.assertFalse(match_whitelist_string(s, origin)) |
807 | 44 | s="o=something" | 57 | s = "o=something" |
808 | 45 | self.assertFalse(match_whitelist_string(s, origin)) | 58 | self.assertFalse(match_whitelist_string(s, origin)) |
809 | 46 | s="o=LabelUbuntu,a=no-match" | 59 | s = "o=LabelUbuntu,a=no-match" |
810 | 47 | self.assertFalse(match_whitelist_string(s, origin)) | 60 | self.assertFalse(match_whitelist_string(s, origin)) |
811 | 48 | # with escaping | 61 | # with escaping |
812 | 49 | origin = self._get_mock_origin("Google, Inc.", archive="stable") | 62 | origin = self._get_mock_origin("Google, Inc.", archive="stable") |
813 | 50 | # good | 63 | # good |
815 | 51 | s="o=Google\, Inc.,a=stable" | 64 | s = "o=Google\, Inc.,a=stable" |
816 | 52 | self.assertTrue(match_whitelist_string(s, origin)) | 65 | self.assertTrue(match_whitelist_string(s, origin)) |
817 | 53 | 66 | ||
818 | 54 | def test_match_whitelist_from_conffile(self): | 67 | def test_match_whitelist_from_conffile(self): |
819 | 55 | # read some | 68 | # read some |
820 | 56 | apt_pkg.config.clear("Unattended-Upgrade") | 69 | apt_pkg.config.clear("Unattended-Upgrade") |
822 | 57 | apt_pkg.read_config_file(apt_pkg.config, "./data/50unattended-upgrades.Test") | 70 | apt_pkg.read_config_file( |
823 | 71 | apt_pkg.config, "./data/50unattended-upgrades.Test") | ||
824 | 58 | allowed_origins = unattended_upgrade.get_allowed_origins() | 72 | allowed_origins = unattended_upgrade.get_allowed_origins() |
825 | 59 | #print allowed_origins | 73 | #print allowed_origins |
826 | 60 | self.assertTrue("o=aOrigin,a=aArchive" in allowed_origins) | 74 | self.assertTrue("o=aOrigin,a=aArchive" in allowed_origins) |
827 | @@ -63,7 +77,8 @@ | |||
828 | 63 | 77 | ||
829 | 64 | def test_compatiblity(self): | 78 | def test_compatiblity(self): |
830 | 65 | apt_pkg.config.clear("Unattended-Upgrade") | 79 | apt_pkg.config.clear("Unattended-Upgrade") |
832 | 66 | apt_pkg.read_config_file(apt_pkg.config, "./data/50unattended-upgrades.compat") | 80 | apt_pkg.read_config_file( |
833 | 81 | apt_pkg.config, "./data/50unattended-upgrades.compat") | ||
834 | 67 | allowed_origins = unattended_upgrade.get_allowed_origins() | 82 | allowed_origins = unattended_upgrade.get_allowed_origins() |
835 | 68 | #print allowed_origins | 83 | #print allowed_origins |
836 | 69 | self.assertTrue("o=Google\, Inc.,a=stable" in allowed_origins) | 84 | self.assertTrue("o=Google\, Inc.,a=stable" in allowed_origins) |
837 | @@ -74,7 +89,7 @@ | |||
838 | 74 | 89 | ||
839 | 75 | def test_unkown_matcher(self): | 90 | def test_unkown_matcher(self): |
840 | 76 | apt_pkg.config.clear("Unattended-Upgrade") | 91 | apt_pkg.config.clear("Unattended-Upgrade") |
842 | 77 | s="xxx=OriginUbuntu" | 92 | s = "xxx=OriginUbuntu" |
843 | 78 | with self.assertRaises(UnknownMatcherError): | 93 | with self.assertRaises(UnknownMatcherError): |
844 | 79 | self.assertTrue(match_whitelist_string(s, None)) | 94 | self.assertTrue(match_whitelist_string(s, None)) |
845 | 80 | 95 | ||
846 | @@ -90,10 +105,12 @@ | |||
847 | 90 | allowed_origins = ["o=Ubuntu"] | 105 | allowed_origins = ["o=Ubuntu"] |
848 | 91 | blacklist = ["linux-.*"] | 106 | blacklist = ["linux-.*"] |
849 | 92 | # with blacklist pkg | 107 | # with blacklist pkg |
851 | 93 | self.assertFalse(check_changes_for_sanity(cache, allowed_origins, blacklist)) | 108 | self.assertFalse( |
852 | 109 | check_changes_for_sanity(cache, allowed_origins, blacklist)) | ||
853 | 94 | # with "normal" pkg | 110 | # with "normal" pkg |
854 | 95 | pkg.name = "apt" | 111 | pkg.name = "apt" |
856 | 96 | self.assertTrue(check_changes_for_sanity(cache, allowed_origins, blacklist)) | 112 | self.assertTrue( |
857 | 113 | check_changes_for_sanity(cache, allowed_origins, blacklist)) | ||
858 | 97 | 114 | ||
859 | 98 | def _get_mock_origin(self, aorigin="", label="", archive="", | 115 | def _get_mock_origin(self, aorigin="", label="", archive="", |
860 | 99 | site="", component=""): | 116 | site="", component=""): |
861 | @@ -125,4 +142,3 @@ | |||
862 | 125 | if __name__ == "__main__": | 142 | if __name__ == "__main__": |
863 | 126 | logging.basicConfig(level=logging.DEBUG) | 143 | logging.basicConfig(level=logging.DEBUG) |
864 | 127 | unittest.main() | 144 | unittest.main() |
865 | 128 | |||
866 | 129 | 145 | ||
867 | === added file 'test/test_pep8.py' | |||
868 | --- test/test_pep8.py 1970-01-01 00:00:00 +0000 | |||
869 | +++ test/test_pep8.py 2012-10-08 16:08:26 +0000 | |||
870 | @@ -0,0 +1,17 @@ | |||
871 | 1 | import glob | ||
872 | 2 | import os | ||
873 | 3 | import subprocess | ||
874 | 4 | import unittest | ||
875 | 5 | |||
876 | 6 | |||
877 | 7 | class PackagePep8TestCase(unittest.TestCase): | ||
878 | 8 | |||
879 | 9 | def test_all_code(self): | ||
880 | 10 | res = 0 | ||
881 | 11 | py_files = glob.glob(os.path.join(os.path.dirname(__file__), "*.py")) | ||
882 | 12 | res += subprocess.call(["pep8", "--repeat", ] + py_files) | ||
883 | 13 | self.assertEqual(res, 0) | ||
884 | 14 | |||
885 | 15 | |||
886 | 16 | if __name__ == "__main__": | ||
887 | 17 | unittest.main() | ||
888 | 0 | 18 | ||
889 | === modified file 'test/test_pyflakes.py' (properties changed: -x to +x) | |||
890 | --- test/test_pyflakes.py 2012-07-13 16:40:10 +0000 | |||
891 | +++ test/test_pyflakes.py 2012-10-08 16:08:26 +0000 | |||
892 | @@ -2,12 +2,14 @@ | |||
893 | 2 | import subprocess | 2 | import subprocess |
894 | 3 | import unittest | 3 | import unittest |
895 | 4 | 4 | ||
896 | 5 | |||
897 | 5 | class TestPyflakesClean(unittest.TestCase): | 6 | class TestPyflakesClean(unittest.TestCase): |
898 | 6 | """ ensure that the tree is pyflakes clean """ | 7 | """ ensure that the tree is pyflakes clean """ |
899 | 7 | 8 | ||
900 | 8 | def test_pyflakes_clean(self): | 9 | def test_pyflakes_clean(self): |
903 | 9 | target = os.path.join(os.path.dirname(__file__), "..", "unattended-upgrade") | 10 | path = os.path.join( |
904 | 10 | self.assertEqual(subprocess.call(["pyflakes", target]), 0) | 11 | os.path.dirname(__file__), "unattended_upgrade.py") |
905 | 12 | self.assertEqual(subprocess.call(["pyflakes", path]), 0) | ||
906 | 11 | 13 | ||
907 | 12 | 14 | ||
908 | 13 | if __name__ == "__main__": | 15 | if __name__ == "__main__": |
909 | 14 | 16 | ||
910 | === modified file 'test/test_substitute.py' | |||
911 | --- test/test_substitute.py 2011-02-04 11:05:12 +0000 | |||
912 | +++ test/test_substitute.py 2012-10-08 16:08:26 +0000 | |||
913 | @@ -1,17 +1,13 @@ | |||
915 | 1 | #!/usr/bin/python | 1 | #!/usr/bin/python3 |
916 | 2 | 2 | ||
917 | 3 | import apt | ||
918 | 4 | import apt_pkg | 3 | import apt_pkg |
919 | 5 | import os | ||
920 | 6 | import logging | 4 | import logging |
921 | 7 | import unittest | 5 | import unittest |
922 | 8 | import sys | ||
923 | 9 | |||
924 | 10 | from StringIO import StringIO | ||
925 | 11 | 6 | ||
926 | 12 | import unattended_upgrade | 7 | import unattended_upgrade |
927 | 13 | from unattended_upgrade import substitute, get_allowed_origins | 8 | from unattended_upgrade import substitute, get_allowed_origins |
928 | 14 | 9 | ||
929 | 10 | |||
930 | 15 | class TestSubstitude(unittest.TestCase): | 11 | class TestSubstitude(unittest.TestCase): |
931 | 16 | 12 | ||
932 | 17 | def setUp(self): | 13 | def setUp(self): |
933 | @@ -36,4 +32,3 @@ | |||
934 | 36 | if __name__ == "__main__": | 32 | if __name__ == "__main__": |
935 | 37 | logging.basicConfig(level=logging.DEBUG) | 33 | logging.basicConfig(level=logging.DEBUG) |
936 | 38 | unittest.main() | 34 | unittest.main() |
937 | 39 | |||
938 | 40 | 35 | ||
939 | === modified file 'unattended-upgrade' | |||
940 | --- unattended-upgrade 2012-08-14 11:55:21 +0000 | |||
941 | +++ unattended-upgrade 2012-10-08 16:08:26 +0000 | |||
942 | @@ -1,4 +1,4 @@ | |||
944 | 1 | #!/usr/bin/python | 1 | #!/usr/bin/python3 |
945 | 2 | # Copyright (c) 2005-2012 Canonical Ltd | 2 | # Copyright (c) 2005-2012 Canonical Ltd |
946 | 3 | # | 3 | # |
947 | 4 | # AUTHOR: | 4 | # AUTHOR: |
948 | @@ -20,26 +20,27 @@ | |||
949 | 20 | # along with unattended-upgrades; if not, write to the Free Software | 20 | # along with unattended-upgrades; if not, write to the Free Software |
950 | 21 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 21 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
951 | 22 | # | 22 | # |
952 | 23 | |||
953 | 24 | import apt_inst | 23 | import apt_inst |
954 | 25 | import apt_pkg | 24 | import apt_pkg |
955 | 26 | 25 | ||
956 | 27 | import copy | 26 | import copy |
957 | 28 | import datetime | 27 | import datetime |
959 | 29 | import email.Charset | 28 | import email.charset |
960 | 30 | import fcntl | 29 | import fcntl |
961 | 31 | import re | 30 | import re |
962 | 32 | import os | 31 | import os |
963 | 33 | import string | 32 | import string |
964 | 34 | import sys | 33 | import sys |
965 | 35 | 34 | ||
967 | 36 | from email.Message import Message | 35 | from io import StringIO |
968 | 36 | from email.message import Message | ||
969 | 37 | from optparse import OptionParser | 37 | from optparse import OptionParser |
975 | 38 | from StringIO import StringIO | 38 | |
976 | 39 | from subprocess import Popen, PIPE | 39 | from subprocess import ( |
977 | 40 | 40 | Popen, | |
978 | 41 | import warnings | 41 | PIPE, |
979 | 42 | warnings.filterwarnings("ignore", "apt API not stable yet", FutureWarning) | 42 | ) |
980 | 43 | |||
981 | 43 | import apt | 44 | import apt |
982 | 44 | import logging | 45 | import logging |
983 | 45 | import lsb_release | 46 | import lsb_release |
984 | @@ -57,29 +58,32 @@ | |||
985 | 57 | DISTRO_ID = lsb_release.get_distro_information()['ID'] | 58 | DISTRO_ID = lsb_release.get_distro_information()['ID'] |
986 | 58 | 59 | ||
987 | 59 | # progress information is written here | 60 | # progress information is written here |
989 | 60 | PROGRESS_LOG="/var/run/unattended-upgrades.progress" | 61 | PROGRESS_LOG = "/var/run/unattended-upgrades.progress" |
990 | 61 | 62 | ||
991 | 62 | # set from the sigint signal handler | 63 | # set from the sigint signal handler |
993 | 63 | SIGNAL_STOP_REQUEST=False | 64 | SIGNAL_STOP_REQUEST = False |
994 | 65 | |||
995 | 64 | 66 | ||
996 | 65 | class UnknownMatcherError(ValueError): | 67 | class UnknownMatcherError(ValueError): |
997 | 66 | pass | 68 | pass |
998 | 67 | 69 | ||
999 | 68 | 70 | ||
1000 | 69 | class UnattendedUpgradesCache(apt.Cache): | 71 | class UnattendedUpgradesCache(apt.Cache): |
1002 | 70 | 72 | ||
1003 | 71 | def __init__(self, rootdir, allowed_origins): | 73 | def __init__(self, rootdir, allowed_origins): |
1004 | 72 | apt.Cache.__init__(self, rootdir=rootdir) | 74 | apt.Cache.__init__(self, rootdir=rootdir) |
1005 | 73 | self.allowed_origins = allowed_origins | 75 | self.allowed_origins = allowed_origins |
1007 | 74 | # ensure we update the candidate versions | 76 | # ensure we update the candidate versions |
1008 | 75 | self.adjust_candidate_versions() | 77 | self.adjust_candidate_versions() |
1009 | 78 | |||
1010 | 76 | def clear(self): | 79 | def clear(self): |
1011 | 77 | apt.Cache.clear(self) | 80 | apt.Cache.clear(self) |
1013 | 78 | # ensure we update the candidate versions | 81 | # ensure we update the candidate versions |
1014 | 79 | self.adjust_candidate_versions() | 82 | self.adjust_candidate_versions() |
1015 | 83 | |||
1016 | 80 | def adjust_candidate_versions(self): | 84 | def adjust_candidate_versions(self): |
1017 | 81 | """ Adjust candidate versions to match highest allowed origin | 85 | """ Adjust candidate versions to match highest allowed origin |
1019 | 82 | 86 | ||
1020 | 83 | This adjusts the origin even if the candidate has a higher | 87 | This adjusts the origin even if the candidate has a higher |
1021 | 84 | version | 88 | version |
1022 | 85 | """ | 89 | """ |
1023 | @@ -114,20 +118,19 @@ | |||
1024 | 114 | (/var/run/unattended-upgrades.progress by default) | 118 | (/var/run/unattended-upgrades.progress by default) |
1025 | 115 | """ | 119 | """ |
1026 | 116 | 120 | ||
1028 | 117 | LOG = PROGRESS_LOG | 121 | LOG = PROGRESS_LOG |
1029 | 118 | 122 | ||
1030 | 119 | def status_change(self, pkg, percent, status): | 123 | def status_change(self, pkg, percent, status): |
1034 | 120 | f=open(self.LOG, "w") | 124 | with open(self.LOG, "w") as f: |
1035 | 121 | f.write(_("Progress: %s %% (%s)") % (percent, pkg)) | 125 | f.write(_("Progress: %s %% (%s)") % (percent, pkg)) |
1033 | 122 | f.close() | ||
1036 | 123 | 126 | ||
1037 | 124 | def _fixup_fds(self): | 127 | def _fixup_fds(self): |
1044 | 125 | required_fds = [ 0, 1, 2, # stdin, stdout, stderr | 128 | required_fds = [0, 1, 2, # stdin, stdout, stderr |
1045 | 126 | self.writefd, | 129 | self.writefd, |
1046 | 127 | self.write_stream.fileno(), | 130 | self.write_stream.fileno(), |
1047 | 128 | self.statusfd, | 131 | self.statusfd, |
1048 | 129 | self.status_stream.fileno() | 132 | self.status_stream.fileno() |
1049 | 130 | ] | 133 | ] |
1050 | 131 | # ensure that our required fds close on exec | 134 | # ensure that our required fds close on exec |
1051 | 132 | for fd in required_fds[3:]: | 135 | for fd in required_fds[3:]: |
1052 | 133 | old_flags = fcntl.fcntl(fd, fcntl.F_GETFD) | 136 | old_flags = fcntl.fcntl(fd, fcntl.F_GETFD) |
1053 | @@ -140,19 +143,19 @@ | |||
1054 | 140 | try: | 143 | try: |
1055 | 141 | fd = int(fdname) | 144 | fd = int(fdname) |
1056 | 142 | except Exception as e: | 145 | except Exception as e: |
1058 | 143 | print "ERROR: can not get fd for '%s'" % fdname | 146 | print("ERROR: can not get fd for '%s'" % fdname) |
1059 | 144 | if fd in required_fds: | 147 | if fd in required_fds: |
1060 | 145 | continue | 148 | continue |
1061 | 146 | try: | 149 | try: |
1062 | 147 | os.close(fd) | 150 | os.close(fd) |
1064 | 148 | #print "closed: ", fd | 151 | #print("closed: ", fd) |
1065 | 149 | except OSError as e: | 152 | except OSError as e: |
1066 | 150 | # there will be one fd that can not be closed | 153 | # there will be one fd that can not be closed |
1067 | 151 | # as its the fd from pythons internal diropen() | 154 | # as its the fd from pythons internal diropen() |
1068 | 152 | # so its ok to ignore one close error | 155 | # so its ok to ignore one close error |
1069 | 153 | error_count += 1 | 156 | error_count += 1 |
1070 | 154 | if error_count > 1: | 157 | if error_count > 1: |
1072 | 155 | print "ERROR: os.close(%s): %s" % (fd, e) | 158 | print("ERROR: os.close(%s): %s" % (fd, e)) |
1073 | 156 | 159 | ||
1074 | 157 | def fork(self): | 160 | def fork(self): |
1075 | 158 | pid = os.fork() | 161 | pid = os.fork() |
1076 | @@ -162,53 +165,62 @@ | |||
1077 | 162 | 165 | ||
1078 | 163 | 166 | ||
1079 | 164 | class Unlocked: | 167 | class Unlocked: |
1083 | 165 | """ context manager for unlocking the apt lock while cache.commit() | 168 | """ |
1084 | 166 | is run | 169 | Context manager for unlocking the apt lock while cache.commit() is run |
1085 | 167 | """ | 170 | """ |
1086 | 171 | |||
1087 | 168 | def __enter__(self): | 172 | def __enter__(self): |
1088 | 169 | try: | 173 | try: |
1089 | 170 | apt_pkg.pkgsystem_unlock() | 174 | apt_pkg.pkgsystem_unlock() |
1090 | 171 | except: | 175 | except: |
1091 | 172 | pass | 176 | pass |
1092 | 177 | |||
1093 | 173 | def __exit__(self, exc_type, exc_value, exc_tb): | 178 | def __exit__(self, exc_type, exc_value, exc_tb): |
1094 | 174 | try: | 179 | try: |
1095 | 175 | apt_pkg.pkgsystem_unlock() | 180 | apt_pkg.pkgsystem_unlock() |
1096 | 176 | except: | 181 | except: |
1097 | 177 | pass | 182 | pass |
1098 | 178 | 183 | ||
1099 | 184 | |||
1100 | 179 | def is_dpkg_journal_dirty(): | 185 | def is_dpkg_journal_dirty(): |
1101 | 180 | """ | 186 | """ |
1103 | 181 | test if the dpkg journal is dirty | 187 | Return True if the dpkg journal is dirty |
1104 | 182 | (similar to debSystem::CheckUpdates) | 188 | (similar to debSystem::CheckUpdates) |
1105 | 183 | """ | 189 | """ |
1108 | 184 | d = os.path.dirname( | 190 | d = os.path.join( |
1109 | 185 | apt_pkg.config.find_file("Dir::State::status"))+"/updates" | 191 | os.path.dirname(apt_pkg.config.find_file("Dir::State::status")), |
1110 | 192 | "updates") | ||
1111 | 186 | for f in os.listdir(d): | 193 | for f in os.listdir(d): |
1112 | 187 | if re.match("[0-9]+", f): | 194 | if re.match("[0-9]+", f): |
1113 | 188 | return True | 195 | return True |
1114 | 189 | return False | 196 | return False |
1115 | 190 | 197 | ||
1116 | 198 | |||
1117 | 191 | def signal_handler(signal, frame): | 199 | def signal_handler(signal, frame): |
1118 | 192 | logging.warn("SIGUSR1 recieved, will stop") | 200 | logging.warn("SIGUSR1 recieved, will stop") |
1119 | 193 | global SIGNAL_STOP_REQUEST | 201 | global SIGNAL_STOP_REQUEST |
1121 | 194 | SIGNAL_STOP_REQUEST=True | 202 | SIGNAL_STOP_REQUEST = True |
1122 | 203 | |||
1123 | 195 | 204 | ||
1124 | 196 | def substitute(line): | 205 | def substitute(line): |
1126 | 197 | """ substitude known mappings and return a new string | 206 | """ substitude known mappings and return a new string |
1127 | 198 | 207 | ||
1128 | 199 | Currently supported ${distro-release} | 208 | Currently supported ${distro-release} |
1129 | 200 | """ | 209 | """ |
1132 | 201 | mapping = {"distro_codename" : get_distro_codename(), | 210 | mapping = {"distro_codename": get_distro_codename(), |
1133 | 202 | "distro_id" : get_distro_id(), | 211 | "distro_id": get_distro_id(), |
1134 | 203 | } | 212 | } |
1135 | 204 | return string.Template(line).substitute(mapping) | 213 | return string.Template(line).substitute(mapping) |
1137 | 205 | 214 | ||
1138 | 215 | |||
1139 | 206 | def get_distro_codename(): | 216 | def get_distro_codename(): |
1140 | 207 | return DISTRO_CODENAME | 217 | return DISTRO_CODENAME |
1141 | 208 | 218 | ||
1142 | 219 | |||
1143 | 209 | def get_distro_id(): | 220 | def get_distro_id(): |
1144 | 210 | return DISTRO_ID | 221 | return DISTRO_ID |
1145 | 211 | 222 | ||
1146 | 223 | |||
1147 | 212 | def get_allowed_origins_legacy(): | 224 | def get_allowed_origins_legacy(): |
1148 | 213 | """ legacy support for old Allowed-Origins var """ | 225 | """ legacy support for old Allowed-Origins var """ |
1149 | 214 | allowed_origins = [] | 226 | allowed_origins = [] |
1150 | @@ -222,10 +234,11 @@ | |||
1151 | 222 | distro_id = re.sub(r'([^\\]),', r'\1\\,', distro_id) | 234 | distro_id = re.sub(r'([^\\]),', r'\1\\,', distro_id) |
1152 | 223 | distro_codename = re.sub(r'([^\\]),', r'\1\\,', distro_codename) | 235 | distro_codename = re.sub(r'([^\\]),', r'\1\\,', distro_codename) |
1153 | 224 | # convert to new format | 236 | # convert to new format |
1155 | 225 | allowed_origins.append("o=%s,a=%s" % (substitute(distro_id), | 237 | allowed_origins.append("o=%s,a=%s" % (substitute(distro_id), |
1156 | 226 | substitute(distro_codename))) | 238 | substitute(distro_codename))) |
1157 | 227 | return allowed_origins | 239 | return allowed_origins |
1158 | 228 | 240 | ||
1159 | 241 | |||
1160 | 229 | def get_allowed_origins(): | 242 | def get_allowed_origins(): |
1161 | 230 | """ return a list of allowed origins from apt.conf | 243 | """ return a list of allowed origins from apt.conf |
1162 | 231 | 244 | ||
1163 | @@ -236,6 +249,7 @@ | |||
1164 | 236 | allowed_origins.append(substitute(s)) | 249 | allowed_origins.append(substitute(s)) |
1165 | 237 | return allowed_origins | 250 | return allowed_origins |
1166 | 238 | 251 | ||
1167 | 252 | |||
1168 | 239 | def match_whitelist_string(whitelist, origin): | 253 | def match_whitelist_string(whitelist, origin): |
1169 | 240 | """ | 254 | """ |
1170 | 241 | take a whitelist string in the form "origin=Debian,label=Debian-Security" | 255 | take a whitelist string in the form "origin=Debian,label=Debian-Security" |
1171 | @@ -251,9 +265,10 @@ | |||
1172 | 251 | whitelist = whitelist.replace("\,", "%2C") | 265 | whitelist = whitelist.replace("\,", "%2C") |
1173 | 252 | for token in whitelist.split(","): | 266 | for token in whitelist.split(","): |
1174 | 253 | # strip and unquote the "," back | 267 | # strip and unquote the "," back |
1176 | 254 | (what, value) = [s.strip().replace("%2C",",") | 268 | (what, value) = [s.strip().replace("%2C", ",") |
1177 | 255 | for s in token.split("=")] | 269 | for s in token.split("=")] |
1179 | 256 | #logging.debug("matching '%s'='%s' against '%s'" % (what, value, origin)) | 270 | #logging.debug("matching '%s'='%s' against '%s'" % ( |
1180 | 271 | # what, value, origin)) | ||
1181 | 257 | # first char is apt-cache policy output, send is the name | 272 | # first char is apt-cache policy output, send is the name |
1182 | 258 | # in the Release file | 273 | # in the Release file |
1183 | 259 | if what in ("o", "origin"): | 274 | if what in ("o", "origin"): |
1184 | @@ -272,6 +287,7 @@ | |||
1185 | 272 | what, token)) | 287 | what, token)) |
1186 | 273 | return res | 288 | return res |
1187 | 274 | 289 | ||
1188 | 290 | |||
1189 | 275 | def upgrade_normal(cache, pkgs_to_upgrade, logfile_dpkg): | 291 | def upgrade_normal(cache, pkgs_to_upgrade, logfile_dpkg): |
1190 | 276 | error = None | 292 | error = None |
1191 | 277 | res = False | 293 | res = False |
1192 | @@ -279,18 +295,19 @@ | |||
1193 | 279 | try: | 295 | try: |
1194 | 280 | with Unlocked(): | 296 | with Unlocked(): |
1195 | 281 | res = cache.commit(install_progress=iprogress) | 297 | res = cache.commit(install_progress=iprogress) |
1197 | 282 | except SystemError,e: | 298 | except SystemError as e: |
1198 | 283 | error = e | 299 | error = e |
1199 | 284 | if res: | 300 | if res: |
1200 | 285 | logging.info(_("All upgrades installed")) | 301 | logging.info(_("All upgrades installed")) |
1201 | 286 | else: | 302 | else: |
1202 | 287 | logging.error(_("Installing the upgrades failed!")) | 303 | logging.error(_("Installing the upgrades failed!")) |
1203 | 288 | logging.error(_("error message: '%s'") % error) | 304 | logging.error(_("error message: '%s'") % error) |
1205 | 289 | logging.error(_("dpkg returned a error! See '%s' for details") % \ | 305 | logging.error(_("dpkg returned a error! See '%s' for details") % |
1206 | 290 | logfile_dpkg) | 306 | logfile_dpkg) |
1207 | 291 | return res | 307 | return res |
1208 | 292 | 308 | ||
1210 | 293 | def upgrade_in_minimal_steps(cache, pkgs_to_upgrade, logfile_dpkg=""): | 309 | |
1211 | 310 | def upgrade_in_minimal_steps(cache, pkgs_to_upgrade, logfile_dpkg, blacklist): | ||
1212 | 294 | 311 | ||
1213 | 295 | install_log = LogInstallProgress() | 312 | install_log = LogInstallProgress() |
1214 | 296 | install_log.LOG += ".minimal-steps" | 313 | install_log.LOG += ".minimal-steps" |
1215 | @@ -298,6 +315,9 @@ | |||
1216 | 298 | # setup signal handler | 315 | # setup signal handler |
1217 | 299 | signal.signal(signal.SIGUSR1, signal_handler) | 316 | signal.signal(signal.SIGUSR1, signal_handler) |
1218 | 300 | 317 | ||
1219 | 318 | # double check any changes we do | ||
1220 | 319 | allowed_origins = get_allowed_origins() | ||
1221 | 320 | |||
1222 | 301 | # to upgrade contains the package names | 321 | # to upgrade contains the package names |
1223 | 302 | to_upgrade = set(pkgs_to_upgrade) | 322 | to_upgrade = set(pkgs_to_upgrade) |
1224 | 303 | while True: | 323 | while True: |
1225 | @@ -314,19 +334,28 @@ | |||
1226 | 314 | pkg.mark_install() | 334 | pkg.mark_install() |
1227 | 315 | else: | 335 | else: |
1228 | 316 | continue | 336 | continue |
1229 | 337 | # double check that we are not running into side effects like | ||
1230 | 338 | # what could have been caused LP: #1020680 | ||
1231 | 339 | if not check_changes_for_sanity(cache, allowed_origins, blacklist): | ||
1232 | 340 | logging.error( | ||
1233 | 341 | "Internal error while building a minimal partition." | ||
1234 | 342 | "Cache has not allowed changes") | ||
1235 | 343 | return False | ||
1236 | 317 | changes = [pkg.name for pkg in cache.get_changes()] | 344 | changes = [pkg.name for pkg in cache.get_changes()] |
1237 | 318 | if len(changes) == 1: | 345 | if len(changes) == 1: |
1238 | 319 | logging.debug("found leaf package %s" % pkg.name) | 346 | logging.debug("found leaf package %s" % pkg.name) |
1239 | 320 | smallest_partition = changes | 347 | smallest_partition = changes |
1240 | 321 | break | 348 | break |
1241 | 322 | if len(changes) < len(smallest_partition): | 349 | if len(changes) < len(smallest_partition): |
1243 | 323 | logging.debug("found partition of size %s (%s)" % (len(changes), changes)) | 350 | logging.debug("found partition of size %s (%s)" % ( |
1244 | 351 | len(changes), changes)) | ||
1245 | 324 | smallest_partition = changes | 352 | smallest_partition = changes |
1246 | 325 | cache.clear() | 353 | cache.clear() |
1247 | 326 | 354 | ||
1248 | 327 | # write progress log information | 355 | # write progress log information |
1249 | 328 | if len(pkgs_to_upgrade) > 0: | 356 | if len(pkgs_to_upgrade) > 0: |
1251 | 329 | percent = (len(pkgs_to_upgrade)-len(to_upgrade)) / float(len(pkgs_to_upgrade))*100.0 | 357 | percent = ((len(pkgs_to_upgrade) - len(to_upgrade)) / |
1252 | 358 | float(len(pkgs_to_upgrade)) * 100.0) | ||
1253 | 330 | else: | 359 | else: |
1254 | 331 | percent = 100.0 | 360 | percent = 100.0 |
1255 | 332 | install_log.status_change(pkg=",".join(smallest_partition), | 361 | install_log.status_change(pkg=",".join(smallest_partition), |
1256 | @@ -343,19 +372,20 @@ | |||
1257 | 343 | if not res: | 372 | if not res: |
1258 | 344 | raise Exception("cache.commit() returned false") | 373 | raise Exception("cache.commit() returned false") |
1259 | 345 | cache.open() | 374 | cache.open() |
1261 | 346 | except Exception, e: | 375 | except Exception as e: |
1262 | 347 | logging.error(_("Installing the upgrades failed!")) | 376 | logging.error(_("Installing the upgrades failed!")) |
1263 | 348 | logging.error(_("error message: '%s'") % e) | 377 | logging.error(_("error message: '%s'") % e) |
1265 | 349 | logging.error(_("dpkg returned a error! See '%s' for details") % \ | 378 | logging.error(_("dpkg returned a error! See '%s' for details") % |
1266 | 350 | logfile_dpkg) | 379 | logfile_dpkg) |
1267 | 351 | return False | 380 | return False |
1269 | 352 | to_upgrade = to_upgrade-set(smallest_partition) | 381 | to_upgrade = to_upgrade - set(smallest_partition) |
1270 | 353 | logging.debug("left to upgrade %s" % to_upgrade) | 382 | logging.debug("left to upgrade %s" % to_upgrade) |
1271 | 354 | if len(to_upgrade) == 0: | 383 | if len(to_upgrade) == 0: |
1272 | 355 | logging.info(_("All upgrades installed")) | 384 | logging.info(_("All upgrades installed")) |
1273 | 356 | break | 385 | break |
1274 | 357 | return True | 386 | return True |
1275 | 358 | 387 | ||
1276 | 388 | |||
1277 | 359 | def is_allowed_origin(ver, allowed_origins): | 389 | def is_allowed_origin(ver, allowed_origins): |
1278 | 360 | if not ver: | 390 | if not ver: |
1279 | 361 | return False | 391 | return False |
1280 | @@ -365,6 +395,7 @@ | |||
1281 | 365 | return True | 395 | return True |
1282 | 366 | return False | 396 | return False |
1283 | 367 | 397 | ||
1284 | 398 | |||
1285 | 368 | def is_pkgname_in_blacklist(pkgname, blacklist): | 399 | def is_pkgname_in_blacklist(pkgname, blacklist): |
1286 | 369 | for blacklist_regexp in blacklist: | 400 | for blacklist_regexp in blacklist: |
1287 | 370 | if re.match(blacklist_regexp, pkgname): | 401 | if re.match(blacklist_regexp, pkgname): |
1288 | @@ -372,6 +403,7 @@ | |||
1289 | 372 | return True | 403 | return True |
1290 | 373 | return False | 404 | return False |
1291 | 374 | 405 | ||
1292 | 406 | |||
1293 | 375 | def check_changes_for_sanity(cache, allowed_origins, blacklist): | 407 | def check_changes_for_sanity(cache, allowed_origins, blacklist): |
1294 | 376 | if cache._depcache.broken_count != 0: | 408 | if cache._depcache.broken_count != 0: |
1295 | 377 | return False | 409 | return False |
1296 | @@ -392,33 +424,39 @@ | |||
1297 | 392 | ignore_require_restart = apt_pkg.config.find_b( | 424 | ignore_require_restart = apt_pkg.config.find_b( |
1298 | 393 | "Unattended-Upgrade::IgnoreAppsRequireRestart", False) | 425 | "Unattended-Upgrade::IgnoreAppsRequireRestart", False) |
1299 | 394 | if (pkg.marked_upgrade and | 426 | if (pkg.marked_upgrade and |
1301 | 395 | ignore_require_restart == False and | 427 | ignore_require_restart is False and |
1302 | 396 | pkg.candidate.record.get("Upgrade-Requires") == "app-restart"): | 428 | pkg.candidate.record.get("Upgrade-Requires") == "app-restart"): |
1304 | 397 | logging.debug("pkg '%s' requires app-restart, not safe to upgrade unattended") | 429 | logging.debug("pkg '%s' requires app-restart, not safe to " |
1305 | 430 | "upgrade unattended") | ||
1306 | 398 | return False | 431 | return False |
1307 | 399 | return True | 432 | return True |
1308 | 400 | 433 | ||
1309 | 434 | |||
1310 | 401 | def pkgname_from_deb(debfile): | 435 | def pkgname_from_deb(debfile): |
1311 | 402 | # FIXME: add error checking here | 436 | # FIXME: add error checking here |
1312 | 403 | try: | 437 | try: |
1313 | 404 | control = apt_inst.DebFile(debfile).control.extractdata("control") | 438 | control = apt_inst.DebFile(debfile).control.extractdata("control") |
1314 | 405 | sections = apt_pkg.TagSection(control) | 439 | sections = apt_pkg.TagSection(control) |
1315 | 406 | return sections["Package"] | 440 | return sections["Package"] |
1317 | 407 | except (IOError, SystemError), e: | 441 | except (IOError, SystemError) as e: |
1318 | 408 | logging.error("failed to read deb file '%s' (%s)" % (debfile, e)) | 442 | logging.error("failed to read deb file '%s' (%s)" % (debfile, e)) |
1319 | 409 | # dumb fallback | 443 | # dumb fallback |
1320 | 410 | return debfile.split("_")[0] | 444 | return debfile.split("_")[0] |
1321 | 411 | 445 | ||
1322 | 446 | |||
1323 | 412 | def get_md5sum_for_file_in_deb(deb_file, conf_file): | 447 | def get_md5sum_for_file_in_deb(deb_file, conf_file): |
1326 | 413 | dpkg_cmd = ["dpkg-deb","--fsys-tarfile", deb_file] | 448 | dpkg_cmd = ["dpkg-deb", "--fsys-tarfile", deb_file] |
1327 | 414 | tar_cmd = ["tar","-x","-O", "-f","-", "."+conf_file] | 449 | tar_cmd = ["tar", "-x", "-O", "-f", "-", "." + conf_file] |
1328 | 415 | md5_cmd = ["md5sum"] | 450 | md5_cmd = ["md5sum"] |
1329 | 416 | dpkg_p = Popen(dpkg_cmd, stdout=PIPE) | 451 | dpkg_p = Popen(dpkg_cmd, stdout=PIPE) |
1332 | 417 | tar_p = Popen(tar_cmd, stdin=dpkg_p.stdout, stdout=PIPE) | 452 | tar_p = Popen(tar_cmd, stdin=dpkg_p.stdout, stdout=PIPE, |
1333 | 418 | md5_p = Popen(md5_cmd, stdin=tar_p.stdout, stdout=PIPE) | 453 | universal_newlines=True) |
1334 | 454 | md5_p = Popen(md5_cmd, stdin=tar_p.stdout, stdout=PIPE, | ||
1335 | 455 | universal_newlines=True) | ||
1336 | 419 | pkg_md5sum = md5_p.communicate()[0].split()[0] | 456 | pkg_md5sum = md5_p.communicate()[0].split()[0] |
1337 | 420 | return pkg_md5sum | 457 | return pkg_md5sum |
1338 | 421 | 458 | ||
1339 | 459 | |||
1340 | 422 | # prefix is *only* needed for the build-in tests | 460 | # prefix is *only* needed for the build-in tests |
1341 | 423 | def conffile_prompt(destFile, prefix=""): | 461 | def conffile_prompt(destFile, prefix=""): |
1342 | 424 | logging.debug("check_conffile_prompt('%s')" % destFile) | 462 | logging.debug("check_conffile_prompt('%s')" % destFile) |
1343 | @@ -426,7 +464,7 @@ | |||
1344 | 426 | 464 | ||
1345 | 427 | # get the conffiles for the /var/lib/dpkg/status file | 465 | # get the conffiles for the /var/lib/dpkg/status file |
1346 | 428 | status_file = apt_pkg.config.find("Dir::State::status") | 466 | status_file = apt_pkg.config.find("Dir::State::status") |
1348 | 429 | tagfile = apt_pkg.TagFile(open(status_file,"r")) | 467 | tagfile = apt_pkg.TagFile(open(status_file, "r")) |
1349 | 430 | conffiles = "" | 468 | conffiles = "" |
1350 | 431 | for section in tagfile: | 469 | for section in tagfile: |
1351 | 432 | if section.get("Package") == pkgname: | 470 | if section.get("Package") == pkgname: |
1352 | @@ -440,21 +478,22 @@ | |||
1353 | 440 | pkg_conffiles = "" | 478 | pkg_conffiles = "" |
1354 | 441 | deb = apt_inst.DebFile(destFile) | 479 | deb = apt_inst.DebFile(destFile) |
1355 | 442 | try: | 480 | try: |
1357 | 443 | pkg_conffiles = deb.control.extractdata("conffiles").strip() | 481 | pkg_conffiles = deb.control.extractdata("conffiles").strip().decode( |
1358 | 482 | "utf-8") | ||
1359 | 444 | except LookupError as e: | 483 | except LookupError as e: |
1360 | 445 | logging.debug("No conffiles in deb '%s' (%s)" % (destFile, e)) | 484 | logging.debug("No conffiles in deb '%s' (%s)" % (destFile, e)) |
1361 | 446 | 485 | ||
1362 | 447 | # Conffiles: | 486 | # Conffiles: |
1363 | 448 | # /etc/bash_completion.d/m-a c7780fab6b14d75ca54e11e992a6c11c | 487 | # /etc/bash_completion.d/m-a c7780fab6b14d75ca54e11e992a6c11c |
1364 | 449 | dpkg_status_conffiles = {} | 488 | dpkg_status_conffiles = {} |
1366 | 450 | for line in string.split(conffiles,"\n"): | 489 | for line in conffiles.splitlines(): |
1367 | 451 | # ignore empty lines | 490 | # ignore empty lines |
1369 | 452 | line = string.strip(line) | 491 | line = line.strip() |
1370 | 453 | if not line: | 492 | if not line: |
1371 | 454 | continue | 493 | continue |
1372 | 455 | # show what we do | 494 | # show what we do |
1373 | 456 | logging.debug("conffile line: '%s'", line) | 495 | logging.debug("conffile line: '%s'", line) |
1375 | 457 | l = string.split(line) | 496 | l = line.split() |
1376 | 458 | conf_file = l[0] | 497 | conf_file = l[0] |
1377 | 459 | md5 = l[1] | 498 | md5 = l[1] |
1378 | 460 | if len(l) > 2: | 499 | if len(l) > 2: |
1379 | @@ -462,13 +501,13 @@ | |||
1380 | 462 | else: | 501 | else: |
1381 | 463 | obs = None | 502 | obs = None |
1382 | 464 | # ignore if conffile is obsolete or does not exist | 503 | # ignore if conffile is obsolete or does not exist |
1384 | 465 | if obs == "obsolete" or not os.path.exists(prefix+conf_file): | 504 | if obs == "obsolete" or not os.path.exists(prefix + conf_file): |
1385 | 466 | continue | 505 | continue |
1386 | 467 | # ignore state "newconffile" until its clearer if there | 506 | # ignore state "newconffile" until its clearer if there |
1387 | 468 | # might be a dpkg prompt (LP: #936870) | 507 | # might be a dpkg prompt (LP: #936870) |
1388 | 469 | if md5 == "newconffile": | 508 | if md5 == "newconffile": |
1389 | 470 | continue | 509 | continue |
1391 | 471 | if (not pkg_conffiles or | 510 | if (not pkg_conffiles or |
1392 | 472 | not conf_file in pkg_conffiles.split("\n")): | 511 | not conf_file in pkg_conffiles.split("\n")): |
1393 | 473 | logging.debug("'%s' not in package conffiles '%s'" % ( | 512 | logging.debug("'%s' not in package conffiles '%s'" % ( |
1394 | 474 | conf_file, pkg_conffiles)) | 513 | conf_file, pkg_conffiles)) |
1395 | @@ -476,7 +515,8 @@ | |||
1396 | 476 | # record for later | 515 | # record for later |
1397 | 477 | dpkg_status_conffiles[conf_file] = md5 | 516 | dpkg_status_conffiles[conf_file] = md5 |
1398 | 478 | # test against the installed file | 517 | # test against the installed file |
1400 | 479 | current_md5 = apt_pkg.md5sum(open(prefix+conf_file).read()) | 518 | with open(prefix + conf_file, 'rb') as fb: |
1401 | 519 | current_md5 = apt_pkg.md5sum(fb) | ||
1402 | 480 | logging.debug("current md5: %s" % current_md5) | 520 | logging.debug("current md5: %s" % current_md5) |
1403 | 481 | # hashes are the same, no conffile prompt | 521 | # hashes are the same, no conffile prompt |
1404 | 482 | if current_md5 == md5: | 522 | if current_md5 == md5: |
1405 | @@ -484,7 +524,7 @@ | |||
1406 | 484 | # calculate md5sum from the deb (may take a bit) | 524 | # calculate md5sum from the deb (may take a bit) |
1407 | 485 | pkg_md5sum = get_md5sum_for_file_in_deb(destFile, conf_file) | 525 | pkg_md5sum = get_md5sum_for_file_in_deb(destFile, conf_file) |
1408 | 486 | logging.debug("pkg_md5sum: %s" % pkg_md5sum) | 526 | logging.debug("pkg_md5sum: %s" % pkg_md5sum) |
1410 | 487 | # the md5sum in the deb is unchanged, this will not | 527 | # the md5sum in the deb is unchanged, this will not |
1411 | 488 | # trigger a conffile prompt | 528 | # trigger a conffile prompt |
1412 | 489 | if pkg_md5sum == md5: | 529 | if pkg_md5sum == md5: |
1413 | 490 | continue | 530 | continue |
1414 | @@ -493,18 +533,19 @@ | |||
1415 | 493 | # and that will trigger a conffile prompt, we can | 533 | # and that will trigger a conffile prompt, we can |
1416 | 494 | # stop processing at this point and just return True | 534 | # stop processing at this point and just return True |
1417 | 495 | return True | 535 | return True |
1419 | 496 | 536 | ||
1420 | 497 | # now check if there are conffiles in the pkg that where not there | 537 | # now check if there are conffiles in the pkg that where not there |
1421 | 498 | # in the previous version in the dpkg status file | 538 | # in the previous version in the dpkg status file |
1422 | 499 | if pkg_conffiles: | 539 | if pkg_conffiles: |
1423 | 500 | for conf_file in pkg_conffiles.split("\n"): | 540 | for conf_file in pkg_conffiles.split("\n"): |
1424 | 501 | if (not conf_file in dpkg_status_conffiles and | 541 | if (not conf_file in dpkg_status_conffiles and |
1426 | 502 | os.path.exists(prefix+conf_file)): | 542 | os.path.exists(prefix + conf_file)): |
1427 | 503 | logging.debug("found conffile '%s' in new pkg but on dpkg " | 543 | logging.debug("found conffile '%s' in new pkg but on dpkg " |
1428 | 504 | "status" % conf_file) | 544 | "status" % conf_file) |
1429 | 505 | pkg_md5sum = get_md5sum_for_file_in_deb(destFile, conf_file) | 545 | pkg_md5sum = get_md5sum_for_file_in_deb(destFile, conf_file) |
1432 | 506 | if pkg_md5sum != apt_pkg.md5sum(open(prefix+conf_file).read()): | 546 | with open(prefix + conf_file, 'rb') as fp: |
1433 | 507 | return True | 547 | if pkg_md5sum != apt_pkg.md5sum(fp): |
1434 | 548 | return True | ||
1435 | 508 | return False | 549 | return False |
1436 | 509 | 550 | ||
1437 | 510 | 551 | ||
1438 | @@ -514,7 +555,7 @@ | |||
1439 | 514 | options = apt_pkg.config.value_list("DPkg::Options") | 555 | options = apt_pkg.config.value_list("DPkg::Options") |
1440 | 515 | for option in map(string.strip, options): | 556 | for option in map(string.strip, options): |
1441 | 516 | if (option == "--force-confold" or | 557 | if (option == "--force-confold" or |
1443 | 517 | option == "--force-confnew"): | 558 | option == "--force-confnew"): |
1444 | 518 | return False | 559 | return False |
1445 | 519 | return True | 560 | return True |
1446 | 520 | 561 | ||
1447 | @@ -535,7 +576,7 @@ | |||
1448 | 535 | def wrap(t, width=70, subsequent_indent=""): | 576 | def wrap(t, width=70, subsequent_indent=""): |
1449 | 536 | out = "" | 577 | out = "" |
1450 | 537 | for s in t.split(): | 578 | for s in t.split(): |
1452 | 538 | if (len(out)-out.rfind("\n")) + len(s) > width: | 579 | if (len(out) - out.rfind("\n")) + len(s) > width: |
1453 | 539 | out += "\n" + subsequent_indent | 580 | out += "\n" + subsequent_indent |
1454 | 540 | out += s + " " | 581 | out += s + " " |
1455 | 541 | return out | 582 | return out |
1456 | @@ -554,8 +595,9 @@ | |||
1457 | 554 | 595 | ||
1458 | 555 | 596 | ||
1459 | 556 | def _send_mail_using_mailx(to_address, subject, body): | 597 | def _send_mail_using_mailx(to_address, subject, body): |
1462 | 557 | mail = subprocess.Popen([ | 598 | mail = subprocess.Popen( |
1463 | 558 | MAIL_BINARY, "-s", subject, to_address], stdin=subprocess.PIPE) | 599 | [MAIL_BINARY, "-s", subject, to_address], |
1464 | 600 | stdin=subprocess.PIPE, universal_newlines=True) | ||
1465 | 559 | mail.stdin.write(body) | 601 | mail.stdin.write(body) |
1466 | 560 | mail.stdin.close() | 602 | mail.stdin.close() |
1467 | 561 | ret = mail.wait() | 603 | ret = mail.wait() |
1468 | @@ -565,14 +607,15 @@ | |||
1469 | 565 | def _send_mail_using_sendmail(to_address, subject, body): | 607 | def _send_mail_using_sendmail(to_address, subject, body): |
1470 | 566 | # format as a proper mail | 608 | # format as a proper mail |
1471 | 567 | msg = Message() | 609 | msg = Message() |
1474 | 568 | charset = email.Charset.Charset("utf-8") | 610 | charset = email.charset.Charset("utf-8") |
1475 | 569 | charset.body_encoding = email.Charset.QP | 611 | charset.body_encoding = email.charset.QP |
1476 | 570 | msg.set_charset(charset) | 612 | msg.set_charset(charset) |
1477 | 571 | msg.set_payload(body) | 613 | msg.set_payload(body) |
1478 | 572 | msg['Subject'] = subject | 614 | msg['Subject'] = subject |
1479 | 573 | msg['To'] = to_address | 615 | msg['To'] = to_address |
1480 | 574 | sendmail = subprocess.Popen( | 616 | sendmail = subprocess.Popen( |
1482 | 575 | [SENDMAIL_BINARY, "-oi", "-t"], stdin=subprocess.PIPE) | 617 | [SENDMAIL_BINARY, "-oi", "-t"], |
1483 | 618 | stdin=subprocess.PIPE, universal_newlines=True) | ||
1484 | 576 | sendmail.stdin.write(msg.as_string()) | 619 | sendmail.stdin.write(msg.as_string()) |
1485 | 577 | sendmail.stdin.close() | 620 | sendmail.stdin.close() |
1486 | 578 | ret = sendmail.wait() | 621 | ret = sendmail.wait() |
1487 | @@ -594,16 +637,18 @@ | |||
1488 | 594 | # mails on on errors, just exit here | 637 | # mails on on errors, just exit here |
1489 | 595 | if (res and | 638 | if (res and |
1490 | 596 | apt_pkg.config.find_b("Unattended-Upgrade::MailOnlyOnError", False)): | 639 | apt_pkg.config.find_b("Unattended-Upgrade::MailOnlyOnError", False)): |
1492 | 597 | return | 640 | return |
1493 | 598 | # Check if reboot-required flag is present | 641 | # Check if reboot-required flag is present |
1494 | 599 | logging.debug("Sending mail with '%s' to '%s'" % (logfile_dpkg, to_email)) | 642 | logging.debug("Sending mail with '%s' to '%s'" % (logfile_dpkg, to_email)) |
1495 | 600 | if os.path.isfile(REBOOT_REQUIRED_FILE): | 643 | if os.path.isfile(REBOOT_REQUIRED_FILE): |
1497 | 601 | subject = _("[reboot required] unattended-upgrades result for '%s'") % host() | 644 | subject = _( |
1498 | 645 | "[reboot required] unattended-upgrades result for '%s'") % host() | ||
1499 | 602 | else: | 646 | else: |
1500 | 603 | subject = _("unattended-upgrades result for '%s'") % host() | 647 | subject = _("unattended-upgrades result for '%s'") % host() |
1501 | 604 | body = _("Unattended upgrade returned: %s\n\n") % res | 648 | body = _("Unattended upgrade returned: %s\n\n") % res |
1502 | 605 | if os.path.isfile(REBOOT_REQUIRED_FILE): | 649 | if os.path.isfile(REBOOT_REQUIRED_FILE): |
1504 | 606 | body += _("Warning: A reboot is required to complete this upgrade.\n\n") | 650 | body += _( |
1505 | 651 | "Warning: A reboot is required to complete this upgrade.\n\n") | ||
1506 | 607 | body += _("Packages that are upgraded:\n") | 652 | body += _("Packages that are upgraded:\n") |
1507 | 608 | body += " " + wrap(pkgs, 70, " ") | 653 | body += " " + wrap(pkgs, 70, " ") |
1508 | 609 | body += "\n" | 654 | body += "\n" |
1509 | @@ -613,15 +658,16 @@ | |||
1510 | 613 | body += "\n" | 658 | body += "\n" |
1511 | 614 | body += "\n" | 659 | body += "\n" |
1512 | 615 | if os.path.exists(logfile_dpkg): | 660 | if os.path.exists(logfile_dpkg): |
1515 | 616 | body += _("Package installation log:")+"\n" | 661 | body += _("Package installation log:") + "\n" |
1516 | 617 | body += open(logfile_dpkg).read() | 662 | with open(logfile_dpkg) as fp: |
1517 | 663 | body += fp.read() | ||
1518 | 618 | body += "\n\n" | 664 | body += "\n\n" |
1519 | 619 | body += _("Unattended-upgrades log:\n") | 665 | body += _("Unattended-upgrades log:\n") |
1520 | 620 | body += mem_log.getvalue() | 666 | body += mem_log.getvalue() |
1521 | 621 | 667 | ||
1525 | 622 | # ensure that the message a utf8 encoded string | 668 | # python2 needs this as utf8 encoded string (not unicode) |
1526 | 623 | if type(body) is unicode: | 669 | if sys.version < '3': |
1527 | 624 | body= body.encode("utf-8", "replace") | 670 | body = body.encode("utf-8") |
1528 | 625 | 671 | ||
1529 | 626 | if os.path.exists(SENDMAIL_BINARY): | 672 | if os.path.exists(SENDMAIL_BINARY): |
1530 | 627 | ret = _send_mail_using_sendmail(to_email, subject, body) | 673 | ret = _send_mail_using_sendmail(to_email, subject, body) |
1531 | @@ -634,15 +680,16 @@ | |||
1532 | 634 | logging.debug("mail returned: %s" % ret) | 680 | logging.debug("mail returned: %s" % ret) |
1533 | 635 | 681 | ||
1534 | 636 | 682 | ||
1536 | 637 | def do_install(cache, pkgs_to_upgrade, options, logfile_dpkg): | 683 | def do_install(cache, pkgs_to_upgrade, blacklisted_pkgs, options, |
1537 | 684 | logfile_dpkg): | ||
1538 | 638 | # set debconf to NON_INTERACTIVE, redirect output | 685 | # set debconf to NON_INTERACTIVE, redirect output |
1540 | 639 | os.putenv("DEBIAN_FRONTEND","noninteractive"); | 686 | os.putenv("DEBIAN_FRONTEND", "noninteractive") |
1541 | 640 | setup_apt_listchanges() | 687 | setup_apt_listchanges() |
1543 | 641 | 688 | ||
1544 | 642 | # redirect to log | 689 | # redirect to log |
1545 | 643 | REDIRECT_INPUT = os.devnull | 690 | REDIRECT_INPUT = os.devnull |
1546 | 644 | fd = os.open(REDIRECT_INPUT, os.O_RDWR) | 691 | fd = os.open(REDIRECT_INPUT, os.O_RDWR) |
1548 | 645 | os.dup2(fd,0) | 692 | os.dup2(fd, 0) |
1549 | 646 | 693 | ||
1550 | 647 | logging.info(_("Writing dpkg log to '%s'") % logfile_dpkg) | 694 | logging.info(_("Writing dpkg log to '%s'") % logfile_dpkg) |
1551 | 648 | 695 | ||
1552 | @@ -651,21 +698,25 @@ | |||
1553 | 651 | old_stdout = 1 | 698 | old_stdout = 1 |
1554 | 652 | old_stderr = 2 | 699 | old_stderr = 2 |
1555 | 653 | else: | 700 | else: |
1557 | 654 | fd = os.open(logfile_dpkg, os.O_RDWR|os.O_CREAT, 0644) | 701 | fd = os.open(logfile_dpkg, os.O_RDWR | os.O_CREAT, 0o644) |
1558 | 655 | old_stdout = os.dup(1) | 702 | old_stdout = os.dup(1) |
1559 | 656 | old_stderr = os.dup(2) | 703 | old_stderr = os.dup(2) |
1562 | 657 | os.dup2(fd,1) | 704 | os.dup2(fd, 1) |
1563 | 658 | os.dup2(fd,2) | 705 | os.dup2(fd, 2) |
1564 | 659 | 706 | ||
1565 | 660 | try: | 707 | try: |
1567 | 661 | if (options.minimal_upgrade_steps or | 708 | if (options.minimal_upgrade_steps or |
1568 | 662 | # COMPAT with the mispelling | 709 | # COMPAT with the mispelling |
1572 | 663 | apt_pkg.config.find_b("Unattended-Upgrades::MinimalSteps", False) or | 710 | apt_pkg.config.find_b( |
1573 | 664 | apt_pkg.config.find_b("Unattended-Upgrade::MinimalSteps", False)): | 711 | "Unattended-Upgrades::MinimalSteps", False) or |
1574 | 665 | open("/var/run/unattended-upgrades.pid", "w").write("%s" % os.getpid()) | 712 | apt_pkg.config.find_b( |
1575 | 713 | "Unattended-Upgrade::MinimalSteps", False)): | ||
1576 | 714 | with open("/var/run/unattended-upgrades.pid", "w") as fp: | ||
1577 | 715 | fp.write("%s" % os.getpid()) | ||
1578 | 666 | # try upgrade all "pkgs" in minimal steps | 716 | # try upgrade all "pkgs" in minimal steps |
1579 | 667 | pkg_install_success = upgrade_in_minimal_steps( | 717 | pkg_install_success = upgrade_in_minimal_steps( |
1581 | 668 | cache, [pkg.name for pkg in pkgs_to_upgrade], logfile_dpkg) | 718 | cache, [pkg.name for pkg in pkgs_to_upgrade], logfile_dpkg, |
1582 | 719 | blacklisted_pkgs) | ||
1583 | 669 | else: | 720 | else: |
1584 | 670 | pkg_install_success = upgrade_normal( | 721 | pkg_install_success = upgrade_normal( |
1585 | 671 | cache, [pkg.name for pkg in pkgs_to_upgrade], logfile_dpkg) | 722 | cache, [pkg.name for pkg in pkgs_to_upgrade], logfile_dpkg) |
1586 | @@ -685,15 +736,16 @@ | |||
1587 | 685 | apt_pkg.config.clear("Unattended-Upgrade") | 736 | apt_pkg.config.clear("Unattended-Upgrade") |
1588 | 686 | # read rootdir (taken from apt.Cache, but we need to run it | 737 | # read rootdir (taken from apt.Cache, but we need to run it |
1589 | 687 | # here before the cache gets initialized | 738 | # here before the cache gets initialized |
1591 | 688 | if os.path.exists(rootdir+"/etc/apt/apt.conf"): | 739 | if os.path.exists(rootdir + "/etc/apt/apt.conf"): |
1592 | 689 | apt_pkg.read_config_file(apt_pkg.config, | 740 | apt_pkg.read_config_file(apt_pkg.config, |
1593 | 690 | rootdir + "/etc/apt/apt.conf") | 741 | rootdir + "/etc/apt/apt.conf") |
1595 | 691 | if os.path.isdir(rootdir+"/etc/apt/apt.conf.d"): | 742 | if os.path.isdir(rootdir + "/etc/apt/apt.conf.d"): |
1596 | 692 | apt_pkg.read_config_dir(apt_pkg.config, | 743 | apt_pkg.read_config_dir(apt_pkg.config, |
1597 | 693 | rootdir + "/etc/apt/apt.conf.d") | 744 | rootdir + "/etc/apt/apt.conf.d") |
1598 | 694 | 745 | ||
1599 | 746 | |||
1600 | 695 | def _get_logdir(): | 747 | def _get_logdir(): |
1602 | 696 | logdir= apt_pkg.config.find_dir( | 748 | logdir = apt_pkg.config.find_dir( |
1603 | 697 | "Unattended-Upgrade::LogDir", | 749 | "Unattended-Upgrade::LogDir", |
1604 | 698 | # COMPAT only | 750 | # COMPAT only |
1605 | 699 | apt_pkg.config.find_dir("APT::UnattendedUpgrades::LogDir", | 751 | apt_pkg.config.find_dir("APT::UnattendedUpgrades::LogDir", |
1606 | @@ -722,7 +774,6 @@ | |||
1607 | 722 | logging.basicConfig(level=logging.INFO, | 774 | logging.basicConfig(level=logging.INFO, |
1608 | 723 | format='%(asctime)s %(levelname)s %(message)s', | 775 | format='%(asctime)s %(levelname)s %(message)s', |
1609 | 724 | filename=logfile) | 776 | filename=logfile) |
1610 | 725 | |||
1611 | 726 | # additional logging | 777 | # additional logging |
1612 | 727 | logger = logging.getLogger() | 778 | logger = logging.getLogger() |
1613 | 728 | mem_log = StringIO() | 779 | mem_log = StringIO() |
1614 | @@ -734,7 +785,11 @@ | |||
1615 | 734 | mem_log_handler = logging.StreamHandler(mem_log) | 785 | mem_log_handler = logging.StreamHandler(mem_log) |
1616 | 735 | logger.addHandler(mem_log_handler) | 786 | logger.addHandler(mem_log_handler) |
1617 | 736 | return mem_log | 787 | return mem_log |
1619 | 737 | 788 | ||
1620 | 789 | |||
1621 | 790 | def get_blacklisted_pkgs(): | ||
1622 | 791 | return apt_pkg.config.value_list("Unattended-Upgrade::Package-Blacklist") | ||
1623 | 792 | |||
1624 | 738 | 793 | ||
1625 | 739 | def main(options, rootdir=""): | 794 | def main(options, rootdir=""): |
1626 | 740 | 795 | ||
1627 | @@ -749,24 +804,27 @@ | |||
1628 | 749 | allowed_origins = get_allowed_origins() | 804 | allowed_origins = get_allowed_origins() |
1629 | 750 | 805 | ||
1630 | 751 | # pkgs that are (for some reason) not save to install | 806 | # pkgs that are (for some reason) not save to install |
1633 | 752 | blacklisted_pkgs = apt_pkg.config.value_list("Unattended-Upgrade::Package-Blacklist") | 807 | blacklisted_pkgs = get_blacklisted_pkgs() |
1634 | 753 | logging.info(_("Initial blacklisted packages: %s"), " ".join(blacklisted_pkgs)) | 808 | logging.info(_("Initial blacklisted packages: %s"), |
1635 | 809 | " ".join(blacklisted_pkgs)) | ||
1636 | 754 | logging.info(_("Starting unattended upgrades script")) | 810 | logging.info(_("Starting unattended upgrades script")) |
1637 | 755 | 811 | ||
1638 | 756 | # display available origin | 812 | # display available origin |
1640 | 757 | logging.info(_("Allowed origins are: %s") % map(str,allowed_origins)) | 813 | logging.info(_("Allowed origins are: %s") % allowed_origins) |
1641 | 758 | 814 | ||
1642 | 759 | # check if the journal is dirty and if so, take emergceny action | 815 | # check if the journal is dirty and if so, take emergceny action |
1643 | 760 | # the alternative is to leave the system potentially unsecure until | 816 | # the alternative is to leave the system potentially unsecure until |
1644 | 761 | # the user comes in and fixes | 817 | # the user comes in and fixes |
1645 | 762 | if (is_dpkg_journal_dirty() and | 818 | if (is_dpkg_journal_dirty() and |
1647 | 763 | apt_pkg.config.find_b("Unattended-Upgrade::AutoFixInterruptedDpkg", True)): | 819 | apt_pkg.config.find_b( |
1648 | 820 | "Unattended-Upgrade::AutoFixInterruptedDpkg", True)): | ||
1649 | 764 | # ensure the dpkg database is not already locked (LP: #754330) | 821 | # ensure the dpkg database is not already locked (LP: #754330) |
1650 | 765 | admindir = os.path.dirname(apt_pkg.config.find("Dir::State::Status")) | 822 | admindir = os.path.dirname(apt_pkg.config.find("Dir::State::Status")) |
1651 | 766 | lockfd = apt_pkg.get_lock(os.path.join(admindir, "lock"), False) | 823 | lockfd = apt_pkg.get_lock(os.path.join(admindir, "lock"), False) |
1652 | 767 | if lockfd > 0: | 824 | if lockfd > 0: |
1655 | 768 | logging.warning(_("Unclean dpkg state detected, trying to correct")) | 825 | logging.warning( |
1656 | 769 | print _("Unclean dpkg state detected, trying to correct") | 826 | _("Unclean dpkg state detected, trying to correct")) |
1657 | 827 | print(_("Unclean dpkg state detected, trying to correct")) | ||
1658 | 770 | env = copy.copy(os.environ) | 828 | env = copy.copy(os.environ) |
1659 | 771 | env["DEBIAN_FRONTEND"] = "noninteractive" | 829 | env["DEBIAN_FRONTEND"] = "noninteractive" |
1660 | 772 | try: | 830 | try: |
1661 | @@ -777,22 +835,23 @@ | |||
1662 | 777 | output = e.output | 835 | output = e.output |
1663 | 778 | logging.warning(_("dpkg --configure -a output:\n%s" % output)) | 836 | logging.warning(_("dpkg --configure -a output:\n%s" % output)) |
1664 | 779 | else: | 837 | else: |
1667 | 780 | logging.debug("Unclean dpkg state, but locked, another package manager working?") | 838 | logging.debug("Unclean dpkg state, but locked, another package " |
1668 | 781 | 839 | "manager working?") | |
1669 | 840 | |||
1670 | 782 | # check and get lock | 841 | # check and get lock |
1671 | 783 | try: | 842 | try: |
1672 | 784 | apt_pkg.pkgsystem_lock() | 843 | apt_pkg.pkgsystem_lock() |
1674 | 785 | except SystemError, e: | 844 | except SystemError as e: |
1675 | 786 | logging.error(_("Lock could not be acquired (another package " | 845 | logging.error(_("Lock could not be acquired (another package " |
1676 | 787 | "manager running?)")) | 846 | "manager running?)")) |
1678 | 788 | print _("Cache lock can not be acquired, exiting") | 847 | print(_("Cache lock can not be acquired, exiting")) |
1679 | 789 | sys.exit(1) | 848 | sys.exit(1) |
1680 | 790 | 849 | ||
1681 | 791 | # get a cache | 850 | # get a cache |
1683 | 792 | cache = UnattendedUpgradesCache(rootdir=rootdir, | 851 | cache = UnattendedUpgradesCache(rootdir=rootdir, |
1684 | 793 | allowed_origins=allowed_origins) | 852 | allowed_origins=allowed_origins) |
1685 | 794 | if cache._depcache.broken_count > 0: | 853 | if cache._depcache.broken_count > 0: |
1687 | 795 | print _("Cache has broken packages, exiting") | 854 | print(_("Cache has broken packages, exiting")) |
1688 | 796 | logging.error(_("Cache has broken packages, exiting")) | 855 | logging.error(_("Cache has broken packages, exiting")) |
1689 | 797 | sys.exit(1) | 856 | sys.exit(1) |
1690 | 798 | # speed things up with latest apt | 857 | # speed things up with latest apt |
1691 | @@ -802,13 +861,14 @@ | |||
1692 | 802 | # find out about the packages that are upgradable (in a allowed_origin) | 861 | # find out about the packages that are upgradable (in a allowed_origin) |
1693 | 803 | pkgs_to_upgrade = [] | 862 | pkgs_to_upgrade = [] |
1694 | 804 | pkgs_kept_back = [] | 863 | pkgs_kept_back = [] |
1696 | 805 | pkgs_auto_removable = set([pkg.name for pkg in cache | 864 | pkgs_auto_removable = set([pkg.name for pkg in cache |
1697 | 806 | if pkg.is_auto_removable]) | 865 | if pkg.is_auto_removable]) |
1698 | 807 | 866 | ||
1699 | 808 | # now do the actual upgrade | 867 | # now do the actual upgrade |
1700 | 809 | for pkg in cache: | 868 | for pkg in cache: |
1701 | 810 | if options.debug and pkg.is_upgradable: | 869 | if options.debug and pkg.is_upgradable: |
1703 | 811 | logging.debug("Checking: %s (%s)" % (pkg.name, map(str, pkg.candidate.origins))) | 870 | logging.debug("Checking: %s (%s)" % ( |
1704 | 871 | pkg.name, map(str, getattr(pkg.candidate, "origins", [])))) | ||
1705 | 812 | if (pkg.is_upgradable and | 872 | if (pkg.is_upgradable and |
1706 | 813 | not is_pkgname_in_blacklist(pkg.name, blacklisted_pkgs) and | 873 | not is_pkgname_in_blacklist(pkg.name, blacklisted_pkgs) and |
1707 | 814 | is_allowed_origin(pkg.candidate, allowed_origins)): | 874 | is_allowed_origin(pkg.candidate, allowed_origins)): |
1708 | @@ -818,7 +878,7 @@ | |||
1709 | 818 | blacklisted_pkgs): | 878 | blacklisted_pkgs): |
1710 | 819 | # add to packages to upgrade | 879 | # add to packages to upgrade |
1711 | 820 | pkgs_to_upgrade.append(pkg) | 880 | pkgs_to_upgrade.append(pkg) |
1713 | 821 | # re-eval pkgs_kept_back as the resolver may fail to | 881 | # re-eval pkgs_kept_back as the resolver may fail to |
1714 | 822 | # directly upgrade a pkg, but that may work during | 882 | # directly upgrade a pkg, but that may work during |
1715 | 823 | # a subsequent operation, see debian bug #639840 | 883 | # a subsequent operation, see debian bug #639840 |
1716 | 824 | for pkgname in pkgs_kept_back: | 884 | for pkgname in pkgs_kept_back: |
1717 | @@ -830,17 +890,18 @@ | |||
1718 | 830 | logging.debug("sanity check failed") | 890 | logging.debug("sanity check failed") |
1719 | 831 | rewind_cache(cache, pkgs_to_upgrade) | 891 | rewind_cache(cache, pkgs_to_upgrade) |
1720 | 832 | pkgs_kept_back.append(pkg.name) | 892 | pkgs_kept_back.append(pkg.name) |
1722 | 833 | except SystemError, e: | 893 | except SystemError as e: |
1723 | 834 | # can't upgrade | 894 | # can't upgrade |
1725 | 835 | logging.warning(_("package '%s' upgradable but fails to be marked for upgrade (%s)") % (pkg.name, e)) | 895 | logging.warning( |
1726 | 896 | _("package '%s' upgradable but fails to " | ||
1727 | 897 | "be marked for upgrade (%s)") % (pkg.name, e)) | ||
1728 | 836 | rewind_cache(cache, pkgs_to_upgrade) | 898 | rewind_cache(cache, pkgs_to_upgrade) |
1729 | 837 | pkgs_kept_back.append(pkg.name) | 899 | pkgs_kept_back.append(pkg.name) |
1730 | 838 | |||
1731 | 839 | 900 | ||
1732 | 840 | pkgs_to_upgrade.sort(key=lambda p: p.name) | 901 | pkgs_to_upgrade.sort(key=lambda p: p.name) |
1733 | 841 | pkgs = "\n".join([pkg.name for pkg in pkgs_to_upgrade]) | 902 | pkgs = "\n".join([pkg.name for pkg in pkgs_to_upgrade]) |
1734 | 842 | logging.debug("pkgs that look like they should be upgraded: %s" % pkgs) | 903 | logging.debug("pkgs that look like they should be upgraded: %s" % pkgs) |
1736 | 843 | 904 | ||
1737 | 844 | # download what looks good | 905 | # download what looks good |
1738 | 845 | if options.debug: | 906 | if options.debug: |
1739 | 846 | fetcher = apt_pkg.Acquire(apt.progress.text.AcquireProgress()) | 907 | fetcher = apt_pkg.Acquire(apt.progress.text.AcquireProgress()) |
1740 | @@ -851,8 +912,8 @@ | |||
1741 | 851 | recs = cache._records | 912 | recs = cache._records |
1742 | 852 | pm = apt_pkg.PackageManager(cache._depcache) | 913 | pm = apt_pkg.PackageManager(cache._depcache) |
1743 | 853 | try: | 914 | try: |
1746 | 854 | pm.get_archives(fetcher,list,recs) | 915 | pm.get_archives(fetcher, list, recs) |
1747 | 855 | except SystemError, e: | 916 | except SystemError as e: |
1748 | 856 | logging.error(_("GetArchives() failed: '%s'") % e) | 917 | logging.error(_("GetArchives() failed: '%s'") % e) |
1749 | 857 | res = fetcher.run() | 918 | res = fetcher.run() |
1750 | 858 | logging.debug("fetch.run() result: %s" % res) | 919 | logging.debug("fetch.run() result: %s" % res) |
1751 | @@ -863,15 +924,19 @@ | |||
1752 | 863 | for item in fetcher.items: | 924 | for item in fetcher.items: |
1753 | 864 | logging.debug("%s" % item) | 925 | logging.debug("%s" % item) |
1754 | 865 | if item.status == item.STAT_ERROR: | 926 | if item.status == item.STAT_ERROR: |
1756 | 866 | print _("An error ocured: '%s'") % item.error_text | 927 | print(_("An error ocured: '%s'") % item.error_text) |
1757 | 867 | logging.error(_("An error ocured: '%s'") % item.error_text) | 928 | logging.error(_("An error ocured: '%s'") % item.error_text) |
1758 | 868 | if not item.complete: | 929 | if not item.complete: |
1761 | 869 | print _("The URI '%s' failed to download, aborting") % item.desc_uri | 930 | print(_("The URI '%s' failed to download, aborting") % |
1762 | 870 | logging.error(_("The URI '%s' failed to download, aborting") % item.desc_uri) | 931 | item.desc_uri) |
1763 | 932 | logging.error(_("The URI '%s' failed to download, aborting") % | ||
1764 | 933 | item.desc_uri) | ||
1765 | 871 | sys.exit(1) | 934 | sys.exit(1) |
1766 | 872 | if not os.path.exists(item.destfile): | 935 | if not os.path.exists(item.destfile): |
1769 | 873 | print _("Download finished, but file '%s' not there?!?" % item.destfile) | 936 | print(_("Download finished, but file '%s' not there?!?" % |
1770 | 874 | logging.error("Download finished, but file '%s' not there?!?" % item.destfile) | 937 | item.destfile)) |
1771 | 938 | logging.error("Download finished, but file '%s' not " | ||
1772 | 939 | "there?!?" % item.destfile) | ||
1773 | 875 | sys.exit(1) | 940 | sys.exit(1) |
1774 | 876 | if not item.is_trusted: | 941 | if not item.is_trusted: |
1775 | 877 | blacklisted_pkgs.append(pkgname_from_deb(item.destfile)) | 942 | blacklisted_pkgs.append(pkgname_from_deb(item.destfile)) |
1776 | @@ -879,18 +944,21 @@ | |||
1777 | 879 | # skip package (means to re-run the whole marking again | 944 | # skip package (means to re-run the whole marking again |
1778 | 880 | # and making sure that the package will not be pulled in by | 945 | # and making sure that the package will not be pulled in by |
1779 | 881 | # some other package again!) | 946 | # some other package again!) |
1781 | 882 | # | 947 | # |
1782 | 883 | # print to stdout to ensure that this message is part of | 948 | # print to stdout to ensure that this message is part of |
1783 | 884 | # the cron mail (only if no summary mail is requested) | 949 | # the cron mail (only if no summary mail is requested) |
1784 | 885 | email = apt_pkg.config.find("Unattended-Upgrade::Mail", "") | 950 | email = apt_pkg.config.find("Unattended-Upgrade::Mail", "") |
1785 | 886 | if not email: | 951 | if not email: |
1787 | 887 | print _("Package '%s' has conffile prompt and needs to be upgraded manually") % pkgname_from_deb(item.destfile) | 952 | print(_("Package '%s' has conffile prompt and needs " |
1788 | 953 | "to be upgraded manually") % pkgname_from_deb( | ||
1789 | 954 | item.destfile)) | ||
1790 | 888 | # log to the logfile | 955 | # log to the logfile |
1792 | 889 | logging.warning(_("Package '%s' has conffile prompt and needs to be upgraded manually") % pkgname_from_deb(item.destfile)) | 956 | logging.warning(_("Package '%s' has conffile prompt and " |
1793 | 957 | "needs to be upgraded manually") % | ||
1794 | 958 | pkgname_from_deb(item.destfile)) | ||
1795 | 890 | blacklisted_pkgs.append(pkgname_from_deb(item.destfile)) | 959 | blacklisted_pkgs.append(pkgname_from_deb(item.destfile)) |
1796 | 891 | pkgs_kept_back.append(pkgname_from_deb(item.destfile)) | 960 | pkgs_kept_back.append(pkgname_from_deb(item.destfile)) |
1797 | 892 | 961 | ||
1798 | 893 | |||
1799 | 894 | # redo the selection about the packages to upgrade based on the new | 962 | # redo the selection about the packages to upgrade based on the new |
1800 | 895 | # blacklist | 963 | # blacklist |
1801 | 896 | logging.debug("blacklist: %s" % blacklisted_pkgs) | 964 | logging.debug("blacklist: %s" % blacklisted_pkgs) |
1802 | @@ -904,7 +972,7 @@ | |||
1803 | 904 | pkg.mark_upgrade() | 972 | pkg.mark_upgrade() |
1804 | 905 | if check_changes_for_sanity(cache, allowed_origins, | 973 | if check_changes_for_sanity(cache, allowed_origins, |
1805 | 906 | blacklisted_pkgs): | 974 | blacklisted_pkgs): |
1807 | 907 | pkgs_to_upgrade.append(pkg) | 975 | pkgs_to_upgrade.append(pkg) |
1808 | 908 | else: | 976 | else: |
1809 | 909 | if not (pkg.name in pkgs_kept_back): | 977 | if not (pkg.name in pkgs_kept_back): |
1810 | 910 | pkgs_kept_back.append(pkg.name) | 978 | pkgs_kept_back.append(pkg.name) |
1811 | @@ -916,23 +984,26 @@ | |||
1812 | 916 | logging.debug("dpkg is configured not to cause conffile prompts") | 984 | logging.debug("dpkg is configured not to cause conffile prompts") |
1813 | 917 | 985 | ||
1814 | 918 | # do auto-remove | 986 | # do auto-remove |
1817 | 919 | if apt_pkg.config.find_b("Unattended-Upgrade::Remove-Unused-Dependencies", False): | 987 | if apt_pkg.config.find_b( |
1818 | 920 | now_auto_removable = set([pkg.name for pkg in cache | 988 | "Unattended-Upgrade::Remove-Unused-Dependencies", False): |
1819 | 989 | now_auto_removable = set([pkg.name for pkg in cache | ||
1820 | 921 | if pkg.is_auto_removable]) | 990 | if pkg.is_auto_removable]) |
1822 | 922 | for pkgname in now_auto_removable-pkgs_auto_removable: | 991 | for pkgname in now_auto_removable - pkgs_auto_removable: |
1823 | 923 | logging.debug("marking %s for remove" % pkgname) | 992 | logging.debug("marking %s for remove" % pkgname) |
1824 | 924 | cache[pkgname].mark_delete() | 993 | cache[pkgname].mark_delete() |
1825 | 925 | logging.info(_("Packages that are auto removed: '%s'") % | 994 | logging.info(_("Packages that are auto removed: '%s'") % |
1827 | 926 | " ".join(now_auto_removable-pkgs_auto_removable)) | 995 | " ".join(now_auto_removable - pkgs_auto_removable)) |
1828 | 927 | 996 | ||
1830 | 928 | logging.debug("InstCount=%i DelCount=%i BrokenCout=%i" % (cache._depcache.inst_count, cache._depcache.del_count, cache._depcache.broken_count)) | 997 | logging.debug("InstCount=%i DelCount=%i BrokenCount=%i" % ( |
1831 | 998 | cache._depcache.inst_count, cache._depcache.del_count, | ||
1832 | 999 | cache._depcache.broken_count)) | ||
1833 | 929 | 1000 | ||
1834 | 930 | # exit if there is nothing to do and nothing to report | 1001 | # exit if there is nothing to do and nothing to report |
1835 | 931 | if (len(pkgs_to_upgrade) == 0) and (len(pkgs_kept_back) == 0): | 1002 | if (len(pkgs_to_upgrade) == 0) and (len(pkgs_kept_back) == 0): |
1836 | 932 | logging.info(_("No packages found that can be upgraded unattended")) | 1003 | logging.info(_("No packages found that can be upgraded unattended")) |
1837 | 933 | return | 1004 | return |
1838 | 934 | 1005 | ||
1840 | 935 | # check if its configured for install on shutdown, if so, the | 1006 | # check if its configured for install on shutdown, if so, the |
1841 | 936 | # environment UNATTENDED_UPGRADES_FORCE_INSTALL_ON_SHUTDOWN will | 1007 | # environment UNATTENDED_UPGRADES_FORCE_INSTALL_ON_SHUTDOWN will |
1842 | 937 | # be set by the unatteded-upgrades-shutdown script | 1008 | # be set by the unatteded-upgrades-shutdown script |
1843 | 938 | if (not "UNATTENDED_UPGRADES_FORCE_INSTALL_ON_SHUTDOWN" in os.environ and | 1009 | if (not "UNATTENDED_UPGRADES_FORCE_INSTALL_ON_SHUTDOWN" in os.environ and |
1844 | @@ -944,7 +1015,7 @@ | |||
1845 | 944 | # check if we are in dry-run mode | 1015 | # check if we are in dry-run mode |
1846 | 945 | if options.dry_run: | 1016 | if options.dry_run: |
1847 | 946 | logging.info("Option --dry-run given, *not* performing real actions") | 1017 | logging.info("Option --dry-run given, *not* performing real actions") |
1849 | 947 | apt_pkg.config.set("Debug::pkgDPkgPM","1") | 1018 | apt_pkg.config.set("Debug::pkgDPkgPM", "1") |
1850 | 948 | 1019 | ||
1851 | 949 | # do the install based on the new list of pkgs | 1020 | # do the install based on the new list of pkgs |
1852 | 950 | pkgs = " ".join([pkg.name for pkg in pkgs_to_upgrade]) | 1021 | pkgs = " ".join([pkg.name for pkg in pkgs_to_upgrade]) |
1853 | @@ -964,7 +1035,7 @@ | |||
1854 | 964 | shutdown_lock = apt_pkg.get_lock("/var/run/unattended-upgrades.lock") | 1035 | shutdown_lock = apt_pkg.get_lock("/var/run/unattended-upgrades.lock") |
1855 | 965 | # do install | 1036 | # do install |
1856 | 966 | pkg_install_success = do_install( | 1037 | pkg_install_success = do_install( |
1858 | 967 | cache, pkgs_to_upgrade, options, logfile_dpkg) | 1038 | cache, pkgs_to_upgrade, blacklisted_pkgs, options, logfile_dpkg) |
1859 | 968 | 1039 | ||
1860 | 969 | # send a mail (if needed) | 1040 | # send a mail (if needed) |
1861 | 970 | if not options.dry_run: | 1041 | if not options.dry_run: |
1862 | @@ -972,17 +1043,18 @@ | |||
1863 | 972 | pkgs, pkg_install_success, pkgs_kept_back, mem_log, logfile_dpkg) | 1043 | pkgs, pkg_install_success, pkgs_kept_back, mem_log, logfile_dpkg) |
1864 | 973 | 1044 | ||
1865 | 974 | # auto-reboot (if required and the config for this is set | 1045 | # auto-reboot (if required and the config for this is set |
1867 | 975 | if (apt_pkg.config.find_b("Unattended-Upgrade::Automatic-Reboot", False) and | 1046 | if (apt_pkg.config.find_b( |
1868 | 1047 | "Unattended-Upgrade::Automatic-Reboot", False) and | ||
1869 | 976 | os.path.exists(REBOOT_REQUIRED_FILE)): | 1048 | os.path.exists(REBOOT_REQUIRED_FILE)): |
1870 | 977 | if shutdown_lock > 0: | 1049 | if shutdown_lock > 0: |
1871 | 978 | os.close(shutdown_lock) | 1050 | os.close(shutdown_lock) |
1872 | 979 | logging.warning("Found %s, rebooting" % REBOOT_REQUIRED_FILE) | 1051 | logging.warning("Found %s, rebooting" % REBOOT_REQUIRED_FILE) |
1873 | 980 | subprocess.call(["/sbin/reboot"]) | 1052 | subprocess.call(["/sbin/reboot"]) |
1875 | 981 | 1053 | ||
1876 | 982 | 1054 | ||
1877 | 983 | if __name__ == "__main__": | 1055 | if __name__ == "__main__": |
1880 | 984 | localesApp="unattended-upgrades" | 1056 | localesApp = "unattended-upgrades" |
1881 | 985 | localesDir="/usr/share/locale" | 1057 | localesDir = "/usr/share/locale" |
1882 | 986 | gettext.bindtextdomain(localesApp, localesDir) | 1058 | gettext.bindtextdomain(localesApp, localesDir) |
1883 | 987 | gettext.textdomain(localesApp) | 1059 | gettext.textdomain(localesApp) |
1884 | 988 | 1060 | ||
1885 | @@ -996,19 +1068,20 @@ | |||
1886 | 996 | help=_("Simulation, download but do not install")) | 1068 | help=_("Simulation, download but do not install")) |
1887 | 997 | parser.add_option("", "--minimal_upgrade_steps", | 1069 | parser.add_option("", "--minimal_upgrade_steps", |
1888 | 998 | action="store_true", default=False, | 1070 | action="store_true", default=False, |
1890 | 999 | help=_("Upgrade in minimal steps (and allow interrupting with SIGINT")) | 1071 | help=_("Upgrade in minimal steps (and allow " |
1891 | 1072 | "interrupting with SIGINT")) | ||
1892 | 1000 | (options, args) = parser.parse_args() | 1073 | (options, args) = parser.parse_args() |
1893 | 1001 | 1074 | ||
1894 | 1002 | if os.getuid() != 0: | 1075 | if os.getuid() != 0: |
1896 | 1003 | print _("You need to be root to run this application") | 1076 | print(_("You need to be root to run this application")) |
1897 | 1004 | sys.exit(1) | 1077 | sys.exit(1) |
1898 | 1005 | 1078 | ||
1899 | 1006 | # nice & ionce | 1079 | # nice & ionce |
1900 | 1007 | os.nice(19) | 1080 | os.nice(19) |
1902 | 1008 | IONICE="/usr/bin/ionice" | 1081 | IONICE = "/usr/bin/ionice" |
1903 | 1009 | if os.path.exists(IONICE): | 1082 | if os.path.exists(IONICE): |
1904 | 1010 | with open(os.devnull, "w") as fstderr: | 1083 | with open(os.devnull, "w") as fstderr: |
1906 | 1011 | subprocess.call([IONICE, "-c3", "-p",str(os.getpid())], | 1084 | subprocess.call([IONICE, "-c3", "-p", str(os.getpid())], |
1907 | 1012 | stderr=fstderr) | 1085 | stderr=fstderr) |
1908 | 1013 | 1086 | ||
1909 | 1014 | # ensure that we are not killed when the terminal goes away e.g. on | 1087 | # ensure that we are not killed when the terminal goes away e.g. on |
1910 | 1015 | 1088 | ||
1911 | === modified file 'unattended-upgrade-shutdown' | |||
1912 | --- unattended-upgrade-shutdown 2012-04-26 11:40:46 +0000 | |||
1913 | +++ unattended-upgrade-shutdown 2012-10-08 16:08:26 +0000 | |||
1914 | @@ -1,4 +1,4 @@ | |||
1916 | 1 | #!/usr/bin/python | 1 | #!/usr/bin/python3 |
1917 | 2 | # Copyright (c) 2009 Canonical Ltd | 2 | # Copyright (c) 2009 Canonical Ltd |
1918 | 3 | # | 3 | # |
1919 | 4 | # AUTHOR: | 4 | # AUTHOR: |
1920 | @@ -141,8 +141,8 @@ | |||
1921 | 141 | os.kill(pid, signal.SIGUSR1) | 141 | os.kill(pid, signal.SIGUSR1) |
1922 | 142 | # show log | 142 | # show log |
1923 | 143 | log_progress() | 143 | log_progress() |
1926 | 144 | time.sleep(5) | 144 | time.sleep(5) |
1927 | 145 | if (time.time() - start_time) > options.delay*60: | 145 | if (time.time() - start_time) > options.delay*60: |
1928 | 146 | logging.warning(_("Giving up on lockfile after %s delay") % options.delay) | 146 | logging.warning(_("Giving up on lockfile after %s delay") % options.delay) |
1929 | 147 | sys.exit(1) | 147 | sys.exit(1) |
1930 | 148 | 148 |