upgrades: Log messages using python logging framework

- When an action is invoked, it configured to handle console and journal
handlers. Console logger (StreamHandler) flushes after each event. Journal event
is sent immediately after the event. So, we are not losing the immediate flush
advantage by switching to logging framework.

- Since console logging is present (and the output is not captured away), using
journal handler also will double log each event. Remove the journal handler.
Console is where the output of various commands is logged. So, keep that.

Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org>
Reviewed-by: James Valleroy <jvalleroy@mailbox.org>
This commit is contained in:
Sunil Mohan Adapa 2025-03-05 13:12:50 -08:00 committed by James Valleroy
parent 1b89151c38
commit bbc2a2b0de
No known key found for this signature in database
GPG Key ID: 77C0C75E7B650808

View File

@ -15,6 +15,8 @@ from plinth.modules import snapshot as snapshot_module
from . import utils
logger = logging.getLogger(__name__)
SOURCES_LIST = '/etc/apt/sources.list'
DIST_UPGRADE_OBSOLETE_PACKAGES: list[str] = []
@ -34,7 +36,7 @@ def _apt_run(arguments):
def _sources_list_update(old_codename: str, new_codename: str):
"""Change the distribution in /etc/apt/sources.list."""
logging.info('Upgrading from %s to %s...', old_codename, new_codename)
logger.info('Upgrading from %s to %s...', old_codename, new_codename)
aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD +
augeas.Augeas.NO_MODL_AUTOLOAD)
aug.transform('aptsources', SOURCES_LIST)
@ -123,21 +125,20 @@ def _snapshot_run_and_disable() -> Generator[None, None, None]:
context manager..
"""
if not snapshot_module.is_supported():
print('Snapshots are not supported, skipping taking a snapshot.',
flush=True)
logger.info('Snapshots are not supported, skipping taking a snapshot.')
yield
return
reenable = False
try:
print('Taking a snapshot before dist upgrade...', flush=True)
logger.info('Taking a snapshot before dist upgrade...')
subprocess.run([
'/usr/share/plinth/actions/actions', 'snapshot', 'create',
'--no-args'
], check=True)
aug = snapshot_module.load_augeas()
if snapshot_module.is_apt_snapshots_enabled(aug):
print('Disabling apt snapshots during dist upgrade...', flush=True)
logger.info('Disabling apt snapshots during dist upgrade...')
subprocess.run([
'/usr/share/plinth/actions/actions',
'snapshot',
@ -145,19 +146,19 @@ def _snapshot_run_and_disable() -> Generator[None, None, None]:
], input='{"args": ["yes"], "kwargs": {}}'.encode(), check=True)
reenable = True
else:
print('Apt snapshots already disabled.', flush=True)
logger.info('Apt snapshots already disabled.')
yield
finally:
if reenable:
print('Re-enabling apt snapshots...', flush=True)
logger.info('Re-enabling apt snapshots...')
subprocess.run([
'/usr/share/plinth/actions/actions', 'snapshot',
'disable_apt_snapshot'
], input='{"args": ["no"], "kwargs": {}}'.encode(), check=True)
else:
print('Not re-enabling apt snapshots, as they were disabled '
'before dist upgrade.')
logger.info('Not re-enabling apt snapshots, as they were disabled '
'before dist upgrade.')
@contextlib.contextmanager
@ -166,11 +167,10 @@ def _services_disable():
# If quassel is running during dist upgrade, it may be restarted
# several times. This causes IRC users to rapidly leave/join
# channels. Stop quassel for the duration of the dist upgrade.
print('Stopping quassel service during dist upgrade...', flush=True)
logger.info('Stopping quassel service during dist upgrade...')
with action_utils.service_ensure_stopped('quasselcore'):
yield
print('Re-enabling quassel service if previously enabled...',
flush=True)
logger.info('Re-enabling quassel service if previously enabled...')
@contextlib.contextmanager
@ -180,27 +180,26 @@ def _apt_hold_packages():
packages_string = ', '.join(packages)
# Hold freedombox package during entire dist upgrade.
print('Holding freedombox package...', flush=True)
logger.info('Holding freedombox package...')
with action_utils.apt_hold_freedombox():
# Hold packages known to have conffile prompts. FreedomBox service
# will handle their upgrade later.
print(f'Holding packages with conffile prompts: {packages_string}...',
flush=True)
logger.info('Holding packages with conffile prompts: %s...',
packages_string)
with action_utils.apt_hold(packages):
yield
print(
'Releasing holds on packages with conffile prompts: '
f'{packages_string}...', flush=True)
logger.info(
'Releasing holds on packages with conffile prompts: %s...',
packages_string)
print('Releasing hold on freedombox package...')
logger.info('Releasing hold on freedombox package...')
def _debconf_set_selections() -> None:
"""Pre-set debconf selections if they are needed for dist upgrade."""
if DIST_UPGRADE_PRE_DEBCONF_SELECTIONS:
print(
f'Setting debconf selections: '
f'{DIST_UPGRADE_PRE_DEBCONF_SELECTIONS}', flush=True)
logger.info('Setting debconf selections: %s',
DIST_UPGRADE_PRE_DEBCONF_SELECTIONS)
action_utils.debconf_set_selections(
DIST_UPGRADE_PRE_DEBCONF_SELECTIONS)
@ -211,26 +210,25 @@ def _packages_remove_obsolete() -> None:
These may prevent other packages from upgrading.
"""
if DIST_UPGRADE_OBSOLETE_PACKAGES:
print(f'Removing packages: {DIST_UPGRADE_OBSOLETE_PACKAGES}...',
flush=True)
logger.info('Removing packages: %s...', DIST_UPGRADE_OBSOLETE_PACKAGES)
_apt_run(['remove'] + DIST_UPGRADE_OBSOLETE_PACKAGES)
def _apt_update():
"""Run 'apt update'."""
print('Updating Apt cache...', flush=True)
logger.info('Updating Apt cache...')
_apt_run(['update'])
def _apt_autoremove():
"""Run 'apt autoremove'."""
print('Running apt autoremove...', flush=True)
logger.info('Running apt autoremove...')
_apt_run(['autoremove'])
def _apt_full_upgrade():
"""Run and check if apt upgrade was successful."""
print('Running apt full-upgrade...', flush=True)
logger.info('Running apt full-upgrade...')
returncode = _apt_run(['full-upgrade'])
if returncode:
raise RuntimeError(
@ -243,7 +241,7 @@ def _unattended_upgrades_run():
To handle upgrading the freedombox package.
"""
print('Running unattended-upgrade...', flush=True)
logger.info('Running unattended-upgrade...')
subprocess.run(['unattended-upgrade', '--verbose'], check=False)
@ -252,18 +250,32 @@ def _freedombox_restart():
To ensure it is using the latest dependencies.
"""
print('Restarting FreedomBox service...', flush=True)
logger.info('Restarting FreedomBox service...')
action_utils.service_restart('plinth')
def _wait():
"""Wait for 10 minutes before performing remaining actions."""
print('Waiting for 10 minutes...', flush=True)
logger.info('Waiting for 10 minutes...')
time.sleep(10 * 60)
def _logging_setup():
"""Log to journal via console logging.
We need to capture all console logs created by apt and other commands and
redirect them to journal. This is the default behavior when launching a
service with systemd-run.
Avoid double logging to the journal by removing the systemd journal as a
log handler..
"""
logging.getLogger(None).removeHandler('journal')
def perform():
"""Perform upgrade to next release of Debian."""
_logging_setup()
with _snapshot_run_and_disable(), \
_services_disable(), \
_apt_hold_packages():