[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#991336: unblock: freedombox/21.4.4



Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: unblock
X-Debbugs-Cc: jvalleroy@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 <jvalleroy@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'

Reply to: