diff --git a/doc/tools/qubes-vm-update.rst b/doc/tools/qubes-vm-update.rst index 63971f7..100af55 100644 --- a/doc/tools/qubes-vm-update.rst +++ b/doc/tools/qubes-vm-update.rst @@ -69,7 +69,7 @@ Auxiliary --dry-run Just print what happens --no-cleanup - Do not remove updater files from target qube + Do not remove updater and cache files from target qube --help, -h Show this help message and exit @@ -110,7 +110,9 @@ RETURN CODES 24: error inside updated vm during installing updates -25: unhandled error inside updated vm +25: error inside updated vm during cleanup + +26: unhandled error inside updated vm 40: qrexec error, communication across domains was interrupted diff --git a/vmupdate/agent/entrypoint.py b/vmupdate/agent/entrypoint.py index 8737584..1a82070 100755 --- a/vmupdate/agent/entrypoint.py +++ b/vmupdate/agent/entrypoint.py @@ -34,6 +34,9 @@ def main(args=None): log.debug("Notify dom0 about upgrades.") os.system("/usr/lib/qubes/upgrades-status-notify") + if not args.no_cleanup: + return_code = max(pkg_mng.clean(), return_code) + if return_code not in EXIT.VM_HANDLED: return_code = EXIT.ERR_VM_UNHANDLED return return_code diff --git a/vmupdate/agent/source/apt/apt_cli.py b/vmupdate/agent/source/apt/apt_cli.py index eda6bfd..039029d 100644 --- a/vmupdate/agent/source/apt/apt_cli.py +++ b/vmupdate/agent/source/apt/apt_cli.py @@ -26,6 +26,7 @@ from source.common.package_manager import PackageManager from source.common.process_result import ProcessResult +from source.common.exit_codes import EXIT class APTCLI(PackageManager): @@ -80,3 +81,12 @@ 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"] + + def clean(self) -> int: + """ + Use apt to clears out the local repository of retrieved package files. + """ + cmd = [self.package_manager, "clean"] # consider autoclean + result = self.run_cmd(cmd, realtime=False) + return_code = EXIT.ERR_VM_CLEANUP if result.code != 0 else 0 + return return_code diff --git a/vmupdate/agent/source/args.py b/vmupdate/agent/source/args.py index 3d67ebc..5b0593c 100644 --- a/vmupdate/agent/source/args.py +++ b/vmupdate/agent/source/args.py @@ -35,9 +35,12 @@ class AgentArgs: {"action": 'store_true', "help": 'Try upgrade even if errors are ' 'encountered (like a refresh error)'}, + ("--no-cleanup",): { + "action": 'store_true', + "help": 'Do not remove cache files after upgrading'}, ("--leave-obsolete",): { "action": 'store_true', - "help": 'Do not remove obsolete packages during upgrading'}, + "help": 'Do not remove updater and cache files from target qube'}, } EXCLUSIVE_OPTIONS_1 = { ("--show-output", "--verbose", "-v"): diff --git a/vmupdate/agent/source/common/exit_codes.py b/vmupdate/agent/source/common/exit_codes.py index 774101c..a3a19f9 100644 --- a/vmupdate/agent/source/common/exit_codes.py +++ b/vmupdate/agent/source/common/exit_codes.py @@ -31,12 +31,13 @@ class EXIT: ERR_SHUTDOWN_APP = 12 # unable to shut down some AppVMs ERR_START_APP = 13 # unable to start some AppVMs - VM_HANDLED = (0, 100, 21, 22, 23, 24) + VM_HANDLED = (0, 100, 21, 22, 23, 24, 25) ERR_VM = 21 ERR_VM_PRE = 22 ERR_VM_REFRESH = 23 ERR_VM_UPDATE = 24 - ERR_VM_UNHANDLED = 25 + ERR_VM_CLEANUP = 25 + ERR_VM_UNHANDLED = 26 ERR_QREXEX = 40 ERR_USAGE = 64 diff --git a/vmupdate/agent/source/common/package_manager.py b/vmupdate/agent/source/common/package_manager.py index 4660871..7844d8b 100644 --- a/vmupdate/agent/source/common/package_manager.py +++ b/vmupdate/agent/source/common/package_manager.py @@ -280,3 +280,10 @@ def upgrade_internal(self, remove_obsolete: bool) -> ProcessResult: *self.get_action(remove_obsolete)] return self.run_cmd(cmd) + + def clean(self) -> int: + """ + Clean cache files of package manager. + Should return 0 on success or EXIT.ERR_VM_CLEANUP otherwise. + """ + return EXIT.ERR_VM_CLEANUP diff --git a/vmupdate/agent/source/dnf/dnf_cli.py b/vmupdate/agent/source/dnf/dnf_cli.py index 0517f73..313b1e5 100644 --- a/vmupdate/agent/source/dnf/dnf_cli.py +++ b/vmupdate/agent/source/dnf/dnf_cli.py @@ -24,6 +24,7 @@ from source.common.package_manager import PackageManager from source.common.process_result import ProcessResult +from source.common.exit_codes import EXIT class DNFCLI(PackageManager): @@ -97,3 +98,12 @@ def get_action(self, remove_obsolete) -> List[str]: return ["--obsoletes", "upgrade"] return ["--setopt=obsoletes=0", "upgrade" if self.package_manager == "dnf" else "update"] + + def clean(self) -> int: + """ + Performs cleanup of temporary files kept for repositories. + """ + cmd = [self.package_manager, "clean", "packages"] + result = self.run_cmd(cmd, realtime=False) + return_code = EXIT.ERR_VM_CLEANUP if result.code != 0 else 0 + return return_code diff --git a/vmupdate/agent/source/pacman/pacman_cli.py b/vmupdate/agent/source/pacman/pacman_cli.py index 3cb5e40..88fc052 100644 --- a/vmupdate/agent/source/pacman/pacman_cli.py +++ b/vmupdate/agent/source/pacman/pacman_cli.py @@ -23,6 +23,7 @@ from source.common.package_manager import PackageManager from source.common.process_result import ProcessResult +from source.common.exit_codes import EXIT class PACMANCLI(PackageManager): @@ -65,3 +66,13 @@ def get_action(self, remove_obsolete) -> List[str]: Pacman will handle obsoletions itself """ return ["-Syu"] + + def clean(self) -> int: + """ + Clean cache files of package manager. + Should return 0 on success or EXIT.ERR_VM_CLEANUP otherwise. + """ + cmd = [self.package_manager, "-Scc"] # consider -Sc + result = self.run_cmd(cmd, realtime=False) + return_code = EXIT.ERR_VM_CLEANUP if result.code != 0 else 0 + return return_code diff --git a/vmupdate/vmupdate.py b/vmupdate/vmupdate.py index 053f70f..49d5edc 100644 --- a/vmupdate/vmupdate.py +++ b/vmupdate/vmupdate.py @@ -95,8 +95,6 @@ def parse_args(args, app): help='Maximum number of VMs configured simultaneously ' '(default: number of cpus)', type=int) - parser.add_argument('--no-cleanup', action='store_true', - help='Do not remove updater files from target qube') parser.add_argument('--dry-run', action='store_true', help='Just print what happens.') parser.add_argument(