Neue Agenten-Rolle "ops" mit Schreibtischplatz (Issue #66)
Fuer den Betrieb fehlte bisher eine Rolle: "user" meldet zwar Daten, bleibt in der Buero-Visualisierung aber unsichtbar, weil sie nie einen Schreibtisch bekommt. Der Ping-Check aus check_fds.sh (Weg 3 im README) lief deshalb als "user" und tauchte im Buero nicht auf. "ops" fuellt die Luecke: die Schreibtischvergabe in AgentRepository::register() greift automatisch, sobald die Rolle erlaubt ist - nur "user" bleibt ohne Platz. Der CHECK-Constraint auf agents.role braucht dafuer eine eigene Migration. Ein Edit von 001_initial.sql wuerde nur frische Datenbanken erreichen: bestehende Installationen haben die Migration laut schema_migrations laengst angewandt und wuerden bei role='ops' weiterhin abbrechen. SQLite kann CHECK nicht per ALTER TABLE aendern, 004 baut die Tabelle deshalb neu (Verfahren aus der SQLite-Doku, foreign_keys kurz aus, weil tickets.assignee_agent_id auf agents zeigt). Im Frontend bekommt die Rolle Label "OPs", eine Akzentfarbe und ein Zahnrad als Schreibtisch-Deko - ohne Eintrag in der ROLES-Map rendert der Avatar grau und ohne Label. Neu ist ausserdem register-ops-agent.sh neben der docker-compose.yml: es liest Admin-Key und Basis-URL aus der .env, registriert den lokalen OPs-Agenten und schreibt den nur einmalig ausgegebenen API-Key mit chmod 600 nach monitor-api.conf - also genau die beiden Schritte aus Weg 3, die hosts.conf und credentials.conf nicht abdecken. Eine vorhandene monitor-api.conf ueberschreibt es nicht, und ein zweiter Agent gleichen Namens (der einen weiteren der acht Schreibtische belegen wuerde) wird vorher abgefangen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
31fcc16ca8
commit
9af2f82801
12 changed files with 248 additions and 11 deletions
8
API.md
8
API.md
|
|
@ -63,12 +63,18 @@ Fehlt oder passt ein Key nicht, antwortet die API mit `401 Unauthorized`.
|
||||||
|
|
||||||
## Agenten
|
## Agenten
|
||||||
|
|
||||||
Rollen (F1/F2): `entwickler`, `product_owner`, `qa`, `user`. Ein Agent bekommt bei der
|
Rollen (F1/F2): `entwickler`, `product_owner`, `qa`, `ops`, `user`. Ein Agent bekommt bei der
|
||||||
Registrierung fest einen von `MONITOR_DESK_COUNT` (Standard 8) Schreibtischen zugewiesen
|
Registrierung fest einen von `MONITOR_DESK_COUNT` (Standard 8) Schreibtischen zugewiesen
|
||||||
(niedrigster freier Index). Die Rolle `user` bekommt nie einen Schreibtisch (kein fester
|
(niedrigster freier Index). Die Rolle `user` bekommt nie einen Schreibtisch (kein fester
|
||||||
Sitzplatz). Sind alle Schreibtische belegt, wird trotzdem registriert, aber ohne
|
Sitzplatz). Sind alle Schreibtische belegt, wird trotzdem registriert, aber ohne
|
||||||
Schreibtisch (`desk_index: null`).
|
Schreibtisch (`desk_index: null`).
|
||||||
|
|
||||||
|
`ops` (Issue #66) ist die Rolle fuer den Betrieb - etwa den Ping-Check aus `check_fds.sh`,
|
||||||
|
der seine Ergebnisse per REST meldet (siehe README, "Weg 3"). Sie bekommt wie die uebrigen
|
||||||
|
Rollen einen Schreibtisch, in der Buero-Visualisierung mit dem Label "OPs" und einem
|
||||||
|
Zahnrad als Deko. Registrieren laesst sich der lokale OPs-Agent mit
|
||||||
|
`register-ops-agent.sh`, das zugleich `monitor-api.conf` schreibt.
|
||||||
|
|
||||||
### `POST /api/v1/agents` — Agent registrieren
|
### `POST /api/v1/agents` — Agent registrieren
|
||||||
|
|
||||||
Auth: `X-Admin-Key`.
|
Auth: `X-Admin-Key`.
|
||||||
|
|
|
||||||
19
README.md
19
README.md
|
|
@ -56,6 +56,8 @@ die dazugehörigen Klärungen in [Detailfragen.md](Detailfragen.md) und
|
||||||
[README_UPDATE.md](README_UPDATE.md)
|
[README_UPDATE.md](README_UPDATE.md)
|
||||||
- `register-agent.sh` — Hilfsskript, um einen neuen Agenten per `POST /api/v1/agents` zu
|
- `register-agent.sh` — Hilfsskript, um einen neuen Agenten per `POST /api/v1/agents` zu
|
||||||
registrieren (siehe [API.md](API.md) Abschnitt "Agenten")
|
registrieren (siehe [API.md](API.md) Abschnitt "Agenten")
|
||||||
|
- `register-ops-agent.sh` — registriert den lokalen OPs-Agenten (Rolle `ops`) und legt dabei
|
||||||
|
`monitor-api.conf` für die Statusmeldung des Ping-Checks an (siehe "Weg 3" unten)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -134,10 +136,19 @@ Kombiniert beide Wege und ist der richtige Weg, wenn der Ping-Check auf einem an
|
||||||
läuft als die API — dann fällt der Umweg über die Datei `status.txt` weg:
|
läuft als die API — dann fällt der Umweg über die Datei `status.txt` weg:
|
||||||
|
|
||||||
1. Wie in Weg 1 die `hosts.conf` pflegen und `check_fds.sh` per Cron laufen lassen.
|
1. Wie in Weg 1 die `hosts.conf` pflegen und `check_fds.sh` per Cron laufen lassen.
|
||||||
2. Wie in Weg 2 einen Agenten registrieren (Rolle `user`, damit er keinen Schreibtisch in der
|
2. Den OPs-Agenten registrieren — das erledigt `register-ops-agent.sh` neben der
|
||||||
Büro-Visualisierung belegt).
|
`docker-compose.yml` in einem Schritt (die API muss dafür laufen):
|
||||||
3. `monitor-api-sample.conf` nach `monitor-api.conf` neben `check_fds.sh` kopieren, dort
|
```bash
|
||||||
`MONITOR_API_BASE` und `MONITOR_API_KEY` eintragen und die Datei auf `chmod 600` setzen.
|
./register-ops-agent.sh # optional: ./register-ops-agent.sh "OPs Rechenzentrum"
|
||||||
|
```
|
||||||
|
Das Skript liest `MONITOR_ADMIN_API_KEY` und `MONITOR_API_BASE` aus der `.env`, legt einen
|
||||||
|
Agenten der Rolle `ops` an (sitzt als „OPs" sichtbar an einem Schreibtisch, Issue #66) und
|
||||||
|
schreibt den nur einmalig ausgegebenen API-Key mit `chmod 600` nach `monitor-api.conf`.
|
||||||
|
Eine bestehende `monitor-api.conf` überschreibt es nicht (`--force` erzwingt es).
|
||||||
|
|
||||||
|
Von Hand geht es weiterhin so: Agenten wie in Weg 2 registrieren (Rolle `ops`),
|
||||||
|
`monitor-api-sample.conf` nach `monitor-api.conf` neben `check_fds.sh` kopieren, dort
|
||||||
|
`MONITOR_API_BASE` (ohne `/api/v1`) und `MONITOR_API_KEY` eintragen, `chmod 600` setzen.
|
||||||
|
|
||||||
`check_fds.sh` meldet dann nach jedem Ping zusätzlich per REST (`online` → `ok`,
|
`check_fds.sh` meldet dann nach jedem Ping zusätzlich per REST (`online` → `ok`,
|
||||||
`offline` → `error`) und schreibt `status.txt` unverändert weiter für den alten Wandmonitor.
|
`offline` → `error`) und schreibt `status.txt` unverändert weiter für den alten Wandmonitor.
|
||||||
|
|
|
||||||
40
api/src/Db/migrations/004_agent_role_ops.sql
Normal file
40
api/src/Db/migrations/004_agent_role_ops.sql
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
-- Issue #66: Neue Agenten-Rolle "ops" fuer den Betrieb (z.B. den Ping-Check aus
|
||||||
|
-- check_fds.sh). Anders als "user" bekommt sie einen festen Schreibtisch in der
|
||||||
|
-- Buero-Visualisierung; die Vergabe in AgentRepository::register() greift automatisch,
|
||||||
|
-- sobald die Rolle erlaubt ist.
|
||||||
|
--
|
||||||
|
-- SQLite kennt kein "ALTER TABLE ... DROP/ADD CONSTRAINT", der CHECK aus
|
||||||
|
-- 001_initial.sql laesst sich also nur ueber einen Tabellen-Neubau erweitern (Verfahren
|
||||||
|
-- aus der SQLite-Doku, "Making Other Kinds Of Table Schema Changes"). Ein Edit von
|
||||||
|
-- 001_initial.sql reicht nicht: bestehende Installationen haben die Migration laut
|
||||||
|
-- schema_migrations laengst angewandt und wuerden bei role='ops' weiterhin abbrechen.
|
||||||
|
--
|
||||||
|
-- foreign_keys wird dafuer kurz abgeschaltet, weil tickets.assignee_agent_id auf agents
|
||||||
|
-- zeigt - mit aktiven Fremdschluesseln wuerde DROP TABLE die Zuweisungen mitnehmen. Nach
|
||||||
|
-- dem Umbenennen traegt die neue Tabelle wieder den Namen "agents", der FK in tickets
|
||||||
|
-- zeigt also unveraendert richtig.
|
||||||
|
PRAGMA foreign_keys = OFF;
|
||||||
|
|
||||||
|
CREATE TABLE agents_new (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
display_name TEXT NOT NULL,
|
||||||
|
role TEXT NOT NULL CHECK (role IN ('entwickler', 'product_owner', 'qa', 'ops', 'user')),
|
||||||
|
api_key_hash TEXT NOT NULL UNIQUE,
|
||||||
|
desk_index INTEGER,
|
||||||
|
state TEXT NOT NULL DEFAULT 'idle',
|
||||||
|
current_ticket_id INTEGER,
|
||||||
|
created_at TEXT NOT NULL,
|
||||||
|
last_seen_at TEXT,
|
||||||
|
FOREIGN KEY (current_ticket_id) REFERENCES tickets (id)
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO agents_new (id, display_name, role, api_key_hash, desk_index, state,
|
||||||
|
current_ticket_id, created_at, last_seen_at)
|
||||||
|
SELECT id, display_name, role, api_key_hash, desk_index, state,
|
||||||
|
current_ticket_id, created_at, last_seen_at
|
||||||
|
FROM agents;
|
||||||
|
|
||||||
|
DROP TABLE agents;
|
||||||
|
ALTER TABLE agents_new RENAME TO agents;
|
||||||
|
|
||||||
|
PRAGMA foreign_keys = ON;
|
||||||
|
|
@ -12,7 +12,7 @@ use Monitor\Api\Http\NotFoundException;
|
||||||
final class AgentRepository
|
final class AgentRepository
|
||||||
{
|
{
|
||||||
/** @var string[] */
|
/** @var string[] */
|
||||||
public const ROLES = ['entwickler', 'product_owner', 'qa', 'user'];
|
public const ROLES = ['entwickler', 'product_owner', 'qa', 'ops', 'user'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Praesenz-Timeout (Issue #17/#20): ein Agent gilt nur noch als anwesend, solange
|
* Praesenz-Timeout (Issue #17/#20): ein Agent gilt nur noch als anwesend, solange
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,20 @@ final class AgentRepositoryTest extends TestCase
|
||||||
self::assertNull($result['agent']['desk_index']);
|
self::assertNull($result['agent']['desk_index']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Issue #66: "ops" ist die Rolle fuer den Betrieb (z.B. der Ping-Check) und sitzt -
|
||||||
|
* anders als "user" - sichtbar an einem Schreibtisch. Der Test deckt zugleich den
|
||||||
|
* erweiterten CHECK-Constraint aus 004_agent_role_ops.sql ab: ohne ihn wuerde das
|
||||||
|
* INSERT scheitern, nicht erst die Zuweisung.
|
||||||
|
*/
|
||||||
|
public function testOpsRoleGetsADesk(): void
|
||||||
|
{
|
||||||
|
$result = $this->repository->register('OPs', 'ops');
|
||||||
|
|
||||||
|
self::assertSame('ops', $result['agent']['role']);
|
||||||
|
self::assertSame(0, $result['agent']['desk_index']);
|
||||||
|
}
|
||||||
|
|
||||||
public function testOverflowAgentGetsNoDeskWhenAllOccupied(): void
|
public function testOverflowAgentGetsNoDeskWhenAllOccupied(): void
|
||||||
{
|
{
|
||||||
$this->repository->register('Alice', 'entwickler');
|
$this->repository->register('Alice', 'entwickler');
|
||||||
|
|
|
||||||
|
|
@ -378,6 +378,16 @@ header.office-header h1 {
|
||||||
stroke-linejoin: round;
|
stroke-linejoin: round;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.desk-deco-gear circle,
|
||||||
|
.desk-deco-gear rect {
|
||||||
|
fill: #a78bfa;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Heller Kern, damit der gefuellte Kreis als Zahnrad-Ring lesbar wird (wie beim Bluetenkern). */
|
||||||
|
.desk-deco-gear-center {
|
||||||
|
fill: #ede9fe !important;
|
||||||
|
}
|
||||||
|
|
||||||
.desk-empty .desk-chair {
|
.desk-empty .desk-chair {
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ export const DEMO_AGENTS = [
|
||||||
{ name: "Quentin", role: "qa", pose: "idle" },
|
{ name: "Quentin", role: "qa", pose: "idle" },
|
||||||
{ name: "Dirk", role: "entwickler", pose: "working" },
|
{ name: "Dirk", role: "entwickler", pose: "working" },
|
||||||
{ name: "Nadja", role: "qa", pose: "coffee" },
|
{ name: "Nadja", role: "qa", pose: "coffee" },
|
||||||
null,
|
{ name: "Olaf", role: "ops", pose: "working" },
|
||||||
null,
|
null,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -639,6 +639,30 @@ function renderDeskAt(origin, agent, width = DESK.w) {
|
||||||
g.appendChild(
|
g.appendChild(
|
||||||
el("path", { d: `M${width - 58},24 l8,8 16,-18`, class: "desk-deco desk-deco-check" })
|
el("path", { d: `M${width - 58},24 l8,8 16,-18`, class: "desk-deco desk-deco-check" })
|
||||||
);
|
);
|
||||||
|
} else if (role.deco === "gear") {
|
||||||
|
const cx = width - 45;
|
||||||
|
const cy = 22;
|
||||||
|
// Zahnrad = Ring plus sechs Zaehne, jeder um 60 Grad um die Mitte gedreht.
|
||||||
|
const teeth = [];
|
||||||
|
for (let i = 0; i < 6; i++) {
|
||||||
|
teeth.push(
|
||||||
|
el("rect", {
|
||||||
|
x: cx - 2.5,
|
||||||
|
y: cy - 15,
|
||||||
|
width: 5,
|
||||||
|
height: 7,
|
||||||
|
rx: 1,
|
||||||
|
transform: `rotate(${i * 60}, ${cx}, ${cy})`,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
g.appendChild(
|
||||||
|
el("g", { class: "desk-deco desk-deco-gear" }, [
|
||||||
|
...teeth,
|
||||||
|
el("circle", { cx, cy, r: 9 }),
|
||||||
|
el("circle", { cx, cy, r: 3.5, class: "desk-deco-gear-center" }),
|
||||||
|
])
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Blockierte Agenten faerben ihr Namensschild ein. Der Zustand steckt hier in der Pose, weil
|
// Blockierte Agenten faerben ihr Namensschild ein. Der Zustand steckt hier in der Pose, weil
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ export const ROLES = {
|
||||||
entwickler: { label: "Entwickler:in", accentColor: "#3b82f6", deco: "star" },
|
entwickler: { label: "Entwickler:in", accentColor: "#3b82f6", deco: "star" },
|
||||||
product_owner: { label: "Product Owner:in", accentColor: "#ec4899", deco: "flower" },
|
product_owner: { label: "Product Owner:in", accentColor: "#ec4899", deco: "flower" },
|
||||||
qa: { label: "QA / Tester:in", accentColor: "#22c55e", deco: "check" },
|
qa: { label: "QA / Tester:in", accentColor: "#22c55e", deco: "check" },
|
||||||
|
ops: { label: "OPs", accentColor: "#8b5cf6", deco: "gear" },
|
||||||
user: { label: "User", accentColor: "#f59e0b", deco: "none" },
|
user: { label: "User", accentColor: "#f59e0b", deco: "none" },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,10 @@
|
||||||
# Diese Datei nach "monitor-api.conf" neben check_fds.sh kopieren und ausfuellen. Fehlt sie
|
# Diese Datei nach "monitor-api.conf" neben check_fds.sh kopieren und ausfuellen. Fehlt sie
|
||||||
# oder bleibt ein Wert leer, meldet check_fds.sh wie bisher nur nach status.txt und per Mail.
|
# oder bleibt ein Wert leer, meldet check_fds.sh wie bisher nur nach status.txt und per Mail.
|
||||||
#
|
#
|
||||||
# Der Key gehoert einem eigens registrierten Agenten der Rolle "user" - die bekommt nie einen
|
# Der Key gehoert einem eigens registrierten Agenten der Rolle "ops" (Issue #66), der in der
|
||||||
# Schreibtisch in der Buero-Visualisierung (AgentRepository::register). Anlegen mit
|
# Buero-Visualisierung als "OPs" an einem Schreibtisch sitzt. Am einfachsten legt
|
||||||
# register-agent.sh; der Key wird nur bei der Registrierung einmalig ausgegeben.
|
# register-ops-agent.sh beides an - Agent und diese Datei; der Key wird nur bei der
|
||||||
|
# Registrierung einmalig ausgegeben.
|
||||||
#
|
#
|
||||||
# Enthaelt ein Secret: chmod 600 monitor-api.conf
|
# Enthaelt ein Secret: chmod 600 monitor-api.conf
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ ADMIN_API_KEY=""
|
||||||
# Anzeigename des neuen Agenten
|
# Anzeigename des neuen Agenten
|
||||||
DISPLAY_NAME=""
|
DISPLAY_NAME=""
|
||||||
|
|
||||||
# Rolle: entwickler | product_owner | qa | user
|
# Rolle: entwickler | product_owner | qa | ops | user
|
||||||
ROLE="entwickler"
|
ROLE="entwickler"
|
||||||
|
|
||||||
# -------------------------------------------------------------------------------
|
# -------------------------------------------------------------------------------
|
||||||
|
|
|
||||||
130
register-ops-agent.sh
Executable file
130
register-ops-agent.sh
Executable file
|
|
@ -0,0 +1,130 @@
|
||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Registriert den lokalen OPs-Agenten (Rolle "ops", Issue #66) bei der monitor-API und legt
|
||||||
|
# die Zugangsdaten fuer check_fds.sh in monitor-api.conf ab - also genau die beiden Schritte
|
||||||
|
# aus "Weg 3" im README, die sich nicht in hosts.conf/credentials.conf erledigen lassen.
|
||||||
|
#
|
||||||
|
# Aufruf (im Verzeichnis mit docker-compose.yml, die API muss laufen):
|
||||||
|
#
|
||||||
|
# ./register-ops-agent.sh [Anzeigename] # Standard-Anzeigename: "OPs"
|
||||||
|
#
|
||||||
|
# Ueberschreibbar per Umgebungsvariable: MONITOR_API_BASE, MONITOR_ADMIN_API_KEY.
|
||||||
|
#
|
||||||
|
# Wichtig: Den API-Key gibt die API nur bei der Registrierung einmalig heraus - deshalb
|
||||||
|
# ueberschreibt das Skript eine vorhandene monitor-api.conf nicht (--force erzwingt es,
|
||||||
|
# der alte Agent bleibt dann mit seinem Schreibtisch registriert).
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
ENV_FILE="$SCRIPT_DIR/.env"
|
||||||
|
API_CONF="${MONITOR_API_CONF:-$SCRIPT_DIR/monitor-api.conf}"
|
||||||
|
|
||||||
|
DISPLAY_NAME="OPs"
|
||||||
|
FORCE=0
|
||||||
|
for arg in "$@"; do
|
||||||
|
case "$arg" in
|
||||||
|
-f|--force) FORCE=1 ;;
|
||||||
|
-h|--help) sed -n '2,20p' "${BASH_SOURCE[0]}" | sed 's/^# \?//'; exit 0 ;;
|
||||||
|
-*) echo "Unbekannte Option: $arg" >&2; exit 1 ;;
|
||||||
|
*) DISPLAY_NAME="$arg" ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if ! command -v curl >/dev/null 2>&1; then
|
||||||
|
echo "Fehler: curl wird benoetigt." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Werte aus der .env lesen, statt sie zu sourcen: die Datei enthaelt Kommentare und Werte,
|
||||||
|
# die als Shell-Code anders bedeuten wuerden, als sie Docker Compose liest.
|
||||||
|
env_value() {
|
||||||
|
[ -f "$ENV_FILE" ] || return 0
|
||||||
|
sed -n "s/^[[:space:]]*$1=//p" "$ENV_FILE" | tail -n1 \
|
||||||
|
| sed -e 's/^"\(.*\)"$/\1/' -e "s/^'\(.*\)'\$/\1/"
|
||||||
|
}
|
||||||
|
|
||||||
|
ADMIN_API_KEY="${MONITOR_ADMIN_API_KEY:-$(env_value MONITOR_ADMIN_API_KEY)}"
|
||||||
|
API_BASE="${MONITOR_API_BASE:-$(env_value MONITOR_API_BASE)}"
|
||||||
|
API_BASE="${API_BASE:-http://localhost:8091}"
|
||||||
|
|
||||||
|
# In der .env steht die Basis-URL inklusive "/api/v1" (so braucht sie das Frontend),
|
||||||
|
# monitor-api.conf dagegen ohne - check_fds.sh haengt den Pfad selbst an.
|
||||||
|
API_ROOT="${API_BASE%/}"
|
||||||
|
API_ROOT="${API_ROOT%/api/v1}"
|
||||||
|
|
||||||
|
if [ -z "$ADMIN_API_KEY" ]; then
|
||||||
|
echo "Fehler: MONITOR_ADMIN_API_KEY steht weder in der Umgebung noch in $ENV_FILE." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ "$ADMIN_API_KEY" = "change-me" ]; then
|
||||||
|
echo "Fehler: MONITOR_ADMIN_API_KEY ist noch der Beispielwert 'change-me'." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ -e "$API_CONF" ] && [ "$FORCE" -ne 1 ]; then
|
||||||
|
echo "Fehler: $API_CONF existiert bereits - der bisherige OPs-Agent ist offenbar schon" >&2
|
||||||
|
echo " registriert. Zum Neuanlegen die Datei wegsichern oder --force angeben." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
json_escape() {
|
||||||
|
printf '%s' "$1" | sed -e 's/\\/\\\\/g' -e 's/"/\\"/g'
|
||||||
|
}
|
||||||
|
|
||||||
|
# Ein zweiter Agent gleichen Namens wuerde einen weiteren der acht Schreibtische belegen.
|
||||||
|
# GET /api/v1/agents ist unauthentifiziert (API.md "Agenten") und dient hier auch als
|
||||||
|
# Erreichbarkeitspruefung.
|
||||||
|
agents_json=$(curl -sS --max-time 10 "$API_ROOT/api/v1/agents" 2>/dev/null) || {
|
||||||
|
echo "Fehler: API unter $API_ROOT nicht erreichbar. Laeuft 'docker compose up'?" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
if printf '%s' "$agents_json" | grep -q "\"display_name\":\"$(json_escape "$DISPLAY_NAME")\""; then
|
||||||
|
echo "Fehler: Ein Agent namens \"$DISPLAY_NAME\" ist bereits registriert." >&2
|
||||||
|
echo " Anderen Anzeigenamen uebergeben oder den alten Agenten loeschen." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
response=$(curl -sS -w '\n%{http_code}' --max-time 10 -X POST "$API_ROOT/api/v1/agents" \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-H "X-Admin-Key: $ADMIN_API_KEY" \
|
||||||
|
-d "{\"display_name\": \"$(json_escape "$DISPLAY_NAME")\", \"role\": \"ops\"}")
|
||||||
|
|
||||||
|
http_code=$(printf '%s' "$response" | tail -n1)
|
||||||
|
body=$(printf '%s' "$response" | sed '$d')
|
||||||
|
|
||||||
|
if [ "$http_code" != "201" ]; then
|
||||||
|
echo "Fehler: Registrierung fehlgeschlagen (HTTP $http_code)." >&2
|
||||||
|
echo "$body" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
api_key=$(printf '%s' "$body" | grep -oE '"api_key":"[0-9a-f]+"' | head -n1 | cut -d'"' -f4)
|
||||||
|
agent_id=$(printf '%s' "$body" | grep -oE '"id":[0-9]+' | head -n1 | cut -d: -f2)
|
||||||
|
desk_index=$(printf '%s' "$body" | grep -oE '"desk_index":(null|[0-9]+)' | head -n1 | cut -d: -f2)
|
||||||
|
|
||||||
|
if [ -z "$api_key" ]; then
|
||||||
|
echo "Fehler: Die Antwort enthielt keinen api_key:" >&2
|
||||||
|
echo "$body" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Erst die Rechte setzen, dann schreiben - sonst stuende das Secret kurzzeitig lesbar da.
|
||||||
|
umask 077
|
||||||
|
cat > "$API_CONF" <<CONF
|
||||||
|
# Zugangsdaten, mit denen check_fds.sh die Ping-Ergebnisse per REST an die monitor-API
|
||||||
|
# meldet. Angelegt von register-ops-agent.sh am $(date +%Y-%m-%d) fuer den Agenten
|
||||||
|
# "$DISPLAY_NAME" (Rolle "ops", ID $agent_id). Enthaelt ein Secret: chmod 600.
|
||||||
|
|
||||||
|
MONITOR_API_BASE="$API_ROOT"
|
||||||
|
MONITOR_API_KEY="$api_key"
|
||||||
|
CONF
|
||||||
|
chmod 600 "$API_CONF"
|
||||||
|
|
||||||
|
echo "OPs-Agent \"$DISPLAY_NAME\" registriert (ID $agent_id, Schreibtisch $desk_index)."
|
||||||
|
echo "Zugangsdaten geschrieben: $API_CONF"
|
||||||
|
echo
|
||||||
|
echo "Naechste Schritte:"
|
||||||
|
echo " 1. Ping-Check testen: $SCRIPT_DIR/check_fds.sh"
|
||||||
|
echo " 2. Ergebnis pruefen: curl -s $API_ROOT/api/v1/systems"
|
||||||
|
echo " 3. Per Cron einplanen, z.B.:"
|
||||||
|
echo " */5 * * * * $SCRIPT_DIR/check_fds.sh >> /var/log/check_fds.log 2>&1"
|
||||||
Loading…
Add table
Reference in a new issue