Package: release.debian.org Severity: normal User: release.debian....@packages.debian.org Usertags: unblock X-Debbugs-Cc: jvalle...@mailbox.org
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA512 Please unblock package freedombox [ Reason ] freedombox 21.4.4 is a fix for #991292. The freedombox dist-upgrade feature normally sets an apt-mark hold on the freedombox package, to prevent the system from becoming unreachable. The hold is set and removed within a try/finally block. However, it is possible that the upgrade process is killed before it is completed, and that the hold is left on the freedombox package. To recover from this state, we can check for a hold that is incorrectly left on the package. We just need to distinguish when the package is temporarily held during upgrade, or purposely held by administrator. We use a flag written to disk to indicate that a hold was placed by freedombox upgrade script. Here are the specific changes: * action_utils: Separate function to hold freedombox package * action_utils: Use flag to indicate freedombox package has been held * upgrades: Check for held freedombox package in manual update * upgrades: Check for held freedombox package daily * action_utils: Don't print when unholding freedombox package [ Impact ] The impact is that if FreedomBox users rely on the automatic dist-upgrade feature, there is a chance that after it completes, they will need to manually remove the hold on the freedombox package. [ Tests ] I tested the following: 1. A hold placed on the freedombox package by the freedombox upgrade script (indicated by flag on disk) will eventually be removed. 2. A hold on the freedombox package by system administrator (no flag on disk) will not be removed. 3. All applications available through FreedomBox can be installed, and no hold is left on freedombox package. 4. Package upgrades using unattended-upgrades are not impacted. [ Risks ] The code is fairly understandable and has been thoroughly tested in a FreedomBox system. No other packages are affected. [ Checklist ] [X] all changes are documented in the d/changelog [x] I reviewed all changes and I approve them [X] attach debdiff against the package in testing unblock freedombox/21.4.4 -----BEGIN PGP SIGNATURE----- iQJKBAEBCgA0FiEEfWrbdQ+RCFWJSEvmd8DHXntlCAgFAmD3TsUWHGp2YWxsZXJv eUBtYWlsYm94Lm9yZwAKCRB3wMdee2UICI3iD/9dSmDucHyok7iBIK/V9Z0aKsd3 0TwhR8el9UCpjqMprn9UkXDjwG5IPXWdRYe8KkShApeWTsxMY/3KrPirUa/1D4Hn 9bJiG//MTee8myeN3rYOC2WUupnm9Q0B4jvBBTo9rBGbRddu3nVfSTf6MLgRBKyB K+B4sJZE732JWbfGIw9e7sufKGHiXq1P3I+r/9LhVhvaOKMyQFHZgxT5I7KYJs0y usKRuwWValA9PSd2WVBPji3iJh5/w7HQKFmSsRR3H+xZ0jfR+x+e3bCj/jziR2ju 86U7yDVFfv8n/7JtwHm410GAd1ZgNYh45boPDTRONNGMU+NoukkWN/tbLI5hv5qs D9ftf0bYaYfJIBDWrKDea+1EGJUR9ZZKXTnwPoQxrQl5PhLSrDlgmH5/69Kqrli6 DQHBOtlxeortq92OwPHA4uUL2STL9p6G7+qGD61qI7OLZr1le8EQ/yooXg6cO7yq t4Tg7+kKWgRyTzn5uuLhO+mqBUK0+PFEeWyfXaZVOtGjmydZJDgBSMszq5pckwYG 9HEYPp6GH+W2LvWdZvuHZ5sAV8XG7xR7oHCAa8DP1YJko8yAK3IBHHz3mEznEttC TytO0YRlYG85P4mOiQaYpJXWLFR18opBkvoDFPhh2WWGParETHx5pyb34MDMU/Dt MfKQ3AT/LOFLvwyBOA== =xLE8 -----END PGP SIGNATURE-----
diff -Nru freedombox-21.4.3/actions/packages freedombox-21.4.4/actions/packages --- freedombox-21.4.3/actions/packages 2021-07-07 10:32:34.000000000 -0400 +++ freedombox-21.4.4/actions/packages 2021-07-16 09:07:51.000000000 -0400 @@ -18,9 +18,8 @@ import apt_inst import apt_pkg from plinth import cfg -from plinth.action_utils import apt_hold, run_apt_command - -LOCK_FILE = '/var/lib/dpkg/lock' +from plinth.action_utils import (apt_hold_freedombox, is_package_manager_busy, + run_apt_command) logger = logging.getLogger(__name__) @@ -93,7 +92,7 @@ extra_arguments += ['-o', 'Dpkg::Options::=--force-confmiss'] subprocess.run(['dpkg', '--configure', '-a']) - with apt_hold(): + with apt_hold_freedombox(): run_apt_command(['--fix-broken', 'install']) returncode = run_apt_command(['install'] + extra_arguments + arguments.packages) @@ -115,12 +114,10 @@ def subcommand_is_package_manager_busy(_): - """Return whether package manager is busy. - This command uses the `lsof` command to check whether the dpkg lock file - is open which indicates that the package manager is busy""" - try: - subprocess.check_output(['lsof', LOCK_FILE]) - except subprocess.CalledProcessError: + """Check whether package manager is busy. + + An exit code of zero indicates that package manager is busy.""" + if not is_package_manager_busy(): sys.exit(-1) diff -Nru freedombox-21.4.3/actions/upgrades freedombox-21.4.4/actions/upgrades --- freedombox-21.4.3/actions/upgrades 2021-07-07 10:32:34.000000000 -0400 +++ freedombox-21.4.4/actions/upgrades 2021-07-16 09:07:51.000000000 -0400 @@ -14,9 +14,10 @@ import sys import time -from plinth.action_utils import (apt_hold, debconf_set_selections, - run_apt_command, service_daemon_reload, - service_restart) +from plinth.action_utils import (apt_hold, apt_hold_flag, apt_hold_freedombox, + apt_unhold_freedombox, debconf_set_selections, + is_package_manager_busy, run_apt_command, + service_daemon_reload, service_restart) from plinth.modules.apache.components import check_url from plinth.modules.snapshot import (is_apt_snapshots_enabled, is_supported as snapshot_is_supported, load_augeas as @@ -141,6 +142,12 @@ """Run unattended-upgrades""" subprocess.run(['dpkg', '--configure', '-a']) run_apt_command(['--fix-broken', 'install']) + + # In case freedombox package was left in held state by an + # interrupted process, release it. + if apt_hold_flag.exists() and not is_package_manager_busy(): + apt_unhold_freedombox() + subprocess.Popen(['systemctl', 'start', 'freedombox-manual-upgrade'], stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, close_fds=True, @@ -432,7 +439,7 @@ # Hold freedombox package during entire dist upgrade. print('Holding freedombox package...', flush=True) - with apt_hold(): + with apt_hold_freedombox(): print('Updating Apt cache...', flush=True) run_apt_command(['update']) @@ -531,6 +538,11 @@ Check if a new stable release is available, and start dist-upgrade process if updates are enabled. """ + # In case freedombox package was left in held state by an + # interrupted process, release it. + if apt_hold_flag.exists() and not is_package_manager_busy(): + apt_unhold_freedombox() + upgrade_ready, reason = _check_dist_upgrade(arguments.test) if upgrade_ready: with open(DIST_UPGRADE_SERVICE_PATH, 'w') as service_file: diff -Nru freedombox-21.4.3/debian/changelog freedombox-21.4.4/debian/changelog --- freedombox-21.4.3/debian/changelog 2021-07-07 10:32:34.000000000 -0400 +++ freedombox-21.4.4/debian/changelog 2021-07-16 09:07:51.000000000 -0400 @@ -1,3 +1,13 @@ +freedombox (21.4.4) unstable; urgency=medium + + * action_utils: Separate function to hold freedombox package + * action_utils: Use flag to indicate freedombox package has been held + * upgrades: Check for held freedombox package in manual update + * upgrades: Check for held freedombox package daily + * action_utils: Don't print when unholding freedombox package + + -- James Valleroy <jvalle...@mailbox.org> Fri, 16 Jul 2021 09:07:51 -0400 + freedombox (21.4.3) unstable; urgency=medium [ Andreas Beckmann ] diff -Nru freedombox-21.4.3/plinth/action_utils.py freedombox-21.4.4/plinth/action_utils.py --- freedombox-21.4.3/plinth/action_utils.py 2021-07-07 10:32:34.000000000 -0400 +++ freedombox-21.4.4/plinth/action_utils.py 2021-07-16 09:07:51.000000000 -0400 @@ -5,6 +5,7 @@ import logging import os +import pathlib import shutil import subprocess import tempfile @@ -15,6 +16,11 @@ UWSGI_ENABLED_PATH = '/etc/uwsgi/apps-enabled/{config_name}.ini' UWSGI_AVAILABLE_PATH = '/etc/uwsgi/apps-available/{config_name}.ini' +# Flag on disk to indicate if freedombox package was held by +# plinth. This is a backup in case the process is interrupted and hold +# is not released. +apt_hold_flag = pathlib.Path('/var/lib/freedombox/package-held') + def is_systemd_running(): """Return if we are running under systemd.""" @@ -413,11 +419,8 @@ @contextmanager -def apt_hold(packages=None, ignore_errors=False): +def apt_hold(packages, ignore_errors=False): """Prevent packages from being removed during apt operations.""" - if not packages: - packages = ['freedombox'] - current_hold = subprocess.check_output(['apt-mark', 'showhold'] + packages) try: yield current_hold or subprocess.run(['apt-mark', 'hold'] + packages, @@ -426,3 +429,42 @@ if not current_hold: subprocess.run(['apt-mark', 'unhold'] + packages, check=not ignore_errors) + + +@contextmanager +def apt_hold_freedombox(): + """Prevent freedombox package from being removed during apt operations.""" + current_hold = subprocess.check_output( + ['apt-mark', 'showhold', 'freedombox']) + try: + if current_hold: + # Package is already held, possibly by administrator. + yield current_hold + else: + # Set the flag. + apt_hold_flag.touch(mode=0o660) + yield subprocess.check_call(['apt-mark', 'hold', 'freedombox']) + finally: + # Was the package held, either in this process or a previous one? + if not current_hold or apt_hold_flag.exists(): + apt_unhold_freedombox() + + +def apt_unhold_freedombox(): + """Remove any hold on freedombox package, and clear flag.""" + subprocess.run(['apt-mark', 'unhold', 'freedombox'], + stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + if apt_hold_flag.exists(): + apt_hold_flag.unlink() + + +def is_package_manager_busy(): + """Return whether package manager is busy. + This command uses the `lsof` command to check whether the dpkg lock file + is open which indicates that the package manager is busy""" + LOCK_FILE = '/var/lib/dpkg/lock' + try: + subprocess.check_output(['lsof', LOCK_FILE]) + return True + except subprocess.CalledProcessError: + return False diff -Nru freedombox-21.4.3/plinth/__init__.py freedombox-21.4.4/plinth/__init__.py --- freedombox-21.4.3/plinth/__init__.py 2021-07-07 10:32:34.000000000 -0400 +++ freedombox-21.4.4/plinth/__init__.py 2021-07-16 09:07:51.000000000 -0400 @@ -3,4 +3,4 @@ Package init file. """ -__version__ = '21.4.3' +__version__ = '21.4.4'