Merge lp:~mvo/unattended-upgrades/minimal-step-paranonia-lp1020680 into lp:~mvo/unattended-upgrades/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
Reviewer Review Type Date Requested Status
Michael Vogt Pending
Review via email: mp+128536@code.launchpad.net

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
=== added file '.bzrignore'
--- .bzrignore 1970-01-01 00:00:00 +0000
+++ .bzrignore 2012-10-08 16:08:26 +0000
@@ -0,0 +1,2 @@
1__pycache__
2build
03
=== modified file 'debian/changelog'
--- debian/changelog 2012-08-14 13:04:45 +0000
+++ debian/changelog 2012-10-08 16:08:26 +0000
@@ -1,3 +1,24 @@
1unattended-upgrades (0.79.3ubuntu2) quantal; urgency=low
2
3 [ Marc Tardif ]
4 * Fixed debug output when a package has no candidates (LP: #1046438)
5
6 [ Michael Vogt ]
7 * debian/test/:
8 - add dep8 tests
9
10 -- Marc Tardif <marc@ubuntu.com> Thu, 13 Sep 2012 16:16:04 -0400
11
12unattended-upgrades (0.79.3ubuntu1) quantal; urgency=low
13
14 [ Thomas Kluyver ]
15 * Port to Python 3
16
17 [ Brian Murray ]
18 * unattended-upgrade: fix typo in debugging output
19
20 -- Michael Vogt <michael.vogt@ubuntu.com> Mon, 10 Sep 2012 09:55:19 +0200
21
1unattended-upgrades (0.79.4) UNRELEASED; urgency=low22unattended-upgrades (0.79.4) UNRELEASED; urgency=low
223
3 * data/50unattended-upgrades.{Debian,Ubuntu}:24 * data/50unattended-upgrades.{Debian,Ubuntu}:
@@ -63,7 +84,7 @@
63 - added, thanks to Pedro Ribeiro, closes: #67873884 - added, thanks to Pedro Ribeiro, closes: #678738
64 * po/sk.po:85 * po/sk.po:
65 - added, thanks to helix84, closes: #67747186 - added, thanks to helix84, closes: #677471
66 87
67 [ Teodor MICU ]88 [ Teodor MICU ]
68 * debian/unattended-upgrades.init:89 * debian/unattended-upgrades.init:
69 - fixes new style lsb-init output, closes: #67803090 - fixes new style lsb-init output, closes: #678030
@@ -93,7 +114,7 @@
93 - updated, thanks to Joe Dalton, closes: #677804114 - updated, thanks to Joe Dalton, closes: #677804
94 * po/de.po:115 * po/de.po:
95 - updated, thanks to Chris Leick (closes: #678204)116 - updated, thanks to Chris Leick (closes: #678204)
96 117
97 [ Teodor MICU ]118 [ Teodor MICU ]
98 * debian/unattended-upgrades.init:119 * debian/unattended-upgrades.init:
99 - use new style lsb-init output, closes: #678030120 - use new style lsb-init output, closes: #678030
100121
=== modified file 'debian/control'
--- debian/control 2012-07-13 18:51:00 +0000
+++ debian/control 2012-10-08 16:08:26 +0000
@@ -3,14 +3,15 @@
3Priority: optional3Priority: optional
4Maintainer: Michael Vogt <michael.vogt@ubuntu.com>4Maintainer: Michael Vogt <michael.vogt@ubuntu.com>
5Build-Depends: debhelper (>= 7.0.50~), po-debconf, lsb-release5Build-Depends: debhelper (>= 7.0.50~), po-debconf, lsb-release
6Build-Depends-Indep: python (>= 2.6.6-3~), python-distutils-extra6Build-Depends-Indep: python3, python3-distutils-extra
7Standards-Version: 3.8.37Standards-Version: 3.9.3
8Vcs-Bzr: http://code.launchpad.net/~ubuntu-core-dev/unattended-upgrades/ubuntu/8Vcs-Bzr: http://code.launchpad.net/~ubuntu-core-dev/unattended-upgrades/ubuntu/
9XS-Testsuite: autopkgtest
910
10Package: unattended-upgrades11Package: unattended-upgrades
11Architecture: all12Architecture: all
12Depends: ${shlibs:Depends}, ${misc:Depends}, debconf, python, 13Depends: ${shlibs:Depends}, ${misc:Depends}, debconf, python3,
13 python-apt (>= 0.7.90), apt-utils, apt, ucf, lsb-release, 14 python3-apt (>= 0.7.90), apt-utils, apt, ucf, lsb-release,
14 lsb-base (>= 3.2-14)15 lsb-base (>= 3.2-14)
15Suggests: bsd-mailx, mail-transport-agent16Suggests: bsd-mailx, mail-transport-agent
16Description: automatic installation of security upgrades17Description: automatic installation of security upgrades
1718
=== modified file 'debian/rules'
--- debian/rules 2011-11-09 19:20:50 +0000
+++ debian/rules 2012-10-08 16:08:26 +0000
@@ -3,24 +3,26 @@
3DIST=$(shell /usr/bin/lsb_release -i -s)3DIST=$(shell /usr/bin/lsb_release -i -s)
44
5%:5%:
6 dh $@ --with python26 dh $@ --with python3
77
8override_dh_auto_build:8override_dh_auto_build:
9 # copy the right template into place9 # copy the right template into place
10 cp data/50unattended-upgrades.$(DIST) data/50unattended-upgrades10 cp data/50unattended-upgrades.$(DIST) data/50unattended-upgrades
11 dh_auto_build11 python3 setup.py build
12
13override_dh_auto_install:
14 python3 setup.py install \
15 --root=$(CURDIR)/debian/unattended-upgrades \
16 --install-layout=deb
1217
13override_dh_auto_clean:18override_dh_auto_clean:
14 # Sanity-check before upload.19 # Sanity-check before upload.
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 \
16 for f in unattended-upgrade unattended-upgrade-shutdown; do \21 ln -nsf $$f $$f.py; \
17 ln -nsf $$f $$f.py; \22 py3compile $$f.py; \
18 python$(PYVER) /usr/lib/python$(PYVER)/py_compile.py \23 rm -f $$f.py; \
19 $$f.py; \24 done
20 rm -f $$f.py; \25 python3 setup.py clean -a
21 done; \
22 fi
23 dh_auto_clean
2426
25override_dh_installinit:27override_dh_installinit:
26 # we do not want to run the init script in the postinst/prerm, its28 # we do not want to run the init script in the postinst/prerm, its
2729
=== added directory 'debian/tests'
=== added file 'debian/tests/control'
--- debian/tests/control 1970-01-01 00:00:00 +0000
+++ debian/tests/control 2012-10-08 16:08:26 +0000
@@ -0,0 +1,2 @@
1Tests: run-tests
2Depends: @, make, python-dev, python3-dev, python-coverage
03
=== added file 'debian/tests/run-tests'
--- debian/tests/run-tests 1970-01-01 00:00:00 +0000
+++ debian/tests/run-tests 2012-10-08 16:08:26 +0000
@@ -0,0 +1,4 @@
1#!/bin/sh
2
3cd test
4make
05
=== modified file 'debian/unattended-upgrades.init'
--- debian/unattended-upgrades.init 2012-06-29 08:09:25 +0000
+++ debian/unattended-upgrades.init 2012-10-08 16:08:26 +0000
@@ -33,7 +33,7 @@
33stop)33stop)
34 if [ -e $SHUTDOWN_HELPER ]; then34 if [ -e $SHUTDOWN_HELPER ]; then
35 [ "$VERBOSE" != "no" ] && log_action_begin_msg "Checking for running $DESC"35 [ "$VERBOSE" != "no" ] && log_action_begin_msg "Checking for running $DESC"
36 python $SHUTDOWN_HELPER36 python3 $SHUTDOWN_HELPER
37 [ "$VERBOSE" != "no" ] && log_action_end_msg $? "$NAME"37 [ "$VERBOSE" != "no" ] && log_action_end_msg $? "$NAME"
38 fi38 fi
39 ;;39 ;;
4040
=== modified file 'pm/sleep.d/10_unattended-upgrades-hibernate'
--- pm/sleep.d/10_unattended-upgrades-hibernate 2011-11-08 16:56:58 +0000
+++ pm/sleep.d/10_unattended-upgrades-hibernate 2012-10-08 16:08:26 +0000
@@ -17,7 +17,7 @@
17case "${1}" in17case "${1}" in
18 hibernate)18 hibernate)
19 if [ -e $SHUTDOWN_HELPER ]; then19 if [ -e $SHUTDOWN_HELPER ]; then
20 python $SHUTDOWN_HELPER20 python3 $SHUTDOWN_HELPER
21 fi21 fi
22 ;;22 ;;
23 resume|thaw)23 resume|thaw)
2424
=== modified file 'setup.py'
--- setup.py 2011-10-24 10:20:18 +0000
+++ setup.py 2012-10-08 16:08:26 +0000
@@ -1,9 +1,10 @@
1#!/usr/bin/env python1#!/usr/bin/env python
22
3from distutils.core import setup3from distutils.core import setup
4from DistUtilsExtra.command import *4from DistUtilsExtra.command import (
5import glob5 build_extra,
6import os6 build_i18n,
7 )
78
8 9
9setup(name='unattended-upgrades', version='0.1',10setup(name='unattended-upgrades', version='0.1',
1011
=== modified file 'test/Makefile'
--- test/Makefile 2011-10-07 09:22:19 +0000
+++ test/Makefile 2012-10-08 16:08:26 +0000
@@ -3,12 +3,15 @@
3all: check3all: check
44
5check:5check:
6 # test with both py2 and py3 for now and also use coverage for the py2
6 set -e; \7 set -e; \
7 find . -name 'test_*.py' | \8 find . -name 'test_*.py' | \
8 while read file; do \9 while read file; do \
9 echo "Running $$file"; \
10 if [ -x $$file ]; then \10 if [ -x $$file ]; then \
11 python $$file ; \11 echo "Running $$file with python3"; \
12 python3 $$file ; \
13 echo "Running $$file with python"; \
14 python-coverage run -a $$file; \
12 fi \15 fi \
13 done16 done
1417
@@ -16,4 +19,8 @@
16 rm -rf ./aptroot/var/cache/19 rm -rf ./aptroot/var/cache/
17 rm -rf ./aptroot/var/lib/apt20 rm -rf ./aptroot/var/lib/apt
18 rm -rf ./aptroot/var/run21 rm -rf ./aptroot/var/run
22 find .. -type d -name __pycache__ | xargs rm -rf
1923
24coverage-html:
25 echo "output in htmlcov/
26 python-coverage html
20\ No newline at end of file27\ No newline at end of file
2128
=== modified file 'test/create_debug_lock.py'
--- test/create_debug_lock.py 2011-06-16 07:10:07 +0000
+++ test/create_debug_lock.py 2012-10-08 16:08:26 +0000
@@ -1,4 +1,4 @@
1#!/usr/bin/python1#!/usr/bin/python3
2#2#
3# create a lock file so that unattended-upgrades-shutdown pauses3# create a lock file so that unattended-upgrades-shutdown pauses
4# on shutdown -- useful for testing4# on shutdown -- useful for testing
@@ -7,6 +7,7 @@
7import os7import os
8import time8import time
99
10
10pid = os.fork()11pid = os.fork()
11if pid == 0:12if pid == 0:
12 os.setsid()13 os.setsid()
1314
=== modified file 'test/test_against_real_archive.py' (properties changed: +x to -x)
--- test/test_against_real_archive.py 2012-02-28 10:48:18 +0000
+++ test/test_against_real_archive.py 2012-10-08 16:08:26 +0000
@@ -1,22 +1,31 @@
1#!/usr/bin/python1#!/usr/bin/python3
2"""Test unattended_upgrades against the real archive in a chroot.
3
4Note that this test is not run by the makefile in this folder, as it requires
5network access, and it fails in some situations (unclear which).
6"""
27
3import apt8import apt
4import apt_pkg9import apt_pkg
5import glob10import glob
11import logging
6import os12import os
7import re13import re
8import unittest14import unittest
915
10import unattended_upgrade16import unattended_upgrade
1117
18
12apt_pkg.config.set("APT::Architecture", "amd64")19apt_pkg.config.set("APT::Architecture", "amd64")
1320
21
14class MockOptions():22class MockOptions():
15 def __init__(self, debug=True, dry_run=True):23 def __init__(self, debug=True, dry_run=True):
16 self.debug = debug24 self.debug = debug
17 self.dry_run = dry_run25 self.dry_run = dry_run
18 self.minimal_upgrade_steps = False26 self.minimal_upgrade_steps = False
1927
28
20class TestAgainstRealArchive(unittest.TestCase):29class TestAgainstRealArchive(unittest.TestCase):
2130
22 def setUp(self):31 def setUp(self):
@@ -40,11 +49,13 @@
40 apt_pkg.config.set("APT::UnattendedUpgrades::LogDir", logdir)49 apt_pkg.config.set("APT::UnattendedUpgrades::LogDir", logdir)
41 unattended_upgrade.DISTRO_CODENAME = "lucid"50 unattended_upgrade.DISTRO_CODENAME = "lucid"
42 res = unattended_upgrade.main(options, os.path.abspath("./aptroot"))51 res = unattended_upgrade.main(options, os.path.abspath("./aptroot"))
52 logging.debug(res)
43 # check if the log file exists53 # check if the log file exists
44 self.assertTrue(os.path.exists(logfile))54 self.assertTrue(os.path.exists(logfile))
45 log = open(logfile).read()55 with open(logfile) as fp:
56 log = fp.read()
46 # check that stuff worked57 # check that stuff worked
47 self.assertFalse(" ERROR " in log)58 self.assertFalse(" ERROR " in log, log)
48 # check if we actually have the expected ugprade in it59 # check if we actually have the expected ugprade in it
49 self.assertTrue(60 self.assertTrue(
50 re.search("INFO Packages that are upgraded:.*awstats", log))61 re.search("INFO Packages that are upgraded:.*awstats", log))
@@ -59,4 +70,3 @@
5970
60if __name__ == "__main__":71if __name__ == "__main__":
61 unittest.main()72 unittest.main()
62
6373
=== modified file 'test/test_conffile.py'
--- test/test_conffile.py 2012-06-28 20:06:37 +0000
+++ test/test_conffile.py 2012-10-08 16:08:26 +0000
@@ -1,12 +1,13 @@
1#!/usr/bin/python1#!/usr/bin/python3
22
3import apt_pkg3import apt_pkg
4import logging4import logging
5import unittest5import unittest
6import sys6
77
8from unattended_upgrade import conffile_prompt8from unattended_upgrade import conffile_prompt
99
10
10class ConffilePromptTestCase(unittest.TestCase):11class ConffilePromptTestCase(unittest.TestCase):
1112
12 def setUp(self):13 def setUp(self):
@@ -19,7 +20,7 @@
19 test_pkg = "./packages/conf-test-package_1.1.deb"20 test_pkg = "./packages/conf-test-package_1.1.deb"
20 self.assertTrue(conffile_prompt(test_pkg, prefix="./root.conffile"),21 self.assertTrue(conffile_prompt(test_pkg, prefix="./root.conffile"),
21 "conffile prompt detection incorrect")22 "conffile prompt detection incorrect")
22 23
23 def test_will_not_prompt(self):24 def test_will_not_prompt(self):
24 # conf-test 0.9 is installed, 1.0 gets installed25 # conf-test 0.9 is installed, 1.0 gets installed
25 # they both have the same config files26 # they both have the same config files
@@ -57,4 +58,3 @@
57if __name__ == "__main__":58if __name__ == "__main__":
58 logging.basicConfig(level=logging.DEBUG)59 logging.basicConfig(level=logging.DEBUG)
59 unittest.main()60 unittest.main()
60
6161
=== modified file 'test/test_in_chroot.py'
--- test/test_in_chroot.py 2012-06-28 20:06:37 +0000
+++ test/test_in_chroot.py 2012-10-08 16:08:26 +0000
@@ -1,4 +1,4 @@
1#!/usr/bin/python1#!/usr/bin/python3
22
3import apt3import apt
4import logging4import logging
@@ -15,7 +15,8 @@
15#SOURCES_LIST="""15#SOURCES_LIST="""
16#deb http://ftp.de.debian.org/debian squeeze main contrib non-free16#deb http://ftp.de.debian.org/debian squeeze main contrib non-free
17#deb http://ftp.de.debian.org/debian squeeze-updates main contrib non-free17#deb http://ftp.de.debian.org/debian squeeze-updates main contrib non-free
18#deb http://ftp.de.debian.org/debian squeeze-proposed-updates main contrib non-f#ree18#deb http://ftp.de.debian.org/debian squeeze-proposed-updates main contrib \
19# non-free
19#deb http://security.debian.org squeeze/updates main contrib non-free20#deb http://security.debian.org squeeze/updates main contrib non-free
20#"""21#"""
21#DISTRO="squeeze"22#DISTRO="squeeze"
@@ -27,7 +28,7 @@
2728
2829
29# ubuntu30# ubuntu
30SOURCES_LIST="""31SOURCES_LIST = """
31deb http://archive.ubuntu.com/ubuntu/ lucid main restricted32deb http://archive.ubuntu.com/ubuntu/ lucid main restricted
32deb-src http://archive.ubuntu.com/ubuntu/ lucid main restricted33deb-src http://archive.ubuntu.com/ubuntu/ lucid main restricted
3334
@@ -37,35 +38,39 @@
37deb http://security.ubuntu.com/ubuntu/ lucid-security main restricted38deb http://security.ubuntu.com/ubuntu/ lucid-security main restricted
38deb-src http://security.ubuntu.com/ubuntu/ lucid-security main restricted39deb-src http://security.ubuntu.com/ubuntu/ lucid-security main restricted
39"""40"""
40DISTRO="lucid"41DISTRO = "lucid"
41ARCH="i386"42ARCH = "i386"
42TARBALL="%s-%s.tgz" % (DISTRO, ARCH)43TARBALL = "%s-%s.tgz" % (DISTRO, ARCH)
43MIRROR="http://archive.ubuntu.com/ubuntu"44MIRROR = "http://archive.ubuntu.com/ubuntu"
44APT_CONF="""APT::Architecture "%s";""" % ARCH45APT_CONF = """APT::Architecture "%s";""" % ARCH
45ORIGINS_PATTERN="origin=Ubuntu,archive=lucid-security"46ORIGINS_PATTERN = "origin=Ubuntu,archive=lucid-security"
4647
47apt.apt_pkg.config.set("APT::Architecture", ARCH)48apt.apt_pkg.config.set("APT::Architecture", ARCH)
48sys.path.insert(0, "..")49sys.path.insert(0, "..")
49import unattended_upgrade50import unattended_upgrade
5051
52
51class MockOptions(object):53class MockOptions(object):
52 debug = True54 debug = True
53 dry_run = False55 dry_run = False
54 minimal_upgrade_steps = False56 minimal_upgrade_steps = False
5557
58
56class TestUnattendedUpgrade(unittest.TestCase):59class TestUnattendedUpgrade(unittest.TestCase):
5760
58 def _create_new_debootstrap_tarball(self, tarball, target):61 def _create_new_debootstrap_tarball(self, tarball, target):
59 print "creating initial test tarball, this is needed only once"62 print("creating initial test tarball, this is needed only once")
60 # force i38663 # force i386
61 subprocess.call(["debootstrap",64 subprocess.call(
62 "--arch=%s" % ARCH,65 ["debootstrap",
63 # smaller version of the minimal system66 "--arch=%s" % ARCH,
64 "--variant=minbase",67 # smaller version of the minimal system
65 "--include=python-apt,apt-utils,gpgv,ubuntu-keyring,ca-certificates",68 "--variant=minbase",
66 DISTRO, 69 "--include=python-apt,apt-utils,gpgv,ubuntu-keyring,"
67 target,70 "ca-certificates",
68 MIRROR])71 DISTRO,
72 target,
73 MIRROR])
69 subprocess.call(["chroot", target, "apt-get", "clean"])74 subprocess.call(["chroot", target, "apt-get", "clean"])
70 subprocess.call(["tar", "czf", tarball, target])75 subprocess.call(["tar", "czf", tarball, target])
7176
@@ -73,7 +78,7 @@
73 subprocess.call(["tar", "xzf", tarball])78 subprocess.call(["tar", "xzf", tarball])
7479
75 def test_normal_upgrade(self):80 def test_normal_upgrade(self):
76 print "Running normal unattended upgrade in chroot"81 print("Running normal unattended upgrade in chroot")
77 options = MockOptions()82 options = MockOptions()
78 options.minimal_upgrade_steps = False83 options.minimal_upgrade_steps = False
79 # run it84 # run it
@@ -82,7 +87,7 @@
82 self.assertTrue(self._verify_install_log_in_real_chroot(target))87 self.assertTrue(self._verify_install_log_in_real_chroot(target))
8388
84 def test_minimal_steps_upgrade(self):89 def test_minimal_steps_upgrade(self):
85 print "Running minimal steps unattended upgrade in chroot"90 print("Running minimal steps unattended upgrade in chroot")
86 options = MockOptions()91 options = MockOptions()
87 options.minimal_upgrade_steps = True92 options.minimal_upgrade_steps = True
88 # run it93 # run it
@@ -91,14 +96,15 @@
91 self.assertTrue(self._verify_install_log_in_real_chroot(target))96 self.assertTrue(self._verify_install_log_in_real_chroot(target))
9297
93 def test_upgrade_on_shutdown_upgrade(self):98 def test_upgrade_on_shutdown_upgrade(self):
94 print "Running unattended upgrade on shutdown (download and install) in chroot"99 print("Running unattended upgrade on shutdown (download and install) "
100 "in chroot")
95 # ensure that it actually installs in shutdown env mode101 # ensure that it actually installs in shutdown env mode
96 options = MockOptions()102 options = MockOptions()
97 os.environ["UNATTENDED_UPGRADES_FORCE_INSTALL_ON_SHUTDOWN"] = "1"103 os.environ["UNATTENDED_UPGRADES_FORCE_INSTALL_ON_SHUTDOWN"] = "1"
98 apt.apt_pkg.config.set("Unattended-Upgrade::InstallOnShutdown", "1")104 apt.apt_pkg.config.set("Unattended-Upgrade::InstallOnShutdown", "1")
99 target = self._run_upgrade_test_in_real_chroot(options)105 target = self._run_upgrade_test_in_real_chroot(options)
100 self.assertTrue(self._verify_install_log_in_real_chroot(target))106 self.assertTrue(self._verify_install_log_in_real_chroot(target))
101 107
102 def _get_lockfile_location(self, target):108 def _get_lockfile_location(self, target):
103 return os.path.join(109 return os.path.join(
104 target, "var/log/unattended-upgrades/unattended-upgrades.log")110 target, "var/log/unattended-upgrades/unattended-upgrades.log")
@@ -114,14 +120,13 @@
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)
115 open(os.path.join(target, "etc/apt/sources.list"), "w").write(121 open(os.path.join(target, "etc/apt/sources.list"), "w").write(
116 SOURCES_LIST)122 SOURCES_LIST)
117
118123
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):
120 """ helper that runs the unattended-upgrade in a chroot125 """ helper that runs the unattended-upgrade in a chroot
121 and does some basic verifications126 and does some basic verifications
122 """127 """
123 if os.getuid() != 0:128 if os.getuid() != 0:
124 print "Skipping because uid != 0"129 print("Skipping because uid != 0")
125 return130 return
126131
127 # clear to avoid pollution in the chroot132 # clear to avoid pollution in the chroot
@@ -130,7 +135,7 @@
130 # create chroot135 # create chroot
131 target = "./test-chroot.%s" % DISTRO136 target = "./test-chroot.%s" % DISTRO
132137
133 # setup chroot if needed 138 # setup chroot if needed
134 if clean_chroot:139 if clean_chroot:
135 self._setup_chroot(target)140 self._setup_chroot(target)
136141
@@ -143,7 +148,7 @@
143 if not os.path.exists("/var/log/unattended-upgrades/"):148 if not os.path.exists("/var/log/unattended-upgrades/"):
144 os.makedirs("/var/log/unattended-upgrades/")149 os.makedirs("/var/log/unattended-upgrades/")
145 # make sure we are up-to-date150 # make sure we are up-to-date
146 subprocess.call(["apt-get","update", "-q", "-q"])151 subprocess.call(["apt-get", "update", "-q", "-q"])
147 # run it152 # run it
148 apt.apt_pkg.config.clear("Unattended-Upgrade::Allowed-Origins")153 apt.apt_pkg.config.clear("Unattended-Upgrade::Allowed-Origins")
149 apt.apt_pkg.config.clear("Unattended-Upgrade::Origins-Pattern")154 apt.apt_pkg.config.clear("Unattended-Upgrade::Origins-Pattern")
@@ -153,7 +158,7 @@
153 unattended_upgrade.main(options)158 unattended_upgrade.main(options)
154 os._exit(0)159 os._exit(0)
155 else:160 else:
156 has_progress=False161 has_progress = False
157 all_progress = ""162 all_progress = ""
158 last_progress = ""163 last_progress = ""
159 progress_log = os.path.join(164 progress_log = os.path.join(
@@ -171,9 +176,9 @@
171 if pid == apid:176 if pid == apid:
172 ret = os.WEXITSTATUS(status)177 ret = os.WEXITSTATUS(status)
173 break178 break
174 #print "*******************", all_progress179 #print("*******************", all_progress)
175 self.assertEqual(ret, 0)180 self.assertEqual(ret, 0)
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
177 # progress data182 # progress data
178 self.assertTrue(has_progress, True)183 self.assertTrue(has_progress, True)
179 self.assertTrue(len(all_progress) > 5)184 self.assertTrue(len(all_progress) > 5)
@@ -183,11 +188,12 @@
183 # examine log188 # examine log
184 log = self._get_lockfile_location(target)189 log = self._get_lockfile_location(target)
185 logfile = open(log).read()190 logfile = open(log).read()
186 #print logfile191 #print(logfile)
187 NEEDLE_PKG="ca-certificates"192 NEEDLE_PKG = "ca-certificates"
188 if not re.search(193 if not re.search(
189 "Packages that are upgraded:.*%s" % NEEDLE_PKG, logfile):194 "Packages that are upgraded:.*%s" % NEEDLE_PKG, logfile):
190 logging.warn("Can not find expected %s upgrade in log" % NEEDLE_PKG)195 logging.warn("Can not find expected %s upgrade in log" %
196 NEEDLE_PKG)
191 return False197 return False
192 if "ERROR Installing the upgrades failed" in logfile:198 if "ERROR Installing the upgrades failed" in logfile:
193 logging.warn("Got a ERROR in the logfile")199 logging.warn("Got a ERROR in the logfile")
@@ -196,9 +202,10 @@
196 target, "var/log/unattended-upgrades/*-dpkg*.log")202 target, "var/log/unattended-upgrades/*-dpkg*.log")
197 dpkg_logfile = open(glob.glob(dpkg_log)[0]).read()203 dpkg_logfile = open(glob.glob(dpkg_log)[0]).read()
198 if not "Preparing to replace %s" % NEEDLE_PKG in dpkg_logfile:204 if not "Preparing to replace %s" % NEEDLE_PKG in dpkg_logfile:
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" %
206 NEEDLE_PKG)
200 return False207 return False
201 #print dpkg_logfile208 #print(dpkg_logfile)
202 return True209 return True
203210
204211
205212
=== modified file 'test/test_logdir.py'
--- test/test_logdir.py 2012-06-29 07:08:35 +0000
+++ test/test_logdir.py 2012-10-08 16:08:26 +0000
@@ -1,9 +1,8 @@
1#!/usr/bin/python1#!/usr/bin/python3
22
3import apt_pkg3import apt_pkg
4import logging4import logging
5import os5import os
6import mock
7import sys6import sys
8import tempfile7import tempfile
9import unittest8import unittest
@@ -11,10 +10,12 @@
11sys.path.insert(0, "..")10sys.path.insert(0, "..")
12from unattended_upgrade import _setup_logging11from unattended_upgrade import _setup_logging
1312
13
14class MockOptions:14class MockOptions:
15 dry_run = False15 dry_run = False
16 debug = False16 debug = False
1717
18
18class TestLogdir(unittest.TestCase):19class TestLogdir(unittest.TestCase):
1920
20 def setUp(self):21 def setUp(self):
2122
=== modified file 'test/test_mail.py'
--- test/test_mail.py 2012-07-13 12:20:03 +0000
+++ test/test_mail.py 2012-10-08 16:08:26 +0000
@@ -1,11 +1,14 @@
1#!/usr/bin/python1#!/usr/bin/python3
2# -*- coding: utf-8 -*-2# -*- coding: utf-8 -*-
3from __future__ import unicode_literals
4
3import apt_pkg5import apt_pkg
4import os6import os
7import sys
5import unittest8import unittest
69
10from io import StringIO
7from email.parser import Parser11from email.parser import Parser
8from StringIO import StringIO
912
10import unattended_upgrade13import unattended_upgrade
11from unattended_upgrade import send_summary_mail, setup_apt_listchanges14from unattended_upgrade import send_summary_mail, setup_apt_listchanges
@@ -40,9 +43,10 @@
40 res = successful43 res = successful
41 pkgs_kept_back = []44 pkgs_kept_back = []
42 # include some unicode chars here for good measure45 # include some unicode chars here for good measure
43 mem_log = StringIO(u"mem_log text üöä")46 mem_log = StringIO("mem_log text üöä")
44 logfile_dpkg = "./apt-term.log"47 logfile_dpkg = "./apt-term.log"
45 open("./apt-term.log", "w").write("logfile_dpkg text")48 with open("./apt-term.log", "w") as fp:
49 fp.write("logfile_dpkg text")
46 return (pkgs, res, pkgs_kept_back, mem_log, logfile_dpkg)50 return (pkgs, res, pkgs_kept_back, mem_log, logfile_dpkg)
4751
48 def _verify_common_mail_content(self, mail_txt):52 def _verify_common_mail_content(self, mail_txt):
@@ -50,47 +54,55 @@
50 self.assertTrue(expected_string in mail_txt)54 self.assertTrue(expected_string in mail_txt)
5155
52 def test_summary_mail_reboot(self):56 def test_summary_mail_reboot(self):
53 open("./reboot-required","w").write("")57 with open("./reboot-required", "w") as fp:
58 fp.write("")
54 send_summary_mail(*self._return_mock_data())59 send_summary_mail(*self._return_mock_data())
55 os.unlink("./reboot-required")60 os.unlink("./reboot-required")
56 mail_txt = open("mail.txt").read()61 # this is used for py2 compat for py3 only we can do
62 # remove the "rb" and the subsequent '.decode("utf-8")'
63 with open("mail.txt", "rb") as fp:
64 mail_txt = fp.read().decode("utf-8")
57 self.assertTrue("[reboot required]" in mail_txt)65 self.assertTrue("[reboot required]" in mail_txt)
58 self._verify_common_mail_content(mail_txt)66 self._verify_common_mail_content(mail_txt)
59 67
60 def test_summary_mail_no_reboot(self):68 def test_summary_mail_no_reboot(self):
61 send_summary_mail(*self._return_mock_data())69 send_summary_mail(*self._return_mock_data())
62 mail_txt = open("mail.txt").read()70 with open("mail.txt", "rb") as fp:
71 mail_txt = fp.read().decode("utf-8")
63 self.assertFalse("[reboot required]" in mail_txt)72 self.assertFalse("[reboot required]" in mail_txt)
64 self._verify_common_mail_content(mail_txt)73 self._verify_common_mail_content(mail_txt)
65 74
66 def test_summary_mail_only_on_error(self):75 def test_summary_mail_only_on_error(self):
67 # default is to always send mail, ensure this is correct76 # default is to always send mail, ensure this is correct
68 # for both success and failure77 # for both success and failure
69 apt_pkg.config.set("Unattended-Upgrade::MailOnlyOnError", "false")78 apt_pkg.config.set("Unattended-Upgrade::MailOnlyOnError", "false")
70 send_summary_mail(*self._return_mock_data(successful=True))79 send_summary_mail(*self._return_mock_data(successful=True))
71 self._verify_common_mail_content(open("mail.txt").read())80 with open("mail.txt", "rb") as fp:
81 self._verify_common_mail_content(fp.read().decode("utf-8"))
72 os.remove("mail.txt")82 os.remove("mail.txt")
73 # now with a simulated failure83 # now with a simulated failure
74 send_summary_mail(*self._return_mock_data(successful=False))84 send_summary_mail(*self._return_mock_data(successful=False))
75 self._verify_common_mail_content(open("mail.txt").read())85 with open("mail.txt", "rb") as fp:
86 self._verify_common_mail_content(fp.read().decode("utf-8"))
76 os.remove("mail.txt")87 os.remove("mail.txt")
77 # now test with "MailOnlyOnError"88 # now test with "MailOnlyOnError"
78 apt_pkg.config.set("Unattended-Upgrade::MailOnlyOnError", "true")89 apt_pkg.config.set("Unattended-Upgrade::MailOnlyOnError", "true")
79 send_summary_mail(*self._return_mock_data(successful=True))90 send_summary_mail(*self._return_mock_data(successful=True))
80 self.assertFalse(os.path.exists("mail.txt"))91 self.assertFalse(os.path.exists("mail.txt"))
81 send_summary_mail(*self._return_mock_data(successful=False))92 send_summary_mail(*self._return_mock_data(successful=False))
82 mail_txt = open("mail.txt").read()93 with open("mail.txt", "rb") as fp:
94 mail_txt = fp.read().decode("utf-8")
83 self._verify_common_mail_content(mail_txt)95 self._verify_common_mail_content(mail_txt)
84 self.assertTrue("Unattended upgrade returned: False" in mail_txt)96 self.assertTrue("Unattended upgrade returned: False" in mail_txt)
85 self.assertTrue(os.path.exists("mail.txt"))97 self.assertTrue(os.path.exists("mail.txt"))
8698
87 def test_apt_listchanges(self):99 def test_apt_listchanges(self):
88 # test with sendmail available100 # test with sendmail available
89 unattended_upgrade.SENDMAIL_BINARY="/bin/true"101 unattended_upgrade.SENDMAIL_BINARY = "/bin/true"
90 setup_apt_listchanges("./data/listchanges.conf.mail")102 setup_apt_listchanges("./data/listchanges.conf.mail")
91 self.assertEqual(os.environ["APT_LISTCHANGES_FRONTEND"], "mail")103 self.assertEqual(os.environ["APT_LISTCHANGES_FRONTEND"], "mail")
92 # test without sendmail104 # test without sendmail
93 unattended_upgrade.SENDMAIL_BINARY="/bin/not-here-xxxxxxxxx"105 unattended_upgrade.SENDMAIL_BINARY = "/bin/not-here-xxxxxxxxx"
94 setup_apt_listchanges("./data/listchanges.conf.pager")106 setup_apt_listchanges("./data/listchanges.conf.pager")
95 self.assertEqual(os.environ["APT_LISTCHANGES_FRONTEND"], "none")107 self.assertEqual(os.environ["APT_LISTCHANGES_FRONTEND"], "none")
96108
@@ -108,6 +120,7 @@
108 # we don't accidently try120 # we don't accidently try
109 self.assertFalse('text/plain; charset="utf-8"' in mail_txt)121 self.assertFalse('text/plain; charset="utf-8"' in mail_txt)
110122
123
111class SendmailTestCase(CommonTestsForMailxAndSendmail, unittest.TestCase):124class SendmailTestCase(CommonTestsForMailxAndSendmail, unittest.TestCase):
112125
113 def setUp(self):126 def setUp(self):
@@ -117,10 +130,15 @@
117 def _verify_common_mail_content(self, mail_txt):130 def _verify_common_mail_content(self, mail_txt):
118 CommonTestsForMailxAndSendmail._verify_common_mail_content(131 CommonTestsForMailxAndSendmail._verify_common_mail_content(
119 self, mail_txt)132 self, mail_txt)
133
134 # python2 needs this as utf8 encoded string (not unicode)
135 if sys.version < '3':
136 mail_txt = mail_txt.encode("utf-8")
137
120 msg = Parser().parsestr(mail_txt)138 msg = Parser().parsestr(mail_txt)
121 content_type = msg["Content-Type"]139 content_type = msg["Content-Type"]
122 self.assertEqual(content_type, 'text/plain; charset="utf-8"')140 self.assertEqual(content_type, 'text/plain; charset="utf-8"')
123 141
124142
125class SendmailAndMailxTestCase(SendmailTestCase):143class SendmailAndMailxTestCase(SendmailTestCase):
126144
@@ -132,4 +150,3 @@
132if __name__ == "__main__":150if __name__ == "__main__":
133 #logging.basicConfig(level=logging.DEBUG)151 #logging.basicConfig(level=logging.DEBUG)
134 unittest.main()152 unittest.main()
135
136153
=== modified file 'test/test_minimal_partitions.py'
--- test/test_minimal_partitions.py 2011-11-18 10:46:15 +0000
+++ test/test_minimal_partitions.py 2012-10-08 16:08:26 +0000
@@ -1,33 +1,32 @@
1#!/usr/bin/python1#!/usr/bin/python3
22
3import apt3import apt
4import apt_pkg4import apt_pkg
5import os5import os
6import logging
7import unittest6import unittest
8import sys
9import time
107
11import unattended_upgrade8import unattended_upgrade
129
10
13class LogInstallProgressMock(unattended_upgrade.LogInstallProgress):11class LogInstallProgressMock(unattended_upgrade.LogInstallProgress):
1412
15 # klass data so that we can veriy in the test as the actual13 # klass data so that we can veriy in the test as the actual
16 # object is destroyed14 # object is destroyed
17 DATA = []15 DATA = []
18 16
19 # overwrite to log the data17 # overwrite to log the data
20 def status_change(self, pkg, percent, status):18 def status_change(self, pkg, percent, status):
21 print pkg, percent19 print(pkg, percent)
22 self.DATA.append([pkg, percent])20 self.DATA.append([pkg, percent])
2321
22
24class TestMinimalPartitions(unittest.TestCase):23class TestMinimalPartitions(unittest.TestCase):
2524
26 def setUp(self):25 def setUp(self):
27 # setup dry-run mode for apt26 # setup dry-run mode for apt
28 apt_pkg.config.set("Dir::Cache", "/tmp")27 apt_pkg.config.set("Dir::Cache", "/tmp")
29 apt_pkg.config.set("Debug::NoLocking","1")28 apt_pkg.config.set("Debug::NoLocking", "1")
30 apt_pkg.config.set("Debug::pkgDPkgPM","1")29 apt_pkg.config.set("Debug::pkgDPkgPM", "1")
31 apt_pkg.config.set("Dir::State::extended_states", "./extended_states")30 apt_pkg.config.set("Dir::State::extended_states", "./extended_states")
32 apt_pkg.config.clear("Dpkg::Post-Invoke")31 apt_pkg.config.clear("Dpkg::Post-Invoke")
33 apt_pkg.config.clear("Dpkg::Pre-Install-Pkgs")32 apt_pkg.config.clear("Dpkg::Pre-Install-Pkgs")
@@ -40,10 +39,11 @@
40 def test_upgrade_in_minimal_steps(self):39 def test_upgrade_in_minimal_steps(self):
41 self.cache.upgrade(True)40 self.cache.upgrade(True)
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()]
43 unattended_upgrade.PROGRESS_LOG="./aptroot/var/run/unatteded-upgrades.progress"42 unattended_upgrade.PROGRESS_LOG = \
43 "./aptroot/var/run/unatteded-upgrades.progress"
44 unattended_upgrade.LogInstallProgress = LogInstallProgressMock44 unattended_upgrade.LogInstallProgress = LogInstallProgressMock
45 unattended_upgrade.upgrade_in_minimal_steps(45 unattended_upgrade.upgrade_in_minimal_steps(
46 self.cache, pkgs_to_upgrade)46 self.cache, pkgs_to_upgrade, "", [])
47 # ensure we count upwarts47 # ensure we count upwarts
48 last_percent = -148 last_percent = -1
49 for (pkg, percent) in LogInstallProgressMock.DATA:49 for (pkg, percent) in LogInstallProgressMock.DATA:
5050
=== modified file 'test/test_origin_pattern.py'
--- test/test_origin_pattern.py 2012-08-14 11:55:21 +0000
+++ test/test_origin_pattern.py 2012-10-08 16:08:26 +0000
@@ -1,4 +1,4 @@
1#!/usr/bin/python1#!/usr/bin/python3
22
3import apt_pkg3import apt_pkg
4import logging4import logging
@@ -12,49 +12,63 @@
12 UnknownMatcherError,12 UnknownMatcherError,
13 )13 )
1414
15
15class MockOrigin():16class MockOrigin():
16 pass17 pass
18
19
17class MockCandidate():20class MockCandidate():
18 pass21 pass
22
23
19class MockPackage():24class MockPackage():
20 pass25 pass
26
27
21class MockCache(list):28class MockCache(list):
22 pass29 pass
30
31
23class MockDepCache():32class MockDepCache():
24 pass33 pass
2534
35
26class TestOriginPatern(unittest.TestCase):36class TestOriginPatern(unittest.TestCase):
2737
28 def setUp(self):38 def setUp(self):
29 pass39 pass
40
30 def tearDown(self):41 def tearDown(self):
31 pass42 pass
43
32 def test_match_whitelist_string(self):44 def test_match_whitelist_string(self):
33 origin = self._get_mock_origin(45 origin = self._get_mock_origin(
34 "OriginUbuntu", "LabelUbuntu", "ArchiveUbuntu",46 "OriginUbuntu", "LabelUbuntu", "ArchiveUbuntu",
35 "archive.ubuntu.com", "main")47 "archive.ubuntu.com", "main")
36 # good48 # good
37 s="o=OriginUbuntu"49 s = "o=OriginUbuntu"
38 self.assertTrue(match_whitelist_string(s, origin))50 self.assertTrue(match_whitelist_string(s, origin))
39 s="o=OriginUbuntu,l=LabelUbuntu,a=ArchiveUbuntu,site=archive.ubuntu.com"51 s = "o=OriginUbuntu,l=LabelUbuntu,a=ArchiveUbuntu," \
52 "site=archive.ubuntu.com"
40 self.assertTrue(match_whitelist_string(s, origin))53 self.assertTrue(match_whitelist_string(s, origin))
41 # bad54 # bad
42 s=""55 s = ""
43 self.assertFalse(match_whitelist_string(s, origin))56 self.assertFalse(match_whitelist_string(s, origin))
44 s="o=something"57 s = "o=something"
45 self.assertFalse(match_whitelist_string(s, origin))58 self.assertFalse(match_whitelist_string(s, origin))
46 s="o=LabelUbuntu,a=no-match"59 s = "o=LabelUbuntu,a=no-match"
47 self.assertFalse(match_whitelist_string(s, origin))60 self.assertFalse(match_whitelist_string(s, origin))
48 # with escaping61 # with escaping
49 origin = self._get_mock_origin("Google, Inc.", archive="stable")62 origin = self._get_mock_origin("Google, Inc.", archive="stable")
50 # good63 # good
51 s="o=Google\, Inc.,a=stable"64 s = "o=Google\, Inc.,a=stable"
52 self.assertTrue(match_whitelist_string(s, origin))65 self.assertTrue(match_whitelist_string(s, origin))
5366
54 def test_match_whitelist_from_conffile(self):67 def test_match_whitelist_from_conffile(self):
55 # read some68 # read some
56 apt_pkg.config.clear("Unattended-Upgrade")69 apt_pkg.config.clear("Unattended-Upgrade")
57 apt_pkg.read_config_file(apt_pkg.config, "./data/50unattended-upgrades.Test")70 apt_pkg.read_config_file(
71 apt_pkg.config, "./data/50unattended-upgrades.Test")
58 allowed_origins = unattended_upgrade.get_allowed_origins()72 allowed_origins = unattended_upgrade.get_allowed_origins()
59 #print allowed_origins73 #print allowed_origins
60 self.assertTrue("o=aOrigin,a=aArchive" in allowed_origins)74 self.assertTrue("o=aOrigin,a=aArchive" in allowed_origins)
@@ -63,7 +77,8 @@
6377
64 def test_compatiblity(self):78 def test_compatiblity(self):
65 apt_pkg.config.clear("Unattended-Upgrade")79 apt_pkg.config.clear("Unattended-Upgrade")
66 apt_pkg.read_config_file(apt_pkg.config, "./data/50unattended-upgrades.compat")80 apt_pkg.read_config_file(
81 apt_pkg.config, "./data/50unattended-upgrades.compat")
67 allowed_origins = unattended_upgrade.get_allowed_origins()82 allowed_origins = unattended_upgrade.get_allowed_origins()
68 #print allowed_origins83 #print allowed_origins
69 self.assertTrue("o=Google\, Inc.,a=stable" in allowed_origins)84 self.assertTrue("o=Google\, Inc.,a=stable" in allowed_origins)
@@ -74,7 +89,7 @@
7489
75 def test_unkown_matcher(self):90 def test_unkown_matcher(self):
76 apt_pkg.config.clear("Unattended-Upgrade")91 apt_pkg.config.clear("Unattended-Upgrade")
77 s="xxx=OriginUbuntu"92 s = "xxx=OriginUbuntu"
78 with self.assertRaises(UnknownMatcherError):93 with self.assertRaises(UnknownMatcherError):
79 self.assertTrue(match_whitelist_string(s, None))94 self.assertTrue(match_whitelist_string(s, None))
8095
@@ -90,10 +105,12 @@
90 allowed_origins = ["o=Ubuntu"]105 allowed_origins = ["o=Ubuntu"]
91 blacklist = ["linux-.*"]106 blacklist = ["linux-.*"]
92 # with blacklist pkg107 # with blacklist pkg
93 self.assertFalse(check_changes_for_sanity(cache, allowed_origins, blacklist))108 self.assertFalse(
109 check_changes_for_sanity(cache, allowed_origins, blacklist))
94 # with "normal" pkg110 # with "normal" pkg
95 pkg.name = "apt"111 pkg.name = "apt"
96 self.assertTrue(check_changes_for_sanity(cache, allowed_origins, blacklist)) 112 self.assertTrue(
113 check_changes_for_sanity(cache, allowed_origins, blacklist))
97114
98 def _get_mock_origin(self, aorigin="", label="", archive="",115 def _get_mock_origin(self, aorigin="", label="", archive="",
99 site="", component=""):116 site="", component=""):
@@ -125,4 +142,3 @@
125if __name__ == "__main__":142if __name__ == "__main__":
126 logging.basicConfig(level=logging.DEBUG)143 logging.basicConfig(level=logging.DEBUG)
127 unittest.main()144 unittest.main()
128
129145
=== added file 'test/test_pep8.py'
--- test/test_pep8.py 1970-01-01 00:00:00 +0000
+++ test/test_pep8.py 2012-10-08 16:08:26 +0000
@@ -0,0 +1,17 @@
1import glob
2import os
3import subprocess
4import unittest
5
6
7class PackagePep8TestCase(unittest.TestCase):
8
9 def test_all_code(self):
10 res = 0
11 py_files = glob.glob(os.path.join(os.path.dirname(__file__), "*.py"))
12 res += subprocess.call(["pep8", "--repeat", ] + py_files)
13 self.assertEqual(res, 0)
14
15
16if __name__ == "__main__":
17 unittest.main()
018
=== modified file 'test/test_pyflakes.py' (properties changed: -x to +x)
--- test/test_pyflakes.py 2012-07-13 16:40:10 +0000
+++ test/test_pyflakes.py 2012-10-08 16:08:26 +0000
@@ -2,12 +2,14 @@
2import subprocess2import subprocess
3import unittest3import unittest
44
5
5class TestPyflakesClean(unittest.TestCase):6class TestPyflakesClean(unittest.TestCase):
6 """ ensure that the tree is pyflakes clean """7 """ ensure that the tree is pyflakes clean """
78
8 def test_pyflakes_clean(self):9 def test_pyflakes_clean(self):
9 target = os.path.join(os.path.dirname(__file__), "..", "unattended-upgrade")10 path = os.path.join(
10 self.assertEqual(subprocess.call(["pyflakes", target]), 0)11 os.path.dirname(__file__), "unattended_upgrade.py")
12 self.assertEqual(subprocess.call(["pyflakes", path]), 0)
1113
1214
13if __name__ == "__main__":15if __name__ == "__main__":
1416
=== modified file 'test/test_substitute.py'
--- test/test_substitute.py 2011-02-04 11:05:12 +0000
+++ test/test_substitute.py 2012-10-08 16:08:26 +0000
@@ -1,17 +1,13 @@
1#!/usr/bin/python1#!/usr/bin/python3
22
3import apt
4import apt_pkg3import apt_pkg
5import os
6import logging4import logging
7import unittest5import unittest
8import sys
9
10from StringIO import StringIO
116
12import unattended_upgrade7import unattended_upgrade
13from unattended_upgrade import substitute, get_allowed_origins8from unattended_upgrade import substitute, get_allowed_origins
149
10
15class TestSubstitude(unittest.TestCase):11class TestSubstitude(unittest.TestCase):
1612
17 def setUp(self):13 def setUp(self):
@@ -36,4 +32,3 @@
36if __name__ == "__main__":32if __name__ == "__main__":
37 logging.basicConfig(level=logging.DEBUG)33 logging.basicConfig(level=logging.DEBUG)
38 unittest.main()34 unittest.main()
39
4035
=== modified file 'unattended-upgrade'
--- unattended-upgrade 2012-08-14 11:55:21 +0000
+++ unattended-upgrade 2012-10-08 16:08:26 +0000
@@ -1,4 +1,4 @@
1#!/usr/bin/python1#!/usr/bin/python3
2# Copyright (c) 2005-2012 Canonical Ltd2# Copyright (c) 2005-2012 Canonical Ltd
3#3#
4# AUTHOR:4# AUTHOR:
@@ -20,26 +20,27 @@
20# along with unattended-upgrades; if not, write to the Free Software20# along with unattended-upgrades; if not, write to the Free Software
21# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA21# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22#22#
23
24import apt_inst23import apt_inst
25import apt_pkg24import apt_pkg
2625
27import copy26import copy
28import datetime27import datetime
29import email.Charset28import email.charset
30import fcntl29import fcntl
31import re30import re
32import os31import os
33import string32import string
34import sys33import sys
3534
36from email.Message import Message35from io import StringIO
36from email.message import Message
37from optparse import OptionParser37from optparse import OptionParser
38from StringIO import StringIO38
39from subprocess import Popen, PIPE39from subprocess import (
4040 Popen,
41import warnings41 PIPE,
42warnings.filterwarnings("ignore", "apt API not stable yet", FutureWarning)42 )
43
43import apt44import apt
44import logging45import logging
45import lsb_release46import lsb_release
@@ -57,29 +58,32 @@
57DISTRO_ID = lsb_release.get_distro_information()['ID']58DISTRO_ID = lsb_release.get_distro_information()['ID']
5859
59# progress information is written here60# progress information is written here
60PROGRESS_LOG="/var/run/unattended-upgrades.progress"61PROGRESS_LOG = "/var/run/unattended-upgrades.progress"
6162
62# set from the sigint signal handler63# set from the sigint signal handler
63SIGNAL_STOP_REQUEST=False64SIGNAL_STOP_REQUEST = False
65
6466
65class UnknownMatcherError(ValueError):67class UnknownMatcherError(ValueError):
66 pass68 pass
6769
6870
69class UnattendedUpgradesCache(apt.Cache):71class UnattendedUpgradesCache(apt.Cache):
70 72
71 def __init__(self, rootdir, allowed_origins):73 def __init__(self, rootdir, allowed_origins):
72 apt.Cache.__init__(self, rootdir=rootdir)74 apt.Cache.__init__(self, rootdir=rootdir)
73 self.allowed_origins = allowed_origins75 self.allowed_origins = allowed_origins
74 # ensure we update the candidate versions 76 # ensure we update the candidate versions
75 self.adjust_candidate_versions()77 self.adjust_candidate_versions()
78
76 def clear(self):79 def clear(self):
77 apt.Cache.clear(self)80 apt.Cache.clear(self)
78 # ensure we update the candidate versions 81 # ensure we update the candidate versions
79 self.adjust_candidate_versions()82 self.adjust_candidate_versions()
83
80 def adjust_candidate_versions(self):84 def adjust_candidate_versions(self):
81 """ Adjust candidate versions to match highest allowed origin85 """ Adjust candidate versions to match highest allowed origin
82 86
83 This adjusts the origin even if the candidate has a higher87 This adjusts the origin even if the candidate has a higher
84 version88 version
85 """89 """
@@ -114,20 +118,19 @@
114 (/var/run/unattended-upgrades.progress by default)118 (/var/run/unattended-upgrades.progress by default)
115 """119 """
116120
117 LOG = PROGRESS_LOG 121 LOG = PROGRESS_LOG
118122
119 def status_change(self, pkg, percent, status):123 def status_change(self, pkg, percent, status):
120 f=open(self.LOG, "w")124 with open(self.LOG, "w") as f:
121 f.write(_("Progress: %s %% (%s)") % (percent, pkg))125 f.write(_("Progress: %s %% (%s)") % (percent, pkg))
122 f.close()
123126
124 def _fixup_fds(self):127 def _fixup_fds(self):
125 required_fds = [ 0, 1, 2, # stdin, stdout, stderr128 required_fds = [0, 1, 2, # stdin, stdout, stderr
126 self.writefd,129 self.writefd,
127 self.write_stream.fileno(),130 self.write_stream.fileno(),
128 self.statusfd,131 self.statusfd,
129 self.status_stream.fileno()132 self.status_stream.fileno()
130 ]133 ]
131 # ensure that our required fds close on exec134 # ensure that our required fds close on exec
132 for fd in required_fds[3:]:135 for fd in required_fds[3:]:
133 old_flags = fcntl.fcntl(fd, fcntl.F_GETFD)136 old_flags = fcntl.fcntl(fd, fcntl.F_GETFD)
@@ -140,19 +143,19 @@
140 try:143 try:
141 fd = int(fdname)144 fd = int(fdname)
142 except Exception as e:145 except Exception as e:
143 print "ERROR: can not get fd for '%s'" % fdname146 print("ERROR: can not get fd for '%s'" % fdname)
144 if fd in required_fds:147 if fd in required_fds:
145 continue148 continue
146 try:149 try:
147 os.close(fd)150 os.close(fd)
148 #print "closed: ", fd151 #print("closed: ", fd)
149 except OSError as e:152 except OSError as e:
150 # there will be one fd that can not be closed153 # there will be one fd that can not be closed
151 # as its the fd from pythons internal diropen()154 # as its the fd from pythons internal diropen()
152 # so its ok to ignore one close error155 # so its ok to ignore one close error
153 error_count += 1156 error_count += 1
154 if error_count > 1:157 if error_count > 1:
155 print "ERROR: os.close(%s): %s" % (fd, e)158 print("ERROR: os.close(%s): %s" % (fd, e))
156159
157 def fork(self):160 def fork(self):
158 pid = os.fork()161 pid = os.fork()
@@ -162,53 +165,62 @@
162165
163166
164class Unlocked:167class Unlocked:
165 """ context manager for unlocking the apt lock while cache.commit()168 """
166 is run 169 Context manager for unlocking the apt lock while cache.commit() is run
167 """170 """
171
168 def __enter__(self):172 def __enter__(self):
169 try:173 try:
170 apt_pkg.pkgsystem_unlock()174 apt_pkg.pkgsystem_unlock()
171 except:175 except:
172 pass176 pass
177
173 def __exit__(self, exc_type, exc_value, exc_tb):178 def __exit__(self, exc_type, exc_value, exc_tb):
174 try:179 try:
175 apt_pkg.pkgsystem_unlock()180 apt_pkg.pkgsystem_unlock()
176 except:181 except:
177 pass182 pass
178183
184
179def is_dpkg_journal_dirty():185def is_dpkg_journal_dirty():
180 """186 """
181 test if the dpkg journal is dirty187 Return True if the dpkg journal is dirty
182 (similar to debSystem::CheckUpdates)188 (similar to debSystem::CheckUpdates)
183 """189 """
184 d = os.path.dirname(190 d = os.path.join(
185 apt_pkg.config.find_file("Dir::State::status"))+"/updates"191 os.path.dirname(apt_pkg.config.find_file("Dir::State::status")),
192 "updates")
186 for f in os.listdir(d):193 for f in os.listdir(d):
187 if re.match("[0-9]+", f):194 if re.match("[0-9]+", f):
188 return True195 return True
189 return False196 return False
190197
198
191def signal_handler(signal, frame):199def signal_handler(signal, frame):
192 logging.warn("SIGUSR1 recieved, will stop")200 logging.warn("SIGUSR1 recieved, will stop")
193 global SIGNAL_STOP_REQUEST201 global SIGNAL_STOP_REQUEST
194 SIGNAL_STOP_REQUEST=True202 SIGNAL_STOP_REQUEST = True
203
195204
196def substitute(line):205def substitute(line):
197 """ substitude known mappings and return a new string 206 """ substitude known mappings and return a new string
198207
199 Currently supported ${distro-release}208 Currently supported ${distro-release}
200 """209 """
201 mapping = {"distro_codename" : get_distro_codename(),210 mapping = {"distro_codename": get_distro_codename(),
202 "distro_id" : get_distro_id(),211 "distro_id": get_distro_id(),
203 }212 }
204 return string.Template(line).substitute(mapping)213 return string.Template(line).substitute(mapping)
205 214
215
206def get_distro_codename():216def get_distro_codename():
207 return DISTRO_CODENAME217 return DISTRO_CODENAME
208218
219
209def get_distro_id():220def get_distro_id():
210 return DISTRO_ID221 return DISTRO_ID
211222
223
212def get_allowed_origins_legacy():224def get_allowed_origins_legacy():
213 """ legacy support for old Allowed-Origins var """225 """ legacy support for old Allowed-Origins var """
214 allowed_origins = []226 allowed_origins = []
@@ -222,10 +234,11 @@
222 distro_id = re.sub(r'([^\\]),', r'\1\\,', distro_id)234 distro_id = re.sub(r'([^\\]),', r'\1\\,', distro_id)
223 distro_codename = re.sub(r'([^\\]),', r'\1\\,', distro_codename)235 distro_codename = re.sub(r'([^\\]),', r'\1\\,', distro_codename)
224 # convert to new format236 # convert to new format
225 allowed_origins.append("o=%s,a=%s" % (substitute(distro_id), 237 allowed_origins.append("o=%s,a=%s" % (substitute(distro_id),
226 substitute(distro_codename)))238 substitute(distro_codename)))
227 return allowed_origins239 return allowed_origins
228240
241
229def get_allowed_origins():242def get_allowed_origins():
230 """ return a list of allowed origins from apt.conf243 """ return a list of allowed origins from apt.conf
231244
@@ -236,6 +249,7 @@
236 allowed_origins.append(substitute(s))249 allowed_origins.append(substitute(s))
237 return allowed_origins250 return allowed_origins
238251
252
239def match_whitelist_string(whitelist, origin):253def match_whitelist_string(whitelist, origin):
240 """254 """
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"
@@ -251,9 +265,10 @@
251 whitelist = whitelist.replace("\,", "%2C")265 whitelist = whitelist.replace("\,", "%2C")
252 for token in whitelist.split(","):266 for token in whitelist.split(","):
253 # strip and unquote the "," back267 # strip and unquote the "," back
254 (what, value) = [s.strip().replace("%2C",",")268 (what, value) = [s.strip().replace("%2C", ",")
255 for s in token.split("=")]269 for s in token.split("=")]
256 #logging.debug("matching '%s'='%s' against '%s'" % (what, value, origin))270 #logging.debug("matching '%s'='%s' against '%s'" % (
271 # what, value, origin))
257 # first char is apt-cache policy output, send is the name272 # first char is apt-cache policy output, send is the name
258 # in the Release file273 # in the Release file
259 if what in ("o", "origin"):274 if what in ("o", "origin"):
@@ -272,6 +287,7 @@
272 what, token))287 what, token))
273 return res288 return res
274289
290
275def upgrade_normal(cache, pkgs_to_upgrade, logfile_dpkg):291def upgrade_normal(cache, pkgs_to_upgrade, logfile_dpkg):
276 error = None292 error = None
277 res = False293 res = False
@@ -279,18 +295,19 @@
279 try:295 try:
280 with Unlocked():296 with Unlocked():
281 res = cache.commit(install_progress=iprogress)297 res = cache.commit(install_progress=iprogress)
282 except SystemError,e:298 except SystemError as e:
283 error = e299 error = e
284 if res:300 if res:
285 logging.info(_("All upgrades installed"))301 logging.info(_("All upgrades installed"))
286 else:302 else:
287 logging.error(_("Installing the upgrades failed!"))303 logging.error(_("Installing the upgrades failed!"))
288 logging.error(_("error message: '%s'") % error)304 logging.error(_("error message: '%s'") % error)
289 logging.error(_("dpkg returned a error! See '%s' for details") % \305 logging.error(_("dpkg returned a error! See '%s' for details") %
290 logfile_dpkg)306 logfile_dpkg)
291 return res307 return res
292308
293def upgrade_in_minimal_steps(cache, pkgs_to_upgrade, logfile_dpkg=""):309
310def upgrade_in_minimal_steps(cache, pkgs_to_upgrade, logfile_dpkg, blacklist):
294311
295 install_log = LogInstallProgress()312 install_log = LogInstallProgress()
296 install_log.LOG += ".minimal-steps"313 install_log.LOG += ".minimal-steps"
@@ -298,6 +315,9 @@
298 # setup signal handler315 # setup signal handler
299 signal.signal(signal.SIGUSR1, signal_handler)316 signal.signal(signal.SIGUSR1, signal_handler)
300317
318 # double check any changes we do
319 allowed_origins = get_allowed_origins()
320
301 # to upgrade contains the package names321 # to upgrade contains the package names
302 to_upgrade = set(pkgs_to_upgrade)322 to_upgrade = set(pkgs_to_upgrade)
303 while True:323 while True:
@@ -314,19 +334,28 @@
314 pkg.mark_install()334 pkg.mark_install()
315 else:335 else:
316 continue336 continue
337 # double check that we are not running into side effects like
338 # what could have been caused LP: #1020680
339 if not check_changes_for_sanity(cache, allowed_origins, blacklist):
340 logging.error(
341 "Internal error while building a minimal partition."
342 "Cache has not allowed changes")
343 return False
317 changes = [pkg.name for pkg in cache.get_changes()]344 changes = [pkg.name for pkg in cache.get_changes()]
318 if len(changes) == 1:345 if len(changes) == 1:
319 logging.debug("found leaf package %s" % pkg.name)346 logging.debug("found leaf package %s" % pkg.name)
320 smallest_partition = changes347 smallest_partition = changes
321 break348 break
322 if len(changes) < len(smallest_partition):349 if len(changes) < len(smallest_partition):
323 logging.debug("found partition of size %s (%s)" % (len(changes), changes))350 logging.debug("found partition of size %s (%s)" % (
351 len(changes), changes))
324 smallest_partition = changes352 smallest_partition = changes
325 cache.clear()353 cache.clear()
326354
327 # write progress log information355 # write progress log information
328 if len(pkgs_to_upgrade) > 0:356 if len(pkgs_to_upgrade) > 0:
329 percent = (len(pkgs_to_upgrade)-len(to_upgrade)) / float(len(pkgs_to_upgrade))*100.0357 percent = ((len(pkgs_to_upgrade) - len(to_upgrade)) /
358 float(len(pkgs_to_upgrade)) * 100.0)
330 else:359 else:
331 percent = 100.0360 percent = 100.0
332 install_log.status_change(pkg=",".join(smallest_partition),361 install_log.status_change(pkg=",".join(smallest_partition),
@@ -343,19 +372,20 @@
343 if not res:372 if not res:
344 raise Exception("cache.commit() returned false")373 raise Exception("cache.commit() returned false")
345 cache.open()374 cache.open()
346 except Exception, e:375 except Exception as e:
347 logging.error(_("Installing the upgrades failed!"))376 logging.error(_("Installing the upgrades failed!"))
348 logging.error(_("error message: '%s'") % e)377 logging.error(_("error message: '%s'") % e)
349 logging.error(_("dpkg returned a error! See '%s' for details") % \378 logging.error(_("dpkg returned a error! See '%s' for details") %
350 logfile_dpkg)379 logfile_dpkg)
351 return False380 return False
352 to_upgrade = to_upgrade-set(smallest_partition)381 to_upgrade = to_upgrade - set(smallest_partition)
353 logging.debug("left to upgrade %s" % to_upgrade)382 logging.debug("left to upgrade %s" % to_upgrade)
354 if len(to_upgrade) == 0:383 if len(to_upgrade) == 0:
355 logging.info(_("All upgrades installed"))384 logging.info(_("All upgrades installed"))
356 break385 break
357 return True386 return True
358387
388
359def is_allowed_origin(ver, allowed_origins):389def is_allowed_origin(ver, allowed_origins):
360 if not ver:390 if not ver:
361 return False391 return False
@@ -365,6 +395,7 @@
365 return True395 return True
366 return False396 return False
367397
398
368def is_pkgname_in_blacklist(pkgname, blacklist):399def is_pkgname_in_blacklist(pkgname, blacklist):
369 for blacklist_regexp in blacklist:400 for blacklist_regexp in blacklist:
370 if re.match(blacklist_regexp, pkgname):401 if re.match(blacklist_regexp, pkgname):
@@ -372,6 +403,7 @@
372 return True403 return True
373 return False404 return False
374405
406
375def check_changes_for_sanity(cache, allowed_origins, blacklist):407def check_changes_for_sanity(cache, allowed_origins, blacklist):
376 if cache._depcache.broken_count != 0:408 if cache._depcache.broken_count != 0:
377 return False409 return False
@@ -392,33 +424,39 @@
392 ignore_require_restart = apt_pkg.config.find_b(424 ignore_require_restart = apt_pkg.config.find_b(
393 "Unattended-Upgrade::IgnoreAppsRequireRestart", False)425 "Unattended-Upgrade::IgnoreAppsRequireRestart", False)
394 if (pkg.marked_upgrade and426 if (pkg.marked_upgrade and
395 ignore_require_restart == False and427 ignore_require_restart is False and
396 pkg.candidate.record.get("Upgrade-Requires") == "app-restart"):428 pkg.candidate.record.get("Upgrade-Requires") == "app-restart"):
397 logging.debug("pkg '%s' requires app-restart, not safe to upgrade unattended")429 logging.debug("pkg '%s' requires app-restart, not safe to "
430 "upgrade unattended")
398 return False431 return False
399 return True432 return True
400433
434
401def pkgname_from_deb(debfile):435def pkgname_from_deb(debfile):
402 # FIXME: add error checking here436 # FIXME: add error checking here
403 try:437 try:
404 control = apt_inst.DebFile(debfile).control.extractdata("control")438 control = apt_inst.DebFile(debfile).control.extractdata("control")
405 sections = apt_pkg.TagSection(control)439 sections = apt_pkg.TagSection(control)
406 return sections["Package"]440 return sections["Package"]
407 except (IOError, SystemError), e:441 except (IOError, SystemError) as e:
408 logging.error("failed to read deb file '%s' (%s)" % (debfile, e))442 logging.error("failed to read deb file '%s' (%s)" % (debfile, e))
409 # dumb fallback443 # dumb fallback
410 return debfile.split("_")[0]444 return debfile.split("_")[0]
411445
446
412def get_md5sum_for_file_in_deb(deb_file, conf_file):447def get_md5sum_for_file_in_deb(deb_file, conf_file):
413 dpkg_cmd = ["dpkg-deb","--fsys-tarfile", deb_file]448 dpkg_cmd = ["dpkg-deb", "--fsys-tarfile", deb_file]
414 tar_cmd = ["tar","-x","-O", "-f","-", "."+conf_file]449 tar_cmd = ["tar", "-x", "-O", "-f", "-", "." + conf_file]
415 md5_cmd = ["md5sum"]450 md5_cmd = ["md5sum"]
416 dpkg_p = Popen(dpkg_cmd, stdout=PIPE)451 dpkg_p = Popen(dpkg_cmd, stdout=PIPE)
417 tar_p = Popen(tar_cmd, stdin=dpkg_p.stdout, stdout=PIPE)452 tar_p = Popen(tar_cmd, stdin=dpkg_p.stdout, stdout=PIPE,
418 md5_p = Popen(md5_cmd, stdin=tar_p.stdout, stdout=PIPE)453 universal_newlines=True)
454 md5_p = Popen(md5_cmd, stdin=tar_p.stdout, stdout=PIPE,
455 universal_newlines=True)
419 pkg_md5sum = md5_p.communicate()[0].split()[0]456 pkg_md5sum = md5_p.communicate()[0].split()[0]
420 return pkg_md5sum457 return pkg_md5sum
421458
459
422# prefix is *only* needed for the build-in tests460# prefix is *only* needed for the build-in tests
423def conffile_prompt(destFile, prefix=""):461def conffile_prompt(destFile, prefix=""):
424 logging.debug("check_conffile_prompt('%s')" % destFile)462 logging.debug("check_conffile_prompt('%s')" % destFile)
@@ -426,7 +464,7 @@
426464
427 # get the conffiles for the /var/lib/dpkg/status file465 # get the conffiles for the /var/lib/dpkg/status file
428 status_file = apt_pkg.config.find("Dir::State::status")466 status_file = apt_pkg.config.find("Dir::State::status")
429 tagfile = apt_pkg.TagFile(open(status_file,"r"))467 tagfile = apt_pkg.TagFile(open(status_file, "r"))
430 conffiles = ""468 conffiles = ""
431 for section in tagfile:469 for section in tagfile:
432 if section.get("Package") == pkgname:470 if section.get("Package") == pkgname:
@@ -440,21 +478,22 @@
440 pkg_conffiles = ""478 pkg_conffiles = ""
441 deb = apt_inst.DebFile(destFile)479 deb = apt_inst.DebFile(destFile)
442 try:480 try:
443 pkg_conffiles = deb.control.extractdata("conffiles").strip()481 pkg_conffiles = deb.control.extractdata("conffiles").strip().decode(
482 "utf-8")
444 except LookupError as e:483 except LookupError as e:
445 logging.debug("No conffiles in deb '%s' (%s)" % (destFile, e))484 logging.debug("No conffiles in deb '%s' (%s)" % (destFile, e))
446485
447 # Conffiles:486 # Conffiles:
448 # /etc/bash_completion.d/m-a c7780fab6b14d75ca54e11e992a6c11c487 # /etc/bash_completion.d/m-a c7780fab6b14d75ca54e11e992a6c11c
449 dpkg_status_conffiles = {}488 dpkg_status_conffiles = {}
450 for line in string.split(conffiles,"\n"):489 for line in conffiles.splitlines():
451 # ignore empty lines490 # ignore empty lines
452 line = string.strip(line)491 line = line.strip()
453 if not line:492 if not line:
454 continue493 continue
455 # show what we do494 # show what we do
456 logging.debug("conffile line: '%s'", line)495 logging.debug("conffile line: '%s'", line)
457 l = string.split(line)496 l = line.split()
458 conf_file = l[0]497 conf_file = l[0]
459 md5 = l[1]498 md5 = l[1]
460 if len(l) > 2:499 if len(l) > 2:
@@ -462,13 +501,13 @@
462 else:501 else:
463 obs = None502 obs = None
464 # ignore if conffile is obsolete or does not exist503 # ignore if conffile is obsolete or does not exist
465 if obs == "obsolete" or not os.path.exists(prefix+conf_file):504 if obs == "obsolete" or not os.path.exists(prefix + conf_file):
466 continue505 continue
467 # ignore state "newconffile" until its clearer if there506 # ignore state "newconffile" until its clearer if there
468 # might be a dpkg prompt (LP: #936870)507 # might be a dpkg prompt (LP: #936870)
469 if md5 == "newconffile":508 if md5 == "newconffile":
470 continue509 continue
471 if (not pkg_conffiles or 510 if (not pkg_conffiles or
472 not conf_file in pkg_conffiles.split("\n")):511 not conf_file in pkg_conffiles.split("\n")):
473 logging.debug("'%s' not in package conffiles '%s'" % (512 logging.debug("'%s' not in package conffiles '%s'" % (
474 conf_file, pkg_conffiles))513 conf_file, pkg_conffiles))
@@ -476,7 +515,8 @@
476 # record for later515 # record for later
477 dpkg_status_conffiles[conf_file] = md5516 dpkg_status_conffiles[conf_file] = md5
478 # test against the installed file517 # test against the installed file
479 current_md5 = apt_pkg.md5sum(open(prefix+conf_file).read())518 with open(prefix + conf_file, 'rb') as fb:
519 current_md5 = apt_pkg.md5sum(fb)
480 logging.debug("current md5: %s" % current_md5)520 logging.debug("current md5: %s" % current_md5)
481 # hashes are the same, no conffile prompt521 # hashes are the same, no conffile prompt
482 if current_md5 == md5:522 if current_md5 == md5:
@@ -484,7 +524,7 @@
484 # calculate md5sum from the deb (may take a bit)524 # calculate md5sum from the deb (may take a bit)
485 pkg_md5sum = get_md5sum_for_file_in_deb(destFile, conf_file)525 pkg_md5sum = get_md5sum_for_file_in_deb(destFile, conf_file)
486 logging.debug("pkg_md5sum: %s" % pkg_md5sum)526 logging.debug("pkg_md5sum: %s" % pkg_md5sum)
487 # the md5sum in the deb is unchanged, this will not 527 # the md5sum in the deb is unchanged, this will not
488 # trigger a conffile prompt528 # trigger a conffile prompt
489 if pkg_md5sum == md5:529 if pkg_md5sum == md5:
490 continue530 continue
@@ -493,18 +533,19 @@
493 # and that will trigger a conffile prompt, we can533 # and that will trigger a conffile prompt, we can
494 # stop processing at this point and just return True534 # stop processing at this point and just return True
495 return True535 return True
496 536
497 # now check if there are conffiles in the pkg that where not there537 # now check if there are conffiles in the pkg that where not there
498 # in the previous version in the dpkg status file538 # in the previous version in the dpkg status file
499 if pkg_conffiles:539 if pkg_conffiles:
500 for conf_file in pkg_conffiles.split("\n"):540 for conf_file in pkg_conffiles.split("\n"):
501 if (not conf_file in dpkg_status_conffiles and541 if (not conf_file in dpkg_status_conffiles and
502 os.path.exists(prefix+conf_file)):542 os.path.exists(prefix + conf_file)):
503 logging.debug("found conffile '%s' in new pkg but on dpkg "543 logging.debug("found conffile '%s' in new pkg but on dpkg "
504 "status" % conf_file)544 "status" % conf_file)
505 pkg_md5sum = get_md5sum_for_file_in_deb(destFile, conf_file)545 pkg_md5sum = get_md5sum_for_file_in_deb(destFile, conf_file)
506 if pkg_md5sum != apt_pkg.md5sum(open(prefix+conf_file).read()):546 with open(prefix + conf_file, 'rb') as fp:
507 return True547 if pkg_md5sum != apt_pkg.md5sum(fp):
548 return True
508 return False549 return False
509550
510551
@@ -514,7 +555,7 @@
514 options = apt_pkg.config.value_list("DPkg::Options")555 options = apt_pkg.config.value_list("DPkg::Options")
515 for option in map(string.strip, options):556 for option in map(string.strip, options):
516 if (option == "--force-confold" or557 if (option == "--force-confold" or
517 option == "--force-confnew"):558 option == "--force-confnew"):
518 return False559 return False
519 return True560 return True
520561
@@ -535,7 +576,7 @@
535def wrap(t, width=70, subsequent_indent=""):576def wrap(t, width=70, subsequent_indent=""):
536 out = ""577 out = ""
537 for s in t.split():578 for s in t.split():
538 if (len(out)-out.rfind("\n")) + len(s) > width:579 if (len(out) - out.rfind("\n")) + len(s) > width:
539 out += "\n" + subsequent_indent580 out += "\n" + subsequent_indent
540 out += s + " "581 out += s + " "
541 return out582 return out
@@ -554,8 +595,9 @@
554595
555596
556def _send_mail_using_mailx(to_address, subject, body):597def _send_mail_using_mailx(to_address, subject, body):
557 mail = subprocess.Popen([598 mail = subprocess.Popen(
558 MAIL_BINARY, "-s", subject, to_address], stdin=subprocess.PIPE)599 [MAIL_BINARY, "-s", subject, to_address],
600 stdin=subprocess.PIPE, universal_newlines=True)
559 mail.stdin.write(body)601 mail.stdin.write(body)
560 mail.stdin.close()602 mail.stdin.close()
561 ret = mail.wait()603 ret = mail.wait()
@@ -565,14 +607,15 @@
565def _send_mail_using_sendmail(to_address, subject, body):607def _send_mail_using_sendmail(to_address, subject, body):
566 # format as a proper mail608 # format as a proper mail
567 msg = Message()609 msg = Message()
568 charset = email.Charset.Charset("utf-8")610 charset = email.charset.Charset("utf-8")
569 charset.body_encoding = email.Charset.QP611 charset.body_encoding = email.charset.QP
570 msg.set_charset(charset)612 msg.set_charset(charset)
571 msg.set_payload(body)613 msg.set_payload(body)
572 msg['Subject'] = subject614 msg['Subject'] = subject
573 msg['To'] = to_address615 msg['To'] = to_address
574 sendmail = subprocess.Popen(616 sendmail = subprocess.Popen(
575 [SENDMAIL_BINARY, "-oi", "-t"], stdin=subprocess.PIPE)617 [SENDMAIL_BINARY, "-oi", "-t"],
618 stdin=subprocess.PIPE, universal_newlines=True)
576 sendmail.stdin.write(msg.as_string())619 sendmail.stdin.write(msg.as_string())
577 sendmail.stdin.close()620 sendmail.stdin.close()
578 ret = sendmail.wait()621 ret = sendmail.wait()
@@ -594,16 +637,18 @@
594 # mails on on errors, just exit here637 # mails on on errors, just exit here
595 if (res and638 if (res and
596 apt_pkg.config.find_b("Unattended-Upgrade::MailOnlyOnError", False)):639 apt_pkg.config.find_b("Unattended-Upgrade::MailOnlyOnError", False)):
597 return640 return
598 # Check if reboot-required flag is present641 # Check if reboot-required flag is present
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))
600 if os.path.isfile(REBOOT_REQUIRED_FILE):643 if os.path.isfile(REBOOT_REQUIRED_FILE):
601 subject = _("[reboot required] unattended-upgrades result for '%s'") % host()644 subject = _(
645 "[reboot required] unattended-upgrades result for '%s'") % host()
602 else:646 else:
603 subject = _("unattended-upgrades result for '%s'") % host()647 subject = _("unattended-upgrades result for '%s'") % host()
604 body = _("Unattended upgrade returned: %s\n\n") % res648 body = _("Unattended upgrade returned: %s\n\n") % res
605 if os.path.isfile(REBOOT_REQUIRED_FILE):649 if os.path.isfile(REBOOT_REQUIRED_FILE):
606 body += _("Warning: A reboot is required to complete this upgrade.\n\n")650 body += _(
651 "Warning: A reboot is required to complete this upgrade.\n\n")
607 body += _("Packages that are upgraded:\n")652 body += _("Packages that are upgraded:\n")
608 body += " " + wrap(pkgs, 70, " ")653 body += " " + wrap(pkgs, 70, " ")
609 body += "\n"654 body += "\n"
@@ -613,15 +658,16 @@
613 body += "\n"658 body += "\n"
614 body += "\n"659 body += "\n"
615 if os.path.exists(logfile_dpkg):660 if os.path.exists(logfile_dpkg):
616 body += _("Package installation log:")+"\n"661 body += _("Package installation log:") + "\n"
617 body += open(logfile_dpkg).read()662 with open(logfile_dpkg) as fp:
663 body += fp.read()
618 body += "\n\n"664 body += "\n\n"
619 body += _("Unattended-upgrades log:\n")665 body += _("Unattended-upgrades log:\n")
620 body += mem_log.getvalue()666 body += mem_log.getvalue()
621667
622 # ensure that the message a utf8 encoded string668 # python2 needs this as utf8 encoded string (not unicode)
623 if type(body) is unicode:669 if sys.version < '3':
624 body= body.encode("utf-8", "replace")670 body = body.encode("utf-8")
625671
626 if os.path.exists(SENDMAIL_BINARY):672 if os.path.exists(SENDMAIL_BINARY):
627 ret = _send_mail_using_sendmail(to_email, subject, body)673 ret = _send_mail_using_sendmail(to_email, subject, body)
@@ -634,15 +680,16 @@
634 logging.debug("mail returned: %s" % ret)680 logging.debug("mail returned: %s" % ret)
635681
636682
637def do_install(cache, pkgs_to_upgrade, options, logfile_dpkg):683def do_install(cache, pkgs_to_upgrade, blacklisted_pkgs, options,
684 logfile_dpkg):
638 # set debconf to NON_INTERACTIVE, redirect output685 # set debconf to NON_INTERACTIVE, redirect output
639 os.putenv("DEBIAN_FRONTEND","noninteractive");686 os.putenv("DEBIAN_FRONTEND", "noninteractive")
640 setup_apt_listchanges()687 setup_apt_listchanges()
641 688
642 # redirect to log689 # redirect to log
643 REDIRECT_INPUT = os.devnull690 REDIRECT_INPUT = os.devnull
644 fd = os.open(REDIRECT_INPUT, os.O_RDWR)691 fd = os.open(REDIRECT_INPUT, os.O_RDWR)
645 os.dup2(fd,0)692 os.dup2(fd, 0)
646693
647 logging.info(_("Writing dpkg log to '%s'") % logfile_dpkg)694 logging.info(_("Writing dpkg log to '%s'") % logfile_dpkg)
648695
@@ -651,21 +698,25 @@
651 old_stdout = 1698 old_stdout = 1
652 old_stderr = 2699 old_stderr = 2
653 else:700 else:
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)
655 old_stdout = os.dup(1)702 old_stdout = os.dup(1)
656 old_stderr = os.dup(2)703 old_stderr = os.dup(2)
657 os.dup2(fd,1)704 os.dup2(fd, 1)
658 os.dup2(fd,2)705 os.dup2(fd, 2)
659706
660 try:707 try:
661 if (options.minimal_upgrade_steps or 708 if (options.minimal_upgrade_steps or
662 # COMPAT with the mispelling709 # COMPAT with the mispelling
663 apt_pkg.config.find_b("Unattended-Upgrades::MinimalSteps", False) or710 apt_pkg.config.find_b(
664 apt_pkg.config.find_b("Unattended-Upgrade::MinimalSteps", False)):711 "Unattended-Upgrades::MinimalSteps", False) or
665 open("/var/run/unattended-upgrades.pid", "w").write("%s" % os.getpid())712 apt_pkg.config.find_b(
713 "Unattended-Upgrade::MinimalSteps", False)):
714 with open("/var/run/unattended-upgrades.pid", "w") as fp:
715 fp.write("%s" % os.getpid())
666 # try upgrade all "pkgs" in minimal steps716 # try upgrade all "pkgs" in minimal steps
667 pkg_install_success = upgrade_in_minimal_steps(717 pkg_install_success = upgrade_in_minimal_steps(
668 cache, [pkg.name for pkg in pkgs_to_upgrade], logfile_dpkg)718 cache, [pkg.name for pkg in pkgs_to_upgrade], logfile_dpkg,
719 blacklisted_pkgs)
669 else:720 else:
670 pkg_install_success = upgrade_normal(721 pkg_install_success = upgrade_normal(
671 cache, [pkg.name for pkg in pkgs_to_upgrade], logfile_dpkg)722 cache, [pkg.name for pkg in pkgs_to_upgrade], logfile_dpkg)
@@ -685,15 +736,16 @@
685 apt_pkg.config.clear("Unattended-Upgrade")736 apt_pkg.config.clear("Unattended-Upgrade")
686 # read rootdir (taken from apt.Cache, but we need to run it737 # read rootdir (taken from apt.Cache, but we need to run it
687 # here before the cache gets initialized738 # here before the cache gets initialized
688 if os.path.exists(rootdir+"/etc/apt/apt.conf"):739 if os.path.exists(rootdir + "/etc/apt/apt.conf"):
689 apt_pkg.read_config_file(apt_pkg.config,740 apt_pkg.read_config_file(apt_pkg.config,
690 rootdir + "/etc/apt/apt.conf")741 rootdir + "/etc/apt/apt.conf")
691 if os.path.isdir(rootdir+"/etc/apt/apt.conf.d"):742 if os.path.isdir(rootdir + "/etc/apt/apt.conf.d"):
692 apt_pkg.read_config_dir(apt_pkg.config,743 apt_pkg.read_config_dir(apt_pkg.config,
693 rootdir + "/etc/apt/apt.conf.d")744 rootdir + "/etc/apt/apt.conf.d")
694745
746
695def _get_logdir():747def _get_logdir():
696 logdir= apt_pkg.config.find_dir(748 logdir = apt_pkg.config.find_dir(
697 "Unattended-Upgrade::LogDir",749 "Unattended-Upgrade::LogDir",
698 # COMPAT only750 # COMPAT only
699 apt_pkg.config.find_dir("APT::UnattendedUpgrades::LogDir",751 apt_pkg.config.find_dir("APT::UnattendedUpgrades::LogDir",
@@ -722,7 +774,6 @@
722 logging.basicConfig(level=logging.INFO,774 logging.basicConfig(level=logging.INFO,
723 format='%(asctime)s %(levelname)s %(message)s',775 format='%(asctime)s %(levelname)s %(message)s',
724 filename=logfile)776 filename=logfile)
725
726 # additional logging777 # additional logging
727 logger = logging.getLogger()778 logger = logging.getLogger()
728 mem_log = StringIO()779 mem_log = StringIO()
@@ -734,7 +785,11 @@
734 mem_log_handler = logging.StreamHandler(mem_log)785 mem_log_handler = logging.StreamHandler(mem_log)
735 logger.addHandler(mem_log_handler)786 logger.addHandler(mem_log_handler)
736 return mem_log787 return mem_log
737 788
789
790def get_blacklisted_pkgs():
791 return apt_pkg.config.value_list("Unattended-Upgrade::Package-Blacklist")
792
738793
739def main(options, rootdir=""):794def main(options, rootdir=""):
740795
@@ -749,24 +804,27 @@
749 allowed_origins = get_allowed_origins()804 allowed_origins = get_allowed_origins()
750805
751 # pkgs that are (for some reason) not save to install806 # pkgs that are (for some reason) not save to install
752 blacklisted_pkgs = apt_pkg.config.value_list("Unattended-Upgrade::Package-Blacklist")807 blacklisted_pkgs = get_blacklisted_pkgs()
753 logging.info(_("Initial blacklisted packages: %s"), " ".join(blacklisted_pkgs))808 logging.info(_("Initial blacklisted packages: %s"),
809 " ".join(blacklisted_pkgs))
754 logging.info(_("Starting unattended upgrades script"))810 logging.info(_("Starting unattended upgrades script"))
755811
756 # display available origin812 # display available origin
757 logging.info(_("Allowed origins are: %s") % map(str,allowed_origins))813 logging.info(_("Allowed origins are: %s") % allowed_origins)
758814
759 # check if the journal is dirty and if so, take emergceny action815 # check if the journal is dirty and if so, take emergceny action
760 # the alternative is to leave the system potentially unsecure until816 # the alternative is to leave the system potentially unsecure until
761 # the user comes in and fixes817 # the user comes in and fixes
762 if (is_dpkg_journal_dirty() and818 if (is_dpkg_journal_dirty() and
763 apt_pkg.config.find_b("Unattended-Upgrade::AutoFixInterruptedDpkg", True)):819 apt_pkg.config.find_b(
820 "Unattended-Upgrade::AutoFixInterruptedDpkg", True)):
764 # ensure the dpkg database is not already locked (LP: #754330)821 # ensure the dpkg database is not already locked (LP: #754330)
765 admindir = os.path.dirname(apt_pkg.config.find("Dir::State::Status"))822 admindir = os.path.dirname(apt_pkg.config.find("Dir::State::Status"))
766 lockfd = apt_pkg.get_lock(os.path.join(admindir, "lock"), False)823 lockfd = apt_pkg.get_lock(os.path.join(admindir, "lock"), False)
767 if lockfd > 0:824 if lockfd > 0:
768 logging.warning(_("Unclean dpkg state detected, trying to correct"))825 logging.warning(
769 print _("Unclean dpkg state detected, trying to correct")826 _("Unclean dpkg state detected, trying to correct"))
827 print(_("Unclean dpkg state detected, trying to correct"))
770 env = copy.copy(os.environ)828 env = copy.copy(os.environ)
771 env["DEBIAN_FRONTEND"] = "noninteractive"829 env["DEBIAN_FRONTEND"] = "noninteractive"
772 try:830 try:
@@ -777,22 +835,23 @@
777 output = e.output835 output = e.output
778 logging.warning(_("dpkg --configure -a output:\n%s" % output))836 logging.warning(_("dpkg --configure -a output:\n%s" % output))
779 else:837 else:
780 logging.debug("Unclean dpkg state, but locked, another package manager working?")838 logging.debug("Unclean dpkg state, but locked, another package "
781 839 "manager working?")
840
782 # check and get lock841 # check and get lock
783 try:842 try:
784 apt_pkg.pkgsystem_lock()843 apt_pkg.pkgsystem_lock()
785 except SystemError, e:844 except SystemError as e:
786 logging.error(_("Lock could not be acquired (another package "845 logging.error(_("Lock could not be acquired (another package "
787 "manager running?)"))846 "manager running?)"))
788 print _("Cache lock can not be acquired, exiting")847 print(_("Cache lock can not be acquired, exiting"))
789 sys.exit(1)848 sys.exit(1)
790849
791 # get a cache850 # get a cache
792 cache = UnattendedUpgradesCache(rootdir=rootdir, 851 cache = UnattendedUpgradesCache(rootdir=rootdir,
793 allowed_origins=allowed_origins)852 allowed_origins=allowed_origins)
794 if cache._depcache.broken_count > 0:853 if cache._depcache.broken_count > 0:
795 print _("Cache has broken packages, exiting")854 print(_("Cache has broken packages, exiting"))
796 logging.error(_("Cache has broken packages, exiting"))855 logging.error(_("Cache has broken packages, exiting"))
797 sys.exit(1)856 sys.exit(1)
798 # speed things up with latest apt857 # speed things up with latest apt
@@ -802,13 +861,14 @@
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)
803 pkgs_to_upgrade = []862 pkgs_to_upgrade = []
804 pkgs_kept_back = []863 pkgs_kept_back = []
805 pkgs_auto_removable = set([pkg.name for pkg in cache 864 pkgs_auto_removable = set([pkg.name for pkg in cache
806 if pkg.is_auto_removable])865 if pkg.is_auto_removable])
807866
808 # now do the actual upgrade867 # now do the actual upgrade
809 for pkg in cache:868 for pkg in cache:
810 if options.debug and pkg.is_upgradable:869 if options.debug and pkg.is_upgradable:
811 logging.debug("Checking: %s (%s)" % (pkg.name, map(str, pkg.candidate.origins)))870 logging.debug("Checking: %s (%s)" % (
871 pkg.name, map(str, getattr(pkg.candidate, "origins", []))))
812 if (pkg.is_upgradable and872 if (pkg.is_upgradable and
813 not is_pkgname_in_blacklist(pkg.name, blacklisted_pkgs) and873 not is_pkgname_in_blacklist(pkg.name, blacklisted_pkgs) and
814 is_allowed_origin(pkg.candidate, allowed_origins)):874 is_allowed_origin(pkg.candidate, allowed_origins)):
@@ -818,7 +878,7 @@
818 blacklisted_pkgs):878 blacklisted_pkgs):
819 # add to packages to upgrade879 # add to packages to upgrade
820 pkgs_to_upgrade.append(pkg)880 pkgs_to_upgrade.append(pkg)
821 # re-eval pkgs_kept_back as the resolver may fail to 881 # re-eval pkgs_kept_back as the resolver may fail to
822 # directly upgrade a pkg, but that may work during882 # directly upgrade a pkg, but that may work during
823 # a subsequent operation, see debian bug #639840883 # a subsequent operation, see debian bug #639840
824 for pkgname in pkgs_kept_back:884 for pkgname in pkgs_kept_back:
@@ -830,17 +890,18 @@
830 logging.debug("sanity check failed")890 logging.debug("sanity check failed")
831 rewind_cache(cache, pkgs_to_upgrade)891 rewind_cache(cache, pkgs_to_upgrade)
832 pkgs_kept_back.append(pkg.name)892 pkgs_kept_back.append(pkg.name)
833 except SystemError, e:893 except SystemError as e:
834 # can't upgrade894 # can't upgrade
835 logging.warning(_("package '%s' upgradable but fails to be marked for upgrade (%s)") % (pkg.name, e))895 logging.warning(
896 _("package '%s' upgradable but fails to "
897 "be marked for upgrade (%s)") % (pkg.name, e))
836 rewind_cache(cache, pkgs_to_upgrade)898 rewind_cache(cache, pkgs_to_upgrade)
837 pkgs_kept_back.append(pkg.name)899 pkgs_kept_back.append(pkg.name)
838
839900
840 pkgs_to_upgrade.sort(key=lambda p: p.name)901 pkgs_to_upgrade.sort(key=lambda p: p.name)
841 pkgs = "\n".join([pkg.name for pkg in pkgs_to_upgrade])902 pkgs = "\n".join([pkg.name for pkg in pkgs_to_upgrade])
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)
843 904
844 # download what looks good905 # download what looks good
845 if options.debug:906 if options.debug:
846 fetcher = apt_pkg.Acquire(apt.progress.text.AcquireProgress())907 fetcher = apt_pkg.Acquire(apt.progress.text.AcquireProgress())
@@ -851,8 +912,8 @@
851 recs = cache._records912 recs = cache._records
852 pm = apt_pkg.PackageManager(cache._depcache)913 pm = apt_pkg.PackageManager(cache._depcache)
853 try:914 try:
854 pm.get_archives(fetcher,list,recs)915 pm.get_archives(fetcher, list, recs)
855 except SystemError, e:916 except SystemError as e:
856 logging.error(_("GetArchives() failed: '%s'") % e)917 logging.error(_("GetArchives() failed: '%s'") % e)
857 res = fetcher.run()918 res = fetcher.run()
858 logging.debug("fetch.run() result: %s" % res)919 logging.debug("fetch.run() result: %s" % res)
@@ -863,15 +924,19 @@
863 for item in fetcher.items:924 for item in fetcher.items:
864 logging.debug("%s" % item)925 logging.debug("%s" % item)
865 if item.status == item.STAT_ERROR:926 if item.status == item.STAT_ERROR:
866 print _("An error ocured: '%s'") % item.error_text927 print(_("An error ocured: '%s'") % item.error_text)
867 logging.error(_("An error ocured: '%s'") % item.error_text)928 logging.error(_("An error ocured: '%s'") % item.error_text)
868 if not item.complete:929 if not item.complete:
869 print _("The URI '%s' failed to download, aborting") % item.desc_uri930 print(_("The URI '%s' failed to download, aborting") %
870 logging.error(_("The URI '%s' failed to download, aborting") % item.desc_uri)931 item.desc_uri)
932 logging.error(_("The URI '%s' failed to download, aborting") %
933 item.desc_uri)
871 sys.exit(1)934 sys.exit(1)
872 if not os.path.exists(item.destfile):935 if not os.path.exists(item.destfile):
873 print _("Download finished, but file '%s' not there?!?" % item.destfile)936 print(_("Download finished, but file '%s' not there?!?" %
874 logging.error("Download finished, but file '%s' not there?!?" % item.destfile)937 item.destfile))
938 logging.error("Download finished, but file '%s' not "
939 "there?!?" % item.destfile)
875 sys.exit(1)940 sys.exit(1)
876 if not item.is_trusted:941 if not item.is_trusted:
877 blacklisted_pkgs.append(pkgname_from_deb(item.destfile))942 blacklisted_pkgs.append(pkgname_from_deb(item.destfile))
@@ -879,18 +944,21 @@
879 # skip package (means to re-run the whole marking again944 # skip package (means to re-run the whole marking again
880 # and making sure that the package will not be pulled in by945 # and making sure that the package will not be pulled in by
881 # some other package again!)946 # some other package again!)
882 # 947 #
883 # print to stdout to ensure that this message is part of948 # print to stdout to ensure that this message is part of
884 # the cron mail (only if no summary mail is requested)949 # the cron mail (only if no summary mail is requested)
885 email = apt_pkg.config.find("Unattended-Upgrade::Mail", "")950 email = apt_pkg.config.find("Unattended-Upgrade::Mail", "")
886 if not email:951 if not email:
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 "
953 "to be upgraded manually") % pkgname_from_deb(
954 item.destfile))
888 # log to the logfile955 # log to the logfile
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 "
957 "needs to be upgraded manually") %
958 pkgname_from_deb(item.destfile))
890 blacklisted_pkgs.append(pkgname_from_deb(item.destfile))959 blacklisted_pkgs.append(pkgname_from_deb(item.destfile))
891 pkgs_kept_back.append(pkgname_from_deb(item.destfile))960 pkgs_kept_back.append(pkgname_from_deb(item.destfile))
892961
893
894 # redo the selection about the packages to upgrade based on the new962 # redo the selection about the packages to upgrade based on the new
895 # blacklist963 # blacklist
896 logging.debug("blacklist: %s" % blacklisted_pkgs)964 logging.debug("blacklist: %s" % blacklisted_pkgs)
@@ -904,7 +972,7 @@
904 pkg.mark_upgrade()972 pkg.mark_upgrade()
905 if check_changes_for_sanity(cache, allowed_origins,973 if check_changes_for_sanity(cache, allowed_origins,
906 blacklisted_pkgs):974 blacklisted_pkgs):
907 pkgs_to_upgrade.append(pkg)975 pkgs_to_upgrade.append(pkg)
908 else:976 else:
909 if not (pkg.name in pkgs_kept_back):977 if not (pkg.name in pkgs_kept_back):
910 pkgs_kept_back.append(pkg.name)978 pkgs_kept_back.append(pkg.name)
@@ -916,23 +984,26 @@
916 logging.debug("dpkg is configured not to cause conffile prompts")984 logging.debug("dpkg is configured not to cause conffile prompts")
917985
918 # do auto-remove986 # do auto-remove
919 if apt_pkg.config.find_b("Unattended-Upgrade::Remove-Unused-Dependencies", False):987 if apt_pkg.config.find_b(
920 now_auto_removable = set([pkg.name for pkg in cache 988 "Unattended-Upgrade::Remove-Unused-Dependencies", False):
989 now_auto_removable = set([pkg.name for pkg in cache
921 if pkg.is_auto_removable])990 if pkg.is_auto_removable])
922 for pkgname in now_auto_removable-pkgs_auto_removable:991 for pkgname in now_auto_removable - pkgs_auto_removable:
923 logging.debug("marking %s for remove" % pkgname)992 logging.debug("marking %s for remove" % pkgname)
924 cache[pkgname].mark_delete()993 cache[pkgname].mark_delete()
925 logging.info(_("Packages that are auto removed: '%s'") %994 logging.info(_("Packages that are auto removed: '%s'") %
926 " ".join(now_auto_removable-pkgs_auto_removable))995 " ".join(now_auto_removable - pkgs_auto_removable))
927996
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" % (
998 cache._depcache.inst_count, cache._depcache.del_count,
999 cache._depcache.broken_count))
9291000
930 # exit if there is nothing to do and nothing to report1001 # exit if there is nothing to do and nothing to report
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):
932 logging.info(_("No packages found that can be upgraded unattended"))1003 logging.info(_("No packages found that can be upgraded unattended"))
933 return1004 return
9341005
935 # check if its configured for install on shutdown, if so, the 1006 # check if its configured for install on shutdown, if so, the
936 # environment UNATTENDED_UPGRADES_FORCE_INSTALL_ON_SHUTDOWN will1007 # environment UNATTENDED_UPGRADES_FORCE_INSTALL_ON_SHUTDOWN will
937 # be set by the unatteded-upgrades-shutdown script1008 # be set by the unatteded-upgrades-shutdown script
938 if (not "UNATTENDED_UPGRADES_FORCE_INSTALL_ON_SHUTDOWN" in os.environ and1009 if (not "UNATTENDED_UPGRADES_FORCE_INSTALL_ON_SHUTDOWN" in os.environ and
@@ -944,7 +1015,7 @@
944 # check if we are in dry-run mode1015 # check if we are in dry-run mode
945 if options.dry_run:1016 if options.dry_run:
946 logging.info("Option --dry-run given, *not* performing real actions")1017 logging.info("Option --dry-run given, *not* performing real actions")
947 apt_pkg.config.set("Debug::pkgDPkgPM","1")1018 apt_pkg.config.set("Debug::pkgDPkgPM", "1")
9481019
949 # do the install based on the new list of pkgs1020 # do the install based on the new list of pkgs
950 pkgs = " ".join([pkg.name for pkg in pkgs_to_upgrade])1021 pkgs = " ".join([pkg.name for pkg in pkgs_to_upgrade])
@@ -964,7 +1035,7 @@
964 shutdown_lock = apt_pkg.get_lock("/var/run/unattended-upgrades.lock")1035 shutdown_lock = apt_pkg.get_lock("/var/run/unattended-upgrades.lock")
965 # do install1036 # do install
966 pkg_install_success = do_install(1037 pkg_install_success = do_install(
967 cache, pkgs_to_upgrade, options, logfile_dpkg)1038 cache, pkgs_to_upgrade, blacklisted_pkgs, options, logfile_dpkg)
9681039
969 # send a mail (if needed)1040 # send a mail (if needed)
970 if not options.dry_run:1041 if not options.dry_run:
@@ -972,17 +1043,18 @@
972 pkgs, pkg_install_success, pkgs_kept_back, mem_log, logfile_dpkg)1043 pkgs, pkg_install_success, pkgs_kept_back, mem_log, logfile_dpkg)
9731044
974 # auto-reboot (if required and the config for this is set1045 # auto-reboot (if required and the config for this is set
975 if (apt_pkg.config.find_b("Unattended-Upgrade::Automatic-Reboot", False) and1046 if (apt_pkg.config.find_b(
1047 "Unattended-Upgrade::Automatic-Reboot", False) and
976 os.path.exists(REBOOT_REQUIRED_FILE)):1048 os.path.exists(REBOOT_REQUIRED_FILE)):
977 if shutdown_lock > 0:1049 if shutdown_lock > 0:
978 os.close(shutdown_lock)1050 os.close(shutdown_lock)
979 logging.warning("Found %s, rebooting" % REBOOT_REQUIRED_FILE)1051 logging.warning("Found %s, rebooting" % REBOOT_REQUIRED_FILE)
980 subprocess.call(["/sbin/reboot"])1052 subprocess.call(["/sbin/reboot"])
981 1053
9821054
983if __name__ == "__main__":1055if __name__ == "__main__":
984 localesApp="unattended-upgrades"1056 localesApp = "unattended-upgrades"
985 localesDir="/usr/share/locale"1057 localesDir = "/usr/share/locale"
986 gettext.bindtextdomain(localesApp, localesDir)1058 gettext.bindtextdomain(localesApp, localesDir)
987 gettext.textdomain(localesApp)1059 gettext.textdomain(localesApp)
9881060
@@ -996,19 +1068,20 @@
996 help=_("Simulation, download but do not install"))1068 help=_("Simulation, download but do not install"))
997 parser.add_option("", "--minimal_upgrade_steps",1069 parser.add_option("", "--minimal_upgrade_steps",
998 action="store_true", default=False,1070 action="store_true", default=False,
999 help=_("Upgrade in minimal steps (and allow interrupting with SIGINT"))1071 help=_("Upgrade in minimal steps (and allow "
1072 "interrupting with SIGINT"))
1000 (options, args) = parser.parse_args()1073 (options, args) = parser.parse_args()
10011074
1002 if os.getuid() != 0:1075 if os.getuid() != 0:
1003 print _("You need to be root to run this application")1076 print(_("You need to be root to run this application"))
1004 sys.exit(1)1077 sys.exit(1)
10051078
1006 # nice & ionce1079 # nice & ionce
1007 os.nice(19)1080 os.nice(19)
1008 IONICE="/usr/bin/ionice"1081 IONICE = "/usr/bin/ionice"
1009 if os.path.exists(IONICE):1082 if os.path.exists(IONICE):
1010 with open(os.devnull, "w") as fstderr:1083 with open(os.devnull, "w") as fstderr:
1011 subprocess.call([IONICE, "-c3", "-p",str(os.getpid())],1084 subprocess.call([IONICE, "-c3", "-p", str(os.getpid())],
1012 stderr=fstderr)1085 stderr=fstderr)
10131086
1014 # ensure that we are not killed when the terminal goes away e.g. on1087 # ensure that we are not killed when the terminal goes away e.g. on
10151088
=== modified file 'unattended-upgrade-shutdown'
--- unattended-upgrade-shutdown 2012-04-26 11:40:46 +0000
+++ unattended-upgrade-shutdown 2012-10-08 16:08:26 +0000
@@ -1,4 +1,4 @@
1#!/usr/bin/python1#!/usr/bin/python3
2# Copyright (c) 2009 Canonical Ltd2# Copyright (c) 2009 Canonical Ltd
3#3#
4# AUTHOR:4# AUTHOR:
@@ -141,8 +141,8 @@
141 os.kill(pid, signal.SIGUSR1)141 os.kill(pid, signal.SIGUSR1)
142 # show log142 # show log
143 log_progress()143 log_progress()
144 time.sleep(5)144 time.sleep(5)
145 if (time.time() - start_time) > options.delay*60:145 if (time.time() - start_time) > options.delay*60:
146 logging.warning(_("Giving up on lockfile after %s delay") % options.delay)146 logging.warning(_("Giving up on lockfile after %s delay") % options.delay)
147 sys.exit(1)147 sys.exit(1)
148 148

Subscribers

People subscribed via source and target branches

to all changes: