diff --git a/plinth/modules/upgrades/distupgrade.py b/plinth/modules/upgrades/distupgrade.py index 1124e04ec..376672b3b 100644 --- a/plinth/modules/upgrades/distupgrade.py +++ b/plinth/modules/upgrades/distupgrade.py @@ -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():