diff options
| author | Dennis Fink | 2026-09-27 13:14:07 +0200 |
|---|---|---|
| committer | Dennis Fink | 2026-09-27 13:20:47 +0200 |
| commit | 555d50bfd10b1ac983aec17cf5b3cdf3a9cb99d7 (patch) | |
| tree | 38539bd205d8b7434b8c02c8482a9a4c0f694268 /prometheus_pacman_exporter/__init__.py | |
| parent | 142af72ebc9e1c2151101d6c3318ee48fdf00a87 (diff) | |
| download | prometheus-pacman-exporter-555d50bfd10b1ac983aec17cf5b3cdf3a9cb99d7.tar.gz prometheus-pacman-exporter-555d50bfd10b1ac983aec17cf5b3cdf3a9cb99d7.zip | |
fix(commands): classify command failures for retries
Allow command invocations to define which child exit codes are
considered successful, including checkupdates exit status 2 when no
updates are available.
Classify unexpected child command failures as exporter exit status 1 so
systemd treats them as runtime failures eligible for retry. Keep exit
status 2 for CLI usage errors, which are configuration problems and
should not be retried.
Update the systemd service with RestartPreventExitStatus=2 so only
retryable runtime failures trigger the configured restart policy.
Diffstat (limited to '')
| -rw-r--r-- | prometheus_pacman_exporter/__init__.py | 40 |
1 files changed, 28 insertions, 12 deletions
diff --git a/prometheus_pacman_exporter/__init__.py b/prometheus_pacman_exporter/__init__.py index 23ce5a2..ac76dc6 100644 --- a/prometheus_pacman_exporter/__init__.py +++ b/prometheus_pacman_exporter/__init__.py @@ -80,7 +80,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.""") @click.pass_context def run_command( - ctx: click.Context, command: list[str] + ctx: click.Context, command: list[str], success_codes: tuple[int, ...] = (0,) ) -> subprocess.CompletedProcess[str]: """Run a shell command and return the result. @@ -89,18 +89,21 @@ def run_command( :param ctx: Click context injected by :func:`click.pass_context`. :param command: Command and its arguments. + :param success_codes: Exit codes considered successful. :return: Completed process with stdout and stderr captured. """ debug("Running command", " ".join(command), err=True) - try: - return subprocess.run( - command, capture_output=True, encoding="utf-8", check=True + result = subprocess.run(command, capture_output=True, encoding="utf-8", check=False) + + if result.returncode not in success_codes: + error( + f"Command ({' '.join(command)}) failed with exit code {result.returncode}" ) - except subprocess.CalledProcessError as e: - error(f"Command ({' '.join(command)}) failed with exit code {e.returncode}") - if e.stderr: - error("stderr:", e.stderr.strip()) - ctx.exit(e.returncode) + if result.stderr: + error("stderr:", result.stderr.strip()) + ctx.exit(1) + + return result @click.command( @@ -193,36 +196,47 @@ def prometheus_pacman_exporter( pacman_base_command = ["pacman", "--query"] queries = [ - ([*pacman_base_command], "installed packages", metrics.INSTALLED_PACKAGES), + ( + [*pacman_base_command], + "installed packages", + metrics.INSTALLED_PACKAGES, + (0,), + ), ( [*pacman_base_command, "--explicit"], "explicitly installed packages", metrics.EXPLICIT_PACKAGES, + (0,), ), ( [*pacman_base_command, "--deps"], "packages installed as dependencies", metrics.DEPENDS_PACKAGES, + (0,), ), ( [*pacman_base_command, "--unrequired"], "unrequired packages", metrics.UNREQUIRED_PACKAGES, + (0,), ), ( [*pacman_base_command, "--foreign"], "foreign packages", metrics.FOREIGN_PACKAGES, + (0,), ), ( [*pacman_base_command, "--native"], "native packages", metrics.NATIVE_PACKAGES, + (0,), ), ( [*pacman_base_command, "--deps", "--unrequired"], "orphan packages", metrics.ORPHAN_PACKAGES, + (0,), ), ( ["checkupdates"] @@ -230,6 +244,7 @@ def prometheus_pacman_exporter( else [*pacman_base_command, "--upgrades"], "updateable packages", metrics.UPDATEABLE_PACKAGES, + (0, 2) if use_checkupdates_flag else (0, 1), ), ] @@ -239,11 +254,12 @@ def prometheus_pacman_exporter( shlex.split(cast(str, aur_command)), "AUR updateable packages", metrics.AUR_UPDATEABLE_PACKAGES, + (0,), ) ) - for command, description, metric in queries: - output = run_command(command) + for command, description, metric, success_codes in queries: + output = run_command(command, success_codes) value = len(output.stdout.splitlines()) verbose(f"Setting {description}:", str(value), err=True) metric.set(value) |
