From 528a5d0e47c03ddf94e3ef2bc531e385a25017c4 Mon Sep 17 00:00:00 2001 From: Piotr Bartman-Szwarc Date: Tue, 3 Sep 2024 17:13:05 +0200 Subject: [PATCH 1/3] updater: cleanup move package manager logic to subclasses --- vmupdate/agent/source/apt/apt_cli.py | 4 +++- vmupdate/agent/source/common/package_manager.py | 6 ++---- vmupdate/agent/source/dnf/dnf_cli.py | 4 ++-- vmupdate/agent/source/pacman/pacman_cli.py | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/vmupdate/agent/source/apt/apt_cli.py b/vmupdate/agent/source/apt/apt_cli.py index 561d556..6beb646 100644 --- a/vmupdate/agent/source/apt/apt_cli.py +++ b/vmupdate/agent/source/apt/apt_cli.py @@ -91,7 +91,9 @@ def get_action(self, remove_obsolete: bool) -> List[str]: """ Return command `upgrade` or `dist-upgrade` if `remove_obsolete`. """ - return ["dist-upgrade"] if remove_obsolete else ["upgrade"] + result = ["-y"] + result += ["dist-upgrade"] if remove_obsolete else ["upgrade"] + return result def clean(self) -> int: """ diff --git a/vmupdate/agent/source/common/package_manager.py b/vmupdate/agent/source/common/package_manager.py index 7844d8b..447b01e 100644 --- a/vmupdate/agent/source/common/package_manager.py +++ b/vmupdate/agent/source/common/package_manager.py @@ -267,7 +267,7 @@ def get_packages(self) -> Dict[str, List[str]]: def get_action(self, remove_obsolete: bool) -> List[str]: """ - Return command for upgrade or upgrade with removing obsolete packages. + Return command and options for upgrade with optional removing obsoletes. """ raise NotImplementedError() @@ -275,9 +275,7 @@ def upgrade_internal(self, remove_obsolete: bool) -> ProcessResult: """ Just run upgrade via CLI. """ - cmd = [self.package_manager, - "--noconfirm" if self.package_manager == "pacman" else "-y", - *self.get_action(remove_obsolete)] + cmd = [self.package_manager, *self.get_action(remove_obsolete)] return self.run_cmd(cmd) diff --git a/vmupdate/agent/source/dnf/dnf_cli.py b/vmupdate/agent/source/dnf/dnf_cli.py index 313b1e5..fbff8ab 100644 --- a/vmupdate/agent/source/dnf/dnf_cli.py +++ b/vmupdate/agent/source/dnf/dnf_cli.py @@ -95,8 +95,8 @@ def get_action(self, remove_obsolete) -> List[str]: Disable or enforce obsolete flag in dnf/yum. """ if remove_obsolete: - return ["--obsoletes", "upgrade"] - return ["--setopt=obsoletes=0", + return ["-y", "--obsoletes", "upgrade"] + return ["-y", "--setopt=obsoletes=0", "upgrade" if self.package_manager == "dnf" else "update"] def clean(self) -> int: diff --git a/vmupdate/agent/source/pacman/pacman_cli.py b/vmupdate/agent/source/pacman/pacman_cli.py index 88fc052..dc9476b 100644 --- a/vmupdate/agent/source/pacman/pacman_cli.py +++ b/vmupdate/agent/source/pacman/pacman_cli.py @@ -65,7 +65,7 @@ def get_action(self, remove_obsolete) -> List[str]: """ Pacman will handle obsoletions itself """ - return ["-Syu"] + return ["--noconfirm", "-Syu"] def clean(self) -> int: """ From 009d2e42d048bb4a53843f337cfee58e1686912b Mon Sep 17 00:00:00 2001 From: Piotr Bartman-Szwarc Date: Wed, 4 Sep 2024 09:23:17 +0200 Subject: [PATCH 2/3] updater: add flags to apt conf to auto-resolve conffiles conflicts fixes QubesOS/qubes-issues/issues/9072 --- vmupdate/agent/entrypoint.py | 10 +++-- .../source/plugins/apt_keep_old_conffiles.py | 37 +++++++++++++++++++ 2 files changed, 43 insertions(+), 4 deletions(-) create mode 100644 vmupdate/agent/source/plugins/apt_keep_old_conffiles.py diff --git a/vmupdate/agent/entrypoint.py b/vmupdate/agent/entrypoint.py index 1a82070..256e1d2 100755 --- a/vmupdate/agent/entrypoint.py +++ b/vmupdate/agent/entrypoint.py @@ -56,6 +56,12 @@ def get_package_manager(os_data, log, log_handler, log_level, no_progress): If appropriate python package is not installed or `no_progress` is `True` cli based version is returned. """ + requirements = {} + # plugins MUST be applied before import anything from package managers. + # in case of apt configuration is loaded on `import apt`. + for plugin in plugins.entrypoints: + plugin(os_data, log, requirements=requirements) + if os_data["os_family"] == "Debian": try: from source.apt.apt_api import APT as PackageManager @@ -82,10 +88,6 @@ def get_package_manager(os_data, log, log_handler, log_level, no_progress): raise NotImplementedError( "Only Debian, RedHat and ArchLinux based OS is supported.") - requirements = {} - for plugin in plugins.entrypoints: - plugin(os_data, log, requirements=requirements) - pkg_mng = PackageManager(log_handler, log_level) pkg_mng.requirements = requirements return pkg_mng diff --git a/vmupdate/agent/source/plugins/apt_keep_old_conffiles.py b/vmupdate/agent/source/plugins/apt_keep_old_conffiles.py new file mode 100644 index 0000000..e208fef --- /dev/null +++ b/vmupdate/agent/source/plugins/apt_keep_old_conffiles.py @@ -0,0 +1,37 @@ +# coding=utf-8 +# +# The Qubes OS Project, http://www.qubes-os.org +# +# Copyright (C) 2024 Piotr Bartman +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +# USA. + +APT_CONF = "/etc/apt/apt.conf.d/01qubes-update" + + +def apt_keep_old_conffiles(os_data, log, **kwargs): + """ + Always chose default behavior for when conflicts in apt conffiles appears. + """ + if os_data["os_family"] != "Debian": + return + + option = '''Dpkg::Options { + "--force-confdef"; + "--force-confold"; +}''' + with open(APT_CONF, "w") as file: + file.write(f'\n{option}\n') From d3ea82275d56d45ad660e99f07f51d9c1811d455 Mon Sep 17 00:00:00 2001 From: Piotr Bartman-Szwarc Date: Wed, 2 Oct 2024 12:31:16 +0200 Subject: [PATCH 3/3] updater: auto-resolve conffiles conflicts only if qubes-updater is used previous version change behavior permanently --- vmupdate/agent/source/apt/apt_api.py | 2 + vmupdate/agent/source/apt/apt_cli.py | 5 ++- .../source/plugins/apt_keep_old_conffiles.py | 37 ------------------- 3 files changed, 6 insertions(+), 38 deletions(-) delete mode 100644 vmupdate/agent/source/plugins/apt_keep_old_conffiles.py diff --git a/vmupdate/agent/source/apt/apt_api.py b/vmupdate/agent/source/apt/apt_api.py index 2158d3e..5bd38f8 100644 --- a/vmupdate/agent/source/apt/apt_api.py +++ b/vmupdate/agent/source/apt/apt_api.py @@ -84,6 +84,8 @@ def upgrade_internal(self, remove_obsolete: bool) -> ProcessResult: Path(os.path.join( apt_pkg.config.find_dir("Dir::Cache::Archives"), "partial") ).mkdir(parents=True, exist_ok=True) + apt_pkg.config.set('Dpkg::Options::', "--force-confdef") + apt_pkg.config.set('Dpkg::Options::', "--force-confold") self.log.debug("Committing upgrade...") self.apt_cache.commit( self.progress.fetch_progress, diff --git a/vmupdate/agent/source/apt/apt_cli.py b/vmupdate/agent/source/apt/apt_cli.py index 6beb646..7f6b0dc 100644 --- a/vmupdate/agent/source/apt/apt_cli.py +++ b/vmupdate/agent/source/apt/apt_cli.py @@ -91,7 +91,10 @@ def get_action(self, remove_obsolete: bool) -> List[str]: """ Return command `upgrade` or `dist-upgrade` if `remove_obsolete`. """ - result = ["-y"] + result = ["-y", + "-o", 'Dpkg::Options::=--force-confdef', + "-o", 'Dpkg::Options::=--force-confold' + ] result += ["dist-upgrade"] if remove_obsolete else ["upgrade"] return result diff --git a/vmupdate/agent/source/plugins/apt_keep_old_conffiles.py b/vmupdate/agent/source/plugins/apt_keep_old_conffiles.py deleted file mode 100644 index e208fef..0000000 --- a/vmupdate/agent/source/plugins/apt_keep_old_conffiles.py +++ /dev/null @@ -1,37 +0,0 @@ -# coding=utf-8 -# -# The Qubes OS Project, http://www.qubes-os.org -# -# Copyright (C) 2024 Piotr Bartman -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, -# USA. - -APT_CONF = "/etc/apt/apt.conf.d/01qubes-update" - - -def apt_keep_old_conffiles(os_data, log, **kwargs): - """ - Always chose default behavior for when conflicts in apt conffiles appears. - """ - if os_data["os_family"] != "Debian": - return - - option = '''Dpkg::Options { - "--force-confdef"; - "--force-confold"; -}''' - with open(APT_CONF, "w") as file: - file.write(f'\n{option}\n')