diff -Nru unattended-upgrades-0.90ubuntu0.1/data/50unattended-upgrades.Ubuntu unattended-upgrades-0.90ubuntu0.10/data/50unattended-upgrades.Ubuntu --- unattended-upgrades-0.90ubuntu0.1/data/50unattended-upgrades.Ubuntu 2016-10-11 17:53:52.000000000 +0000 +++ unattended-upgrades-0.90ubuntu0.10/data/50unattended-upgrades.Ubuntu 2017-05-03 01:41:12.000000000 +0000 @@ -2,6 +2,11 @@ Unattended-Upgrade::Allowed-Origins { "${distro_id}:${distro_codename}"; "${distro_id}:${distro_codename}-security"; + // Extended Security Maintenance; doesn't necessarily exist for + // every release and this system may not have it installed, but if + // available, the policy for updates is such that unattended-upgrades + // should also install from here by default. + "${distro_id}ESM:${distro_codename}"; // "${distro_id}:${distro_codename}-updates"; // "${distro_id}:${distro_codename}-proposed"; // "${distro_id}:${distro_codename}-backports"; diff -Nru unattended-upgrades-0.90ubuntu0.1/debian/changelog unattended-upgrades-0.90ubuntu0.10/debian/changelog --- unattended-upgrades-0.90ubuntu0.1/debian/changelog 2016-10-11 20:02:24.000000000 +0000 +++ unattended-upgrades-0.90ubuntu0.10/debian/changelog 2019-01-18 18:35:05.000000000 +0000 @@ -1,3 +1,98 @@ +unattended-upgrades (0.90ubuntu0.10) xenial-security; urgency=medium + + * No change rebuild in the -security pocket (See LP #1686470) + + -- Marc Deslauriers Fri, 18 Jan 2019 13:34:27 -0500 + +unattended-upgrades (0.90ubuntu0.9) xenial; urgency=medium + + * unattended-upgrade: Do not reboot during a dry-run. (LP: #1269177) + + -- Brian Murray Tue, 19 Dec 2017 14:51:05 -0800 + +unattended-upgrades (0.90ubuntu0.8) xenial; urgency=medium + + * Do not mark packages for deletion / autoremoval if unattended-upgrades is + being run in dry-run mode. (LP: #1544942) + + -- Brian Murray Mon, 18 Sep 2017 13:36:57 -0700 + +unattended-upgrades (0.90ubuntu0.7) xenial; urgency=medium + + * Cherry-pick 2e5deed, f26edb4 from upstream to add support for a + --download-only option, enabling us to download updates at a random time + of day by default but apply them predictably in the 6am-7am window. + LP: #1686470. + + -- Steve Langasek Mon, 31 Jul 2017 12:34:37 -0700 + +unattended-upgrades (0.90ubuntu0.6) xenial; urgency=medium + + * Add UbuntuESM to the list of sources automatically upgraded from by + default. LP: #1687129. + + -- Steve Langasek Tue, 02 May 2017 21:41:25 -0400 + +unattended-upgrades (0.90ubuntu0.5) xenial; urgency=medium + + * Complete the solution for the unattended-upgrades.service unit not + correctly working (LP: #1654600): + - d/rules : Remove the override_dh_installinit. The stop option is no longer + available so the command falls back to default. This is the normal + behavior so the override is not required + - d/unattended-upgrades.init : Add Default-Start runlevels, otherwise the + unattended-upgrades.service unit cannot be enabled on boot + - d/postinst : Cleanup the stop symlinks created by the wrong + override_dh_installinit. Without that, the systemd unit cannot be + enabled correctly. + Force disable the service before deb-systemd-helper runs so the old + symlink is not left dangling (workaround for Debian Bug #797108). + Force enable and start of the systemd unit to work around Debian Bug #797108 + which fails to enable systemd units correctly when WantedBy= statement + is changed which is the case here. + Both systemctl enable AND start are needed as enable --now fails on + Xenial. + - d/unattended-upgrades.service : Fix the service so it runs correctly on + shutdown : + Remove DefaultDependencies=no : Breaks normal shutdown dependencies + Set After= to network.target and local-fs.target. Since our service is + now ExecStop, it will run before network and local-fs become unavailable. + Add RequiresMountsFor=/var/log /var/run /var/lib /boot : Necessary if + /var is a separate file system. Set WantedBy= to multi-user.target + - Add DEP8 tests to verify the following : + Verify that the unattended-upgrades.service unit is enabled and started. + Verify that InstallOnShutdown works when configured. + + -- Louis Bouchard Fri, 21 Apr 2017 16:47:52 +0200 + +unattended-upgrades (0.90ubuntu0.4) xenial; urgency=medium + + * The systemd unit needs to be an ExecStop since it is is activated on + shutdown. Otherwise, it will get scheduled after completion of + the local-fs.target. In the case where /var is a separate + filesystem, unattended-upgrade-shutdown will hang until timeout + since /var/run is expected but no longer there. Also added + TimeoutStopSec=900 used in other released.(LP: #1654600) + + -- Louis Bouchard Fri, 03 Mar 2017 15:27:31 +0100 + +unattended-upgrades (0.90ubuntu0.3) xenial-proposed; urgency=medium + + * Ensure that network and local filesystems are available when running + unattended-upgrades during shutdown mode. (LP: #1618900) + + -- Brian Murray Wed, 14 Dec 2016 13:38:32 -0800 + +unattended-upgrades (0.90ubuntu0.2) xenial-proposed; urgency=medium + + * Create logfile_dpkg if it does not exist so that the file can be read + later, thereby preventing a FileNotFound crash. (LP: #1590321) + * Create the directory /var/lib/apt/periodic/, if it does not exist, so that + we don't receive a Traceback when trying to write a stampfile there. + (LP: #1639977) + + -- Brian Murray Mon, 07 Nov 2016 14:38:04 -0800 + unattended-upgrades (0.90ubuntu0.1) xenial-proposed; urgency=medium * Modify data/50unattended-upgrades.Ubuntu such that the release pocket is diff -Nru unattended-upgrades-0.90ubuntu0.1/debian/postinst unattended-upgrades-0.90ubuntu0.10/debian/postinst --- unattended-upgrades-0.90ubuntu0.1/debian/postinst 2016-02-18 22:19:18.000000000 +0000 +++ unattended-upgrades-0.90ubuntu0.10/debian/postinst 2017-04-21 14:51:30.000000000 +0000 @@ -61,6 +61,18 @@ && [ -f /etc/rc6.d/S[0-9][0-9]unattended-upgrades ] ; then update-rc.d -f unattended-upgrades remove fi + # Recover from broken dh_installinit override in versions < 0.90ubuntu0.5 + if dpkg --compare-versions "$2" lt "0.90ubuntu0.5"; then + if [ -f /etc/rc0.d/K[0-9][0-9]unattended-upgrades ] \ + && [ -f /etc/rc6.d/K[0-9][0-9]unattended-upgrades ] ; then + update-rc.d -f unattended-upgrades remove + fi + # Explicitely disable the service otherwise the shutdown.target + # symlink will remain (See Debian Bug #797108) + if deb-systemd-helper --quiet was-enabled unattended-upgrades.service; then + deb-systemd-helper disable unattended-upgrades.service >/dev/null || true + fi + fi ;; abort-upgrade|abort-remove|abort-deconfigure) @@ -77,6 +89,21 @@ #DEBHELPER# +# Explicitely enable and start the service.i Debian Bug #797108 for +# deb-systemd-helper fails to correctly enable the unit. It checks for +# enablement using the content of the WantedBy= which has changed so it +# sees the service as disable and will not enable it. +case "$1" in + configure) + if dpkg --compare-versions "$2" lt "0.90ubuntu0.5" \ + && [ -d /run/systemd/system ]; then + # workaround systemd bug with enable --now which + # fails to start the unit + systemctl enable unattended-upgrades || true + systemctl start unattended-upgrades || true + fi + ;; +esac exit 0 Binary files /tmp/tmpYSQfvh/pL0AHIfx4S/unattended-upgrades-0.90ubuntu0.1/debian/.postinst.swp and /tmp/tmpYSQfvh/MtzJlnnBQ8/unattended-upgrades-0.90ubuntu0.10/debian/.postinst.swp differ diff -Nru unattended-upgrades-0.90ubuntu0.1/debian/rules unattended-upgrades-0.90ubuntu0.10/debian/rules --- unattended-upgrades-0.90ubuntu0.1/debian/rules 2016-02-18 22:19:18.000000000 +0000 +++ unattended-upgrades-0.90ubuntu0.10/debian/rules 2017-04-20 15:16:24.000000000 +0000 @@ -28,8 +28,3 @@ rm -f $$f.py; \ done $(PYTHON) setup.py clean -a - -override_dh_installinit: - # we do not want to run the init script in the postinst/prerm, its - # really only useful on shutdown, see Debian bug #645919 - dh_installinit $@ --no-start -- stop 10 0 6 . diff -Nru unattended-upgrades-0.90ubuntu0.1/debian/tests/control unattended-upgrades-0.90ubuntu0.10/debian/tests/control --- unattended-upgrades-0.90ubuntu0.1/debian/tests/control 2016-02-18 22:19:18.000000000 +0000 +++ unattended-upgrades-0.90ubuntu0.10/debian/tests/control 2017-04-20 15:16:24.000000000 +0000 @@ -1,2 +1,3 @@ -Tests: run-tests +Tests: run-tests test-systemd.py Depends: @, @builddeps@ +Restrictions: needs-root, isolation-container diff -Nru unattended-upgrades-0.90ubuntu0.1/debian/tests/test-systemd.py unattended-upgrades-0.90ubuntu0.10/debian/tests/test-systemd.py --- unattended-upgrades-0.90ubuntu0.1/debian/tests/test-systemd.py 1970-01-01 00:00:00.000000000 +0000 +++ unattended-upgrades-0.90ubuntu0.10/debian/tests/test-systemd.py 2017-04-20 15:16:24.000000000 +0000 @@ -0,0 +1,80 @@ +#!/usr/bin/python3 + +import os +import sys +import subprocess + + +def test_systemd_service(): + ''' + Verify that the unattended-upgrades.service unit is started + correctly. The unit must be started in order for the ExecStop= + to work correctly + ''' + Service = 'unattended-upgrades.service' + try: + subprocess.check_output(['systemctl', '--quiet', 'is-active', Service]) + except subprocess.CalledProcessError: + out = subprocess.getoutput( + 'systemctl status unattended-upgrades.service') + print('test_systemd_service() FAILED\n%s' % out) + return False + return True + + +def enable_install_on_shutdown(): + ''' + Enable InstallOnShutdown to verify that the command runs correctly + upon reboot + ''' + apt_conf_file = '/etc/apt/apt.conf.d/50unattended-upgrades' + param = 'Unattended-Upgrade::InstallOnShutdown' + sed_cmd = 's/\/\/%s/%s/' % (param, param) + + try: + subprocess.check_output(['/bin/sed', '-i', sed_cmd, apt_conf_file]) + except subprocess.CalledProcessError: + print("Unable to edit %s" % apt_conf_file) + return False + return True + + +def check_log_files(): + ''' + Verify that the logfiles are correctly produced by the InstallOnShutdown + run upon reboot. This will confirm that it did run correctly when we + rebooted. + ''' + logdir = '/var/log/unattended-upgrades/' + logfiles = ['unattended-upgrades.log', 'unattended-upgrades-shutdown.log'] + + for file in logfiles: + if not os.path.exists(logdir + file): + print("File missing : %s" % (logdir + file)) + return False + return True + + +if __name__ == '__main__': + autopkgtest_reboot_mark = os.getenv('AUTOPKGTEST_REBOOT_MARK') + + if autopkgtest_reboot_mark is None: + if not test_systemd_service(): + sys.exit(1) + + if enable_install_on_shutdown(): + print('Rebooting to test InstallOnShutdown...') + subprocess.check_call(['/tmp/autopkgtest-reboot', + 'InstallOnShutdown']) + else: + sys.exit(1) + + if autopkgtest_reboot_mark == 'InstallOnShutdown': + if not check_log_files(): + print("InstallOnShutdown did not run") + sys.exit(1) + else: + print('Invalid autopkgtest_reboot_mark value') + sys.exit(1) + + sys.exit(0) diff -Nru unattended-upgrades-0.90ubuntu0.1/debian/unattended-upgrades.init unattended-upgrades-0.90ubuntu0.10/debian/unattended-upgrades.init --- unattended-upgrades-0.90ubuntu0.1/debian/unattended-upgrades.init 2016-02-18 22:19:18.000000000 +0000 +++ unattended-upgrades-0.90ubuntu0.10/debian/unattended-upgrades.init 2017-04-20 15:16:24.000000000 +0000 @@ -4,7 +4,7 @@ # Required-Start: $local_fs $remote_fs # Required-Stop: $local_fs $remote_fs # Provides: unattended-upgrade-shutdown-check -# Default-Start: +# Default-Start: 2 3 4 5 # Default-Stop: 0 6 # Short-Description: Check if unattended upgrades are being applied # Description: Check if unattended upgrades are being applied diff -Nru unattended-upgrades-0.90ubuntu0.1/debian/unattended-upgrades.service unattended-upgrades-0.90ubuntu0.10/debian/unattended-upgrades.service --- unattended-upgrades-0.90ubuntu0.1/debian/unattended-upgrades.service 2016-02-18 22:19:18.000000000 +0000 +++ unattended-upgrades-0.90ubuntu0.10/debian/unattended-upgrades.service 2017-04-20 15:16:24.000000000 +0000 @@ -1,12 +1,14 @@ [Unit] Description=Unattended Upgrades Shutdown -DefaultDependencies=no -Before=shutdown.target reboot.target halt.target +After=network.target local-fs.target +RequiresMountsFor=/var/log /var/run /var/lib /boot Documentation=man:unattended-upgrade(8) [Service] Type=oneshot -ExecStart=/usr/share/unattended-upgrades/unattended-upgrade-shutdown +RemainAfterExit=yes +ExecStop=/usr/share/unattended-upgrades/unattended-upgrade-shutdown +TimeoutStopSec=900 [Install] -WantedBy=shutdown.target +WantedBy=multi-user.target diff -Nru unattended-upgrades-0.90ubuntu0.1/test/test_in_chroot.py unattended-upgrades-0.90ubuntu0.10/test/test_in_chroot.py --- unattended-upgrades-0.90ubuntu0.1/test/test_in_chroot.py 2016-02-18 22:19:18.000000000 +0000 +++ unattended-upgrades-0.90ubuntu0.10/test/test_in_chroot.py 2017-07-31 19:32:05.000000000 +0000 @@ -54,6 +54,7 @@ debug = False verbose = True apt_debug = False + download_only = False dry_run = False minimal_upgrade_steps = False diff -Nru unattended-upgrades-0.90ubuntu0.1/test/test_remove_unused.py unattended-upgrades-0.90ubuntu0.10/test/test_remove_unused.py --- unattended-upgrades-0.90ubuntu0.1/test/test_remove_unused.py 2016-02-18 22:19:18.000000000 +0000 +++ unattended-upgrades-0.90ubuntu0.10/test/test_remove_unused.py 2017-07-31 19:32:05.000000000 +0000 @@ -14,6 +14,7 @@ class MockOptions(object): debug = False verbose = False + download_only = False dry_run = False apt_debug = False minimal_upgrade_steps = False diff -Nru unattended-upgrades-0.90ubuntu0.1/test/test_rewind.py unattended-upgrades-0.90ubuntu0.10/test/test_rewind.py --- unattended-upgrades-0.90ubuntu0.1/test/test_rewind.py 2016-02-18 22:19:18.000000000 +0000 +++ unattended-upgrades-0.90ubuntu0.10/test/test_rewind.py 2017-07-31 19:32:05.000000000 +0000 @@ -13,6 +13,7 @@ class MockOptions(object): debug = False verbose = False + download_only = False dry_run = True apt_debug = False minimal_upgrade_steps = False diff -Nru unattended-upgrades-0.90ubuntu0.1/test/test_untrusted.py unattended-upgrades-0.90ubuntu0.10/test/test_untrusted.py --- unattended-upgrades-0.90ubuntu0.1/test/test_untrusted.py 2016-02-18 22:19:18.000000000 +0000 +++ unattended-upgrades-0.90ubuntu0.10/test/test_untrusted.py 2017-07-31 19:32:05.000000000 +0000 @@ -13,6 +13,7 @@ class MockOptions(object): debug = True verbose = False + download_only = False dry_run = True apt_debug = False minimal_upgrade_steps = False diff -Nru unattended-upgrades-0.90ubuntu0.1/test/unattended_upgrade.py unattended-upgrades-0.90ubuntu0.10/test/unattended_upgrade.py --- unattended-upgrades-0.90ubuntu0.1/test/unattended_upgrade.py 2016-02-18 22:19:18.000000000 +0000 +++ unattended-upgrades-0.90ubuntu0.10/test/unattended_upgrade.py 2017-12-19 22:50:59.000000000 +0000 @@ -1008,6 +1008,8 @@ def write_stamp_file(): statedir = os.path.join(apt_pkg.config.find_dir("Dir::State"), "periodic") + if not os.path.exists(statedir): + os.makedirs(statedir) with open(os.path.join(statedir, "unattended-upgrades-stamp"), "w"): pass @@ -1092,13 +1094,15 @@ if pkg.is_auto_removable]) -def do_auto_remove(cache, auto_removable, logfile_dpkg, verbose=False): +def do_auto_remove(cache, auto_removable, logfile_dpkg, + verbose=False, dry_run=False): if not auto_removable: return True for pkgname in auto_removable: - logging.debug("marking %s for remove" % pkgname) - cache[pkgname].mark_delete() + if not dry_run: + logging.debug("marking %s for remove" % pkgname) + cache[pkgname].mark_delete() logging.info(_("Packages that are auto removed: '%s'"), " ".join(sorted(auto_removable))) @@ -1243,6 +1247,9 @@ res = fetcher.run() logging.debug("fetch.run() result: %s", res) + if options.download_only: + return + if dpkg_conffile_prompt(): # now check the downloaded debs for conffile conflicts and build # a blacklist @@ -1331,7 +1338,9 @@ write_stamp_file() # check if we couldn't reboot on previous run because # a user was logged-in at this time - reboot_if_requested_and_needed() + # never reboot during a dry run + if not options.dry_run: + reboot_if_requested_and_needed() return # check if its configured for install on shutdown, if so, the @@ -1355,6 +1364,9 @@ # get log logfile_dpkg = os.path.join(_get_logdir(), 'unattended-upgrades-dpkg.log') + if not os.path.exists(logfile_dpkg): + with open(logfile_dpkg, 'w'): + pass # only perform install step if we actually have packages to install pkg_install_success = True @@ -1385,7 +1397,8 @@ auto_removals = get_auto_removable(cache) pkg_install_success &= do_auto_remove( cache, auto_removals, logfile_dpkg, - options.verbose or options.debug) + options.verbose or options.debug, + options.dry_run) # the user wants *only new* auto-removals to be removed elif apt_pkg.config.find_b( "Unattended-Upgrade::Remove-New-Unused-Dependencies", True): @@ -1394,7 +1407,8 @@ auto_removals = new_pending_autoremovals - previous_autoremovals pkg_install_success &= do_auto_remove( cache, auto_removals, logfile_dpkg, - options.verbose or options.debug) + options.verbose or options.debug, + options.dry_run) logging.debug("InstCount=%i DelCount=%i BrokenCount=%i" % (cache._depcache.inst_count, @@ -1446,6 +1460,9 @@ parser.add_option("", "--dry-run", action="store_true", default=False, help=_("Simulation, download but do not install")) + parser.add_option("", "--download-only", + action="store_true", default=False, + help=_("Only download, do not even try to install.")) parser.add_option("", "--minimal-upgrade-steps", action="store_true", default=False, help=_("Upgrade in minimal steps (and allow " diff -Nru unattended-upgrades-0.90ubuntu0.1/unattended-upgrade unattended-upgrades-0.90ubuntu0.10/unattended-upgrade --- unattended-upgrades-0.90ubuntu0.1/unattended-upgrade 2016-02-18 22:19:18.000000000 +0000 +++ unattended-upgrades-0.90ubuntu0.10/unattended-upgrade 2017-12-19 22:50:59.000000000 +0000 @@ -1008,6 +1008,8 @@ def write_stamp_file(): statedir = os.path.join(apt_pkg.config.find_dir("Dir::State"), "periodic") + if not os.path.exists(statedir): + os.makedirs(statedir) with open(os.path.join(statedir, "unattended-upgrades-stamp"), "w"): pass @@ -1092,13 +1094,15 @@ if pkg.is_auto_removable]) -def do_auto_remove(cache, auto_removable, logfile_dpkg, verbose=False): +def do_auto_remove(cache, auto_removable, logfile_dpkg, + verbose=False, dry_run=False): if not auto_removable: return True for pkgname in auto_removable: - logging.debug("marking %s for remove" % pkgname) - cache[pkgname].mark_delete() + if not dry_run: + logging.debug("marking %s for remove" % pkgname) + cache[pkgname].mark_delete() logging.info(_("Packages that are auto removed: '%s'"), " ".join(sorted(auto_removable))) @@ -1243,6 +1247,9 @@ res = fetcher.run() logging.debug("fetch.run() result: %s", res) + if options.download_only: + return + if dpkg_conffile_prompt(): # now check the downloaded debs for conffile conflicts and build # a blacklist @@ -1331,7 +1338,9 @@ write_stamp_file() # check if we couldn't reboot on previous run because # a user was logged-in at this time - reboot_if_requested_and_needed() + # never reboot during a dry run + if not options.dry_run: + reboot_if_requested_and_needed() return # check if its configured for install on shutdown, if so, the @@ -1355,6 +1364,9 @@ # get log logfile_dpkg = os.path.join(_get_logdir(), 'unattended-upgrades-dpkg.log') + if not os.path.exists(logfile_dpkg): + with open(logfile_dpkg, 'w'): + pass # only perform install step if we actually have packages to install pkg_install_success = True @@ -1385,7 +1397,8 @@ auto_removals = get_auto_removable(cache) pkg_install_success &= do_auto_remove( cache, auto_removals, logfile_dpkg, - options.verbose or options.debug) + options.verbose or options.debug, + options.dry_run) # the user wants *only new* auto-removals to be removed elif apt_pkg.config.find_b( "Unattended-Upgrade::Remove-New-Unused-Dependencies", True): @@ -1394,7 +1407,8 @@ auto_removals = new_pending_autoremovals - previous_autoremovals pkg_install_success &= do_auto_remove( cache, auto_removals, logfile_dpkg, - options.verbose or options.debug) + options.verbose or options.debug, + options.dry_run) logging.debug("InstCount=%i DelCount=%i BrokenCount=%i" % (cache._depcache.inst_count, @@ -1446,6 +1460,9 @@ parser.add_option("", "--dry-run", action="store_true", default=False, help=_("Simulation, download but do not install")) + parser.add_option("", "--download-only", + action="store_true", default=False, + help=_("Only download, do not even try to install.")) parser.add_option("", "--minimal-upgrade-steps", action="store_true", default=False, help=_("Upgrade in minimal steps (and allow "