diff --git a/vmupdate/agent/source/apt/apt_api.py b/vmupdate/agent/source/apt/apt_api.py index 2443cc6..2158d3e 100644 --- a/vmupdate/agent/source/apt/apt_api.py +++ b/vmupdate/agent/source/apt/apt_api.py @@ -95,6 +95,9 @@ def upgrade_internal(self, remove_obsolete: bool) -> ProcessResult: "An error occurred while upgrading packages: %s", str(exc)) result += ProcessResult(EXIT.ERR_VM_UPDATE, out="", err=str(exc)) + if remove_obsolete: + result += self.remove_obsolete_kernels() + return result diff --git a/vmupdate/agent/source/apt/apt_cli.py b/vmupdate/agent/source/apt/apt_cli.py index 039029d..59b4dcd 100644 --- a/vmupdate/agent/source/apt/apt_cli.py +++ b/vmupdate/agent/source/apt/apt_cli.py @@ -76,6 +76,17 @@ def get_packages(self): return packages + def upgrade_internal(self, remove_obsolete: bool) -> ProcessResult: + """ + Additionally remove obsolete kernels. + """ + result = super().upgrade_internal(remove_obsolete) + + if remove_obsolete: + result += self.remove_obsolete_kernels() + + return result + def get_action(self, remove_obsolete: bool) -> List[str]: """ Return command `upgrade` or `dist-upgrade` if `remove_obsolete`. @@ -90,3 +101,34 @@ def clean(self) -> int: result = self.run_cmd(cmd, realtime=False) return_code = EXIT.ERR_VM_CLEANUP if result.code != 0 else 0 return return_code + + def remove_obsolete_kernels(self) -> ProcessResult: + """ + Remove old kernel packages in a little hacky way. + + Usage of `apt autoremove` is not always safe and definitely + should not be run automatically. However, we want at lest remove + old kernels since they are heavy and clutter template vms. + """ + # dry run of autoremove to print which packages will be removed + # (printed with `Remv ` prefix). It's a simple way to keep apt logic + # which by default keep 2 newest versions of kernel. + cmd = [self.package_manager, "autoremove", "-s"] + result = self.run_cmd(cmd, realtime=False) + + if not result: # no error + obsoletes = set() + for line in result.out.splitlines(): + if line.startswith("Remv"): + package_name = line[len("Remv "):] + # consider using wider pattern + if package_name.startswith("linux-image"): + obsoletes.add(package_name.split(" ")[0]) + if obsoletes: + cmd = [self.package_manager, "remove", "-y", *obsoletes] + result = self.run_cmd(cmd, realtime=False) + else: + result = ProcessResult.OK + + result.code = EXIT.ERR_VM_CLEANUP if result.code != 0 else 0 + return result \ No newline at end of file