feat(agent): system info collector for pveversion/zfs/apt

This commit is contained in:
Carsten 2026-04-21 22:35:32 +02:00
parent da5ed6cd08
commit 61fa959d52
5 changed files with 89 additions and 0 deletions

View file

@ -0,0 +1,45 @@
defmodule ProxmoxAgent.Collectors.SystemInfo do
@moduledoc "Slow-path system metadata: pveversion, zfs version, apt upgradable count."
@spec collect(keyword()) :: %{
pve_version: String.t() | nil,
zfs_version: String.t() | nil,
pending_updates: non_neg_integer(),
agent_version: String.t(),
errors: [map()]
}
def collect(opts \\ []) do
runner = Keyword.get(opts, :runner, &ProxmoxAgent.Shell.run/2)
{pve, e1} = trim_output(runner.("pveversion", []), :pveversion)
{zfs, e2} = trim_output(runner.("zfs", ["--version"]), :zfs_version)
{apt, e3} = runner.("apt", ["list", "--upgradable"]) |> count_upgrades()
%{
pve_version: pve,
zfs_version: zfs,
pending_updates: apt,
agent_version: ProxmoxAgent.version(),
errors: Enum.filter([e1, e2, e3], & &1)
}
end
defp trim_output({:ok, text}, _tag), do: {String.trim(text) |> first_line(), nil}
defp trim_output({:error, reason}, tag),
do: {nil, %{tag: Atom.to_string(tag), message: inspect(reason)}}
defp first_line(str), do: str |> String.split("\n", parts: 2) |> hd()
defp count_upgrades({:ok, text}) do
count =
text
|> String.split("\n", trim: true)
|> Enum.count(&String.contains?(&1, "[upgradable"))
{count, nil}
end
defp count_upgrades({:error, reason}),
do: {0, %{tag: "apt_upgradable", message: inspect(reason)}}
end

View file

@ -0,0 +1,3 @@
Listing...
libssl3/stable 3.0.11-1~deb12u2 amd64 [upgradable from: 3.0.11-1~deb12u1]
openssh-server/stable 1:9.2p1-2+deb12u3 amd64 [upgradable from: 1:9.2p1-2+deb12u2]

View file

@ -0,0 +1 @@
pve-manager/8.3.1/abc123 (running kernel: 6.8.12-1-pve)

View file

@ -0,0 +1,2 @@
zfs-2.3.0-pve2
zfs-kmod-2.3.0-pve2

View file

@ -0,0 +1,38 @@
defmodule ProxmoxAgent.Collectors.SystemInfoTest do
use ExUnit.Case, async: true
alias ProxmoxAgent.Collectors.SystemInfo
@fixtures Path.expand("../../fixtures/system", __DIR__)
defp fake_runner do
fn
"pveversion", [] -> {:ok, File.read!(Path.join(@fixtures, "pveversion.txt"))}
"zfs", ["--version"] -> {:ok, File.read!(Path.join(@fixtures, "zfs_version.txt"))}
"apt", ["list", "--upgradable"] -> {:ok, File.read!(Path.join(@fixtures, "apt_upgradable.txt"))}
end
end
test "collects pveversion, zfs version and pending upgrade count" do
sample = SystemInfo.collect(runner: fake_runner())
assert sample.pve_version =~ "pve-manager/8.3.1"
assert sample.zfs_version =~ "2.3.0"
assert sample.pending_updates == 2
assert sample.errors == []
end
test "partial sample when one command fails" do
partial = fn
"pveversion", [] -> {:ok, "pve-manager/8.3.1/abc (running kernel: 6.8.12-1-pve)\n"}
"zfs", ["--version"] -> {:error, {:enoent, "zfs"}}
"apt", ["list", "--upgradable"] -> {:ok, "Listing...\n"}
end
sample = SystemInfo.collect(runner: partial)
assert sample.pve_version =~ "8.3.1"
assert sample.zfs_version == nil
assert sample.pending_updates == 0
assert length(sample.errors) == 1
end
end