diff options
| author | Dennis Fink | 2026-09-27 21:37:45 +0200 |
|---|---|---|
| committer | Dennis Fink | 2026-09-27 21:37:45 +0200 |
| commit | c7403b5870aed4baaf5253d21761619d8607efb7 (patch) | |
| tree | 98da4ca9ec935431c9ca533dc395cb1451a9d37a /prometheus_pacman_exporter | |
| parent | 731a25e096cf9af3c0c5b3303796df7b3e91df36 (diff) | |
| download | prometheus-pacman-exporter-c7403b5870aed4baaf5253d21761619d8607efb7.tar.gz prometheus-pacman-exporter-c7403b5870aed4baaf5253d21761619d8607efb7.zip | |
fix(commands): distinguish empty query results
Track exit codes that indicate an empty package query separately from
accepted success codes.
Treat pacman exit status 1 as an empty result only when both stdout and
stderr are empty, while preserving genuine command failures as errors.
Apply the empty-result handling to pacman queries that may legitimately
return no packages, including update checks.
Diffstat (limited to 'prometheus_pacman_exporter')
| -rw-r--r-- | prometheus_pacman_exporter/__init__.py | 45 |
1 files changed, 34 insertions, 11 deletions
diff --git a/prometheus_pacman_exporter/__init__.py b/prometheus_pacman_exporter/__init__.py index 0125187..80198d7 100644 --- a/prometheus_pacman_exporter/__init__.py +++ b/prometheus_pacman_exporter/__init__.py @@ -30,38 +30,48 @@ class PackageQuery(NamedTuple): description: str metric: Gauge accepted_exit_codes: tuple[int, ...] = (0,) + empty_exit_codes: tuple[int, ...] = () PACMAN_BASE_COMMAND = ("pacman", "--query") +PACMAN_EMPTY_EXIT_CODES = (1,) BASE_QUERIES: tuple[PackageQuery, ...] = ( PackageQuery(PACMAN_BASE_COMMAND, "installed packages", metrics.INSTALLED_PACKAGES), PackageQuery( (*PACMAN_BASE_COMMAND, "--explicit"), "explicitly installed packages", metrics.EXPLICIT_PACKAGES, + empty_exit_codes=PACMAN_EMPTY_EXIT_CODES, ), PackageQuery( (*PACMAN_BASE_COMMAND, "--deps"), "packages installed as dependencies", metrics.DEPENDS_PACKAGES, + empty_exit_codes=PACMAN_EMPTY_EXIT_CODES, ), PackageQuery( (*PACMAN_BASE_COMMAND, "--unrequired"), "unrequired packages", metrics.UNREQUIRED_PACKAGES, + empty_exit_codes=PACMAN_EMPTY_EXIT_CODES, ), PackageQuery( (*PACMAN_BASE_COMMAND, "--foreign"), "foreign packages", metrics.FOREIGN_PACKAGES, + empty_exit_codes=PACMAN_EMPTY_EXIT_CODES, ), PackageQuery( - (*PACMAN_BASE_COMMAND, "--native"), "native packages", metrics.NATIVE_PACKAGES + (*PACMAN_BASE_COMMAND, "--native"), + "native packages", + metrics.NATIVE_PACKAGES, + empty_exit_codes=PACMAN_EMPTY_EXIT_CODES, ), PackageQuery( (*PACMAN_BASE_COMMAND, "--deps", "--unrequired"), "orphan packages", metrics.ORPHAN_PACKAGES, + (0, 1), ), ) @@ -124,6 +134,7 @@ def run_command( ctx: click.Context, command: tuple[str, ...], accepted_exit_codes: tuple[int, ...] = (0,), + empty_exit_codes: tuple[int, ...] = (), ) -> subprocess.CompletedProcess[str]: """Run a command and return the result. @@ -133,19 +144,29 @@ def run_command( :param ctx: Click context injected by :func:`click.pass_context`. :param command: Command and its arguments. :param accepted_exit_codes: Exit codes considered successful. + :param empty_exit_codes: Exit codes considered an empty result when both + stdout and stderr are empty. :return: Completed process with stdout and stderr captured. """ command_string = shlex.join(command) - debug("Running command", command_string, err=True) + debug("Running command:", command_string, err=True) result = subprocess.run(command, capture_output=True, encoding="utf-8", check=False) - if result.returncode not in accepted_exit_codes: - error( - f"Command ({command_string}) failed with exit code:", str(result.returncode) - ) - if result.stderr: - error("stderr:", result.stderr.strip()) - ctx.exit(1) + if result.returncode in accepted_exit_codes: + return result + + if ( + result.returncode in empty_exit_codes + and not result.stdout.strip() + and not result.stderr.strip() + ): + debug("Command returned an empty result:", command_string, err=True) + return result + + error(f"Command ({command_string}) failed with exit code:", str(result.returncode)) + if result.stderr: + error("stderr:", result.stderr.strip()) + ctx.exit(1) return result @@ -262,7 +283,7 @@ def prometheus_pacman_exporter( (*PACMAN_BASE_COMMAND, "--upgrades"), "updateable packages", metrics.UPDATEABLE_PACKAGES, - (0, 1), + empty_exit_codes=PACMAN_EMPTY_EXIT_CODES, ) ) @@ -276,7 +297,9 @@ def prometheus_pacman_exporter( ) for query in queries: - output = run_command(query.command, query.accepted_exit_codes) + output = run_command( + query.command, query.accepted_exit_codes, query.empty_exit_codes + ) value = len(output.stdout.splitlines()) verbose(f"Setting {query.description}:", str(value), err=True) query.metric.set(value) |
