From b13fc37cc41066854e2e3e69be18632b2ce25451 Mon Sep 17 00:00:00 2001 From: benya Date: Fri, 5 Jun 2026 02:25:02 +0300 Subject: [PATCH] Add agent version reporting --- agent/openwrt/rmm-agent.sh | 55 +++++++++++++++++-- .../package/rmm-agent/files/usr/bin/rmm-agent | 55 +++++++++++++++++-- web/app.js | 15 +++++ web/index.html | 4 ++ web/styles.css | 4 -- 5 files changed, 117 insertions(+), 16 deletions(-) diff --git a/agent/openwrt/rmm-agent.sh b/agent/openwrt/rmm-agent.sh index 02f8c5f..398b0ba 100644 --- a/agent/openwrt/rmm-agent.sh +++ b/agent/openwrt/rmm-agent.sh @@ -1,6 +1,7 @@ #!/bin/sh set -u +AGENT_VERSION="${AGENT_VERSION:-0.4.0}" CONFIG_FILE="${CONFIG_FILE:-/etc/rmm-agent.conf}" SERVER_URL="${SERVER_URL:-http://127.0.0.1:8080}" ENROLLMENT_TOKEN="${ENROLLMENT_TOKEN:-dev-enroll-token}" @@ -118,6 +119,31 @@ http_post() { return 1 } +http_post_status() { + url="$1" + body="$2" + auth="${3:-}" + tmp="/tmp/rmm-agent-http-$$.out" + + if command -v curl >/dev/null 2>&1; then + if [ -n "$auth" ]; then + code="$(curl -sS -o "$tmp" -w '%{http_code}' -X POST "$url" -H "Content-Type: application/json" -H "Authorization: Bearer $auth" -d "$body" 2>/dev/null || true)" + else + code="$(curl -sS -o "$tmp" -w '%{http_code}' -X POST "$url" -H "Content-Type: application/json" -d "$body" 2>/dev/null || true)" + fi + rm -f "$tmp" + [ -n "$code" ] || code="000" + printf '%s' "$code" + return 0 + fi + + if http_post "$url" "$body" "$auth" >/dev/null; then + printf '200' + else + printf '000' + fi +} + http_get() { url="$1" @@ -355,8 +381,8 @@ build_inventory() { leases="$(json_array_or_empty "$(dhcp_leases_json)")" wifi="$(json_array_or_empty "$(wifi_clients_json)")" - printf '{"hostname":"%s","openwrt_version":"%s","board":%s,"interfaces":%s,"default_route":"%s","wan_ip":"%s","dhcp_leases":%s,"wifi_clients":%s}' \ - "$hn" "$ver" "$board" "$interfaces" "$route" "$wan" "$leases" "$wifi" + printf '{"hostname":"%s","openwrt_version":"%s","agent_version":"%s","board":%s,"interfaces":%s,"default_route":"%s","wan_ip":"%s","dhcp_leases":%s,"wifi_clients":%s}' \ + "$hn" "$ver" "$(json_escape "$AGENT_VERSION")" "$board" "$interfaces" "$route" "$wan" "$leases" "$wifi" } build_metrics() { @@ -880,10 +906,20 @@ send_command_result() { body="$(printf '{"device_id":"%s","status":"%s","exit_code":%s,"output":"%s","result":{}}' \ "$(json_escape "$DEVICE_ID")" "$status" "$exit_code" "$(json_escape "$output")")" - if ! http_post "$SERVER_URL/api/agent/commands/$command_id/result" "$body" "$DEVICE_TOKEN" >/dev/null; then + code="$(http_post_status "$SERVER_URL/api/agent/commands/$command_id/result" "$body" "$DEVICE_TOKEN")" + case "$code" in + 2??) + return 0 + ;; + 4??) + log "server rejected result for $command_id with HTTP $code" + return 0 + ;; + *) log "failed to send result for $command_id" spool_command_result "$command_id" "$body" - fi + ;; + esac } spool_command_result() { @@ -899,9 +935,16 @@ flush_spooled_results() { [ -f "$file" ] || continue command_id="$(basename "$file" .json)" body="$(cat "$file")" - if http_post "$SERVER_URL/api/agent/commands/$command_id/result" "$body" "$DEVICE_TOKEN" >/dev/null; then + code="$(http_post_status "$SERVER_URL/api/agent/commands/$command_id/result" "$body" "$DEVICE_TOKEN")" + case "$code" in + 2??) rm -f "$file" - fi + ;; + 4??) + log "dropping rejected spooled result for $command_id with HTTP $code" + rm -f "$file" + ;; + esac done } diff --git a/agent/package/rmm-agent/files/usr/bin/rmm-agent b/agent/package/rmm-agent/files/usr/bin/rmm-agent index 7a6273a..02f8034 100644 --- a/agent/package/rmm-agent/files/usr/bin/rmm-agent +++ b/agent/package/rmm-agent/files/usr/bin/rmm-agent @@ -1,6 +1,7 @@ #!/bin/sh set -u +AGENT_VERSION="${AGENT_VERSION:-0.4.0}" CONFIG_FILE="${CONFIG_FILE:-/etc/rmm-agent.conf}" SERVER_URL="${SERVER_URL:-http://127.0.0.1:8080}" ENROLLMENT_TOKEN="${ENROLLMENT_TOKEN:-dev-enroll-token}" @@ -118,6 +119,31 @@ http_post() { return 1 } +http_post_status() { + url="$1" + body="$2" + auth="${3:-}" + tmp="/tmp/rmm-agent-http-$$.out" + + if command -v curl >/dev/null 2>&1; then + if [ -n "$auth" ]; then + code="$(curl -sS -o "$tmp" -w '%{http_code}' -X POST "$url" -H "Content-Type: application/json" -H "Authorization: Bearer $auth" -d "$body" 2>/dev/null || true)" + else + code="$(curl -sS -o "$tmp" -w '%{http_code}' -X POST "$url" -H "Content-Type: application/json" -d "$body" 2>/dev/null || true)" + fi + rm -f "$tmp" + [ -n "$code" ] || code="000" + printf '%s' "$code" + return 0 + fi + + if http_post "$url" "$body" "$auth" >/dev/null; then + printf '200' + else + printf '000' + fi +} + http_get() { url="$1" @@ -355,8 +381,8 @@ build_inventory() { leases="$(json_array_or_empty "$(dhcp_leases_json)")" wifi="$(json_array_or_empty "$(wifi_clients_json)")" - printf '{"hostname":"%s","openwrt_version":"%s","board":%s,"interfaces":%s,"default_route":"%s","wan_ip":"%s","dhcp_leases":%s,"wifi_clients":%s}' \ - "$hn" "$ver" "$board" "$interfaces" "$route" "$wan" "$leases" "$wifi" + printf '{"hostname":"%s","openwrt_version":"%s","agent_version":"%s","board":%s,"interfaces":%s,"default_route":"%s","wan_ip":"%s","dhcp_leases":%s,"wifi_clients":%s}' \ + "$hn" "$ver" "$(json_escape "$AGENT_VERSION")" "$board" "$interfaces" "$route" "$wan" "$leases" "$wifi" } build_metrics() { @@ -806,10 +832,20 @@ send_command_result() { body="$(printf '{"device_id":"%s","status":"%s","exit_code":%s,"output":"%s","result":{}}' \ "$(json_escape "$DEVICE_ID")" "$status" "$exit_code" "$(json_escape "$output")")" - if ! http_post "$SERVER_URL/api/agent/commands/$command_id/result" "$body" "$DEVICE_TOKEN" >/dev/null; then + code="$(http_post_status "$SERVER_URL/api/agent/commands/$command_id/result" "$body" "$DEVICE_TOKEN")" + case "$code" in + 2??) + return 0 + ;; + 4??) + log "server rejected result for $command_id with HTTP $code" + return 0 + ;; + *) log "failed to send result for $command_id" spool_command_result "$command_id" "$body" - fi + ;; + esac } spool_command_result() { @@ -825,9 +861,16 @@ flush_spooled_results() { [ -f "$file" ] || continue command_id="$(basename "$file" .json)" body="$(cat "$file")" - if http_post "$SERVER_URL/api/agent/commands/$command_id/result" "$body" "$DEVICE_TOKEN" >/dev/null; then + code="$(http_post_status "$SERVER_URL/api/agent/commands/$command_id/result" "$body" "$DEVICE_TOKEN")" + case "$code" in + 2??) rm -f "$file" - fi + ;; + 4??) + log "dropping rejected spooled result for $command_id with HTTP $code" + rm -f "$file" + ;; + esac done } diff --git a/web/app.js b/web/app.js index de049dc..213cd94 100644 --- a/web/app.js +++ b/web/app.js @@ -21,6 +21,8 @@ const state = { presetReview: null, }; +const EXPECTED_AGENT_VERSION = "0.4.0"; + const els = { loginView: document.querySelector("#loginView"), loginForm: document.querySelector("#loginForm"), @@ -59,6 +61,7 @@ const els = { infoTarget: document.querySelector("#infoTarget"), infoSystem: document.querySelector("#infoSystem"), infoKernel: document.querySelector("#infoKernel"), + infoAgentVersion: document.querySelector("#infoAgentVersion"), infoCreatedAt: document.querySelector("#infoCreatedAt"), infoLastSeenAt: document.querySelector("#infoLastSeenAt"), infoDeviceId: document.querySelector("#infoDeviceId"), @@ -370,6 +373,16 @@ function deviceModel(device) { : "-"; } +function deviceAgentVersion(device) { + return device && device.inventory && device.inventory.agent_version ? String(device.inventory.agent_version) : ""; +} + +function agentVersionLabel(version) { + if (!version) return "неизвестна"; + if (version === EXPECTED_AGENT_VERSION) return `${version} актуальная`; + return `${version} требуется обновление`; +} + function deviceClientCount(device) { const leases = Array.isArray(device.inventory && device.inventory.dhcp_leases) ? device.inventory.dhcp_leases.length : 0; const wifi = Array.isArray(device.inventory && device.inventory.wifi_clients) ? device.inventory.wifi_clients.length : 0; @@ -399,6 +412,7 @@ function filteredDevices() { deviceDisplayName(device), device.id, device.openwrt_version, + deviceAgentVersion(device), deviceModel(device), device.inventory && device.inventory.wan_ip, device.group, @@ -507,6 +521,7 @@ function renderDeviceInformation(device) { els.infoTarget.textContent = release.target || "-"; els.infoSystem.textContent = board.system || "-"; els.infoKernel.textContent = board.kernel || "-"; + els.infoAgentVersion.textContent = agentVersionLabel(deviceAgentVersion(device)); els.infoCreatedAt.textContent = formatDate(device.created_at); els.infoLastSeenAt.textContent = formatDate(device.last_seen_at); els.infoDeviceId.textContent = device.id || "-"; diff --git a/web/index.html b/web/index.html index bbba0e2..6e49d68 100644 --- a/web/index.html +++ b/web/index.html @@ -206,6 +206,10 @@ Версия ядра - +
+ Версия агента + - +
Зарегистрирован - diff --git a/web/styles.css b/web/styles.css index 4bcfde5..ac93482 100644 --- a/web/styles.css +++ b/web/styles.css @@ -1283,10 +1283,6 @@ select { border-right: 0; } -.information-item:nth-last-child(-n + 4) { - border-bottom: 0; -} - .information-item span, .technical-details span { color: var(--muted);