Einen Agent verbinden
Es gibt zwei Wege, einen Agent in Caldera zu bringen. Beide enden gleich: Der Agent ist ein Eintrag in Caldera, er meldet im Agent-Protokoll, und ein Admin sieht und steuert ihn. Sie unterscheiden sich darin, wer das Melden betreibt und wem der Prozess des Agents gehört.
Die zwei Wege
| A. Eigener Reporter | B. Blueprint und Runtime | |
|---|---|---|
| Was meldet | Wenige Zeilen, die selbst geschrieben und als eigener Prozess betrieben werden. | Die Runtime caldera.pyz, die Caldera ausliefert. |
| Wer den Agent startet und stoppt | Die eigene Umgebung (systemd, cron, eigener Code). | Die Runtime (start, stop, Neustart mit Backoff). |
| Wie der Agent eingerichtet wird | Von Hand: Checkout, Geheimnisse, Unit-Dateien. | caldera init <code> aus einem veröffentlichten Blueprint. |
| Pause bedeutet | Was der Agent damit macht (eine Datei, ein Flag, eine gestoppte Unit). | Die Runtime stoppt den Prozess des Agents; Fortsetzen startet ihn. |
| Einstellungen | Ein Schema wird deklariert und die Grenzen werden im eigenen Code durchgesetzt. | Das Manifest deklariert Schema, Standardwerte und Grenzen; die Runtime setzt sie durch. |
| Updates | Werden selbst ausgerollt. | Caldera nennt eine Version; die Runtime lädt, prüft die Gesundheit, behält oder rollt zurück. |
| Zurückrollen | Eigene Sache. | caldera rollback auf dem Rechner, oder Caldera nennt die alte Version. |
| Braucht Python 3 | Nein. Jede Sprache, die JSON per POST senden kann. | Ja, auf dem Rechner des Agents. |
| Braucht Caldera zum Einrichten | Nur um den Agent und sein Token anzulegen. | Ja, für init (der Code). Zum Betrieb nie. |
| Geeignet für | Einen Agent, der schon existiert und einen eigenen Scheduler hat, oder einen ohne eigenen Prozess. | Einen neuen Agent, oder einen, der sich als ein dauerhaft laufender Prozess umbauen lässt. |
Wie wählen
- B wählen, wenn der Agent neu ist oder ein Programm, das als dauerhaft laufender Prozess laufen kann. Dann gibt es Einrichtung mit einem Befehl, Updates mit Gesundheitsprüfung und Rollback, das Einstellungsformular aus dem Manifest und Bots für den Zugriff auf die anderen Produkte der Suite.
- A wählen, wenn der Agent ein eigenes Leben hat, das Caldera nicht besitzen soll. Die Prozess-Runtime startet einen Prozess und pausiert, indem sie ihn stoppt. Hat der Agent keinen solchen Prozess (seine Läufe sind zum Beispiel ein Timer und seine Pause ist eine Datei, die auch ein Chat-Bot setzt), passt die Prozess-Runtime nicht. Dann entweder den eigenen Reporter behalten oder den Adapter-Modus nutzen, in dem die Runtime nichts startet und stoppt und einen Befehl aufruft, den der Agent bereitstellt.
- Mit A anfangen und später zu B wechseln ist möglich. Der Agent behält seinen Verlauf in Caldera nur, wenn derselbe Agent-Eintrag bleibt; eine Blueprint-Installation legt immer einen neuen Agent an. Der Wechsel steht unter Agents betreiben, mit dem Weg zurück.
Welcher Weg es auch ist, die feste Regel gilt: Der Agent darf Caldera zum Laufen nicht brauchen (siehe Konzepte).
Weg A: ein eigener Reporter
Schritte
-
Den Agent anlegen. Ein Admin öffnet die Übersicht, drückt "Neuer Agent", vergibt einen Namen und erhält das Token einmalig (
caldera_agt_...) mit zwei fertigen Zeilen:CALDERA_URL=https://app.calderaapp.io CALDERA_TOKEN=caldera_agt_...Gespeichert wird nur ein Hash des Tokens. Geht es verloren, wird es im Menü des Agents erneuert ("Token erneuern"): Das alte Token funktioniert sofort nicht mehr.
-
Die zwei Zeilen dorthin legen, wo der Reporter sie liest, in eine private Datei auf dem Rechner des Agents (Modus 600). Nie in ein Repository.
-
Den Reporter schreiben, gegen das Agent-Protokoll. Die Regeln, die einen Agent von Caldera unabhängig machen:
- ein eigener Prozess (ein systemd-User-Service oder ein Sidecar);
- ein Timeout bei jeder Anfrage;
- ist Caldera nicht erreichbar, langsam oder antwortet unsinnig: eine Zeile loggen, das nächste Intervall abwarten, erneut versuchen, sonst nichts ändern;
- Pause, Grenzen und Einstellungen sind die eigenen Dateien des Agents;
- ein Befehl ist ein Wunsch: gegen die eigenen Grenzen prüfen, anwenden oder ablehnen und mit einem Ack in der nächsten Meldung antworten;
- nur senden, was die Seite zeigen soll. Mail-Inhalte, Nachrichten und Ähnliches bleiben beim Agent. Logs sind die einzige Ausnahme, und der Agent entscheidet, welche er herausgibt.
-
Starten und die Seite prüfen. Der Agent erscheint nach der ersten Meldung in der Übersicht.
-
Die Unabhängigkeitsprobe machen.
Ein minimaler Reporter
Das ist die kleinste Schleife, die die Regeln einhält. handle durch eigene
Prüfungen ersetzen. Sie benutzt nur die Python-Standardbibliothek; jede Sprache
funktioniert.
import json
import os
import time
import urllib.error
import urllib.request
URL = os.environ["CALDERA_URL"].rstrip("/")
TOKEN = os.environ["CALDERA_TOKEN"]
def post(path, body):
request = urllib.request.Request(
URL + "/api/agent/v1" + path,
data=json.dumps(body).encode(),
method="POST",
headers={"Authorization": "Bearer " + TOKEN, "Content-Type": "application/json"},
)
with urllib.request.urlopen(request, timeout=30) as response: # immer ein Timeout
return json.load(response)
def handle(command):
"""Gibt (ok, message) zurück, oder None bei einem `log`-Befehl (der Upload ist die Antwort)."""
if command["type"] == "log":
# das Log senden mit post("/log", {"command": command["id"], "name": ..., "text": ...})
return None
return False, "This agent does not support that." # eine Ablehnung ist eine normale Antwort
acks, interval = [], 30
while True:
report = {
"protocol": 1,
"state": {"level": "ok", "label": "Ready"},
"controls": ["pause", "resume"],
"acks": acks,
}
try:
answer = post("/report", report)
acks = [] # zugestellt
interval = max(10, min(300, int(answer.get("interval", 30))))
for command in answer.get("commands", []):
result = handle(command)
if result is not None:
acks.append({"id": command["id"], "ok": result[0], "message": result[1]})
except (urllib.error.URLError, OSError, ValueError) as error:
print("caldera unreachable:", error) # eine Zeile, dann das nächste Intervall
time.sleep(interval if not acks else 2)
Was das Beispiel zeigt und worauf es ankommt:
ackswerden erst geleert, nachdem eine Meldung zugestellt wurde. So geht eine Antwort nicht an einer fehlgeschlagenen Anfrage verloren.- Ein Befehl wird höchstens einmal zugestellt. Geht die Antwort auf eine Meldung
verloren, geht der Befehl mit ihr verloren, und Caldera lässt ihn nach zehn Minuten
fehlschlagen. Das ist Absicht:
run_nowdarf nie zweimal laufen, nur weil ein Netz eine Antwort verloren hat. Eine Person kann ihn erneut senden. - Ein
nullin einer Meldung gilt als "nicht vorhanden", außer insettings.values, wonullbedeutet "diese Einstellung ist nicht gesetzt". Besser ist es, ein ungesetztes Feld wegzulassen. - Anteile (Gauges, Anteile an Gegenständen) sind Zahlen von 0 bis 1. Zeiten sind Unix-Sekunden.
Ein Muster: ein zeitgesteuerter Agent mit einer Datei als Pause
Ein Agent, dessen Läufe ein Timer sind und dessen Pause eine Datei ist, die auch
andere (zum Beispiel ein Chat-Bot) setzen und löschen, ist der typische Fall für einen
eigenen Reporter. Der Reporter ist ein eigener Service neben dem Timer. Calderas
pause legt dieselbe Datei an wie der Chat-Befehl, deshalb lässt sich eine in
Caldera gesetzte Pause ohne Caldera aufheben. resume löscht die Datei und sagt,
wenn eine andere Sperre (eine Person arbeitet in einer Sitzung, ein Build läuft) den
Agent weiter warten lässt. run_now legt eine Datei an, nach der der Scheduler des
Timers sucht. Einstellungen sind eine feste Liste von Feldern mit harten Grenzen, in
die eigene Konfiguration des Agents geschrieben; alles andere wird abgelehnt, und
ein set-Befehl gilt ganz oder gar nicht. Logs sind auf Namen beschränkt, die der
Agent selbst kennt, und es werden nur die letzten 512 KB gesendet.
Soll ein solcher Agent zusätzlich Einrichtung und Updates von Caldera bekommen, gibt es den Adapter-Modus.
Gauges aus der letzten eigenen Beobachtung
Ein Gauge, das aus der letzten eigenen Beobachtung des Agents gebaut wird (zum
Beispiel das Kontingent nach dem letzten Modellaufruf), kann der Seite des Anbieters
hinterherhinken, weil andere Sitzungen dasselbe Kontingent verbrauchen und ein Agent,
der seine Läufe über einer Schwelle anhält, keine neue Beobachtung macht. Die Zeit
der Messung gehört in das detail des Gauges (zum Beispiel "Stand 06.10. 14:05,
..."), damit ein veralteter Wert als veraltet erkennbar ist. Siehe
Agents betreiben.
Weg B: ein Blueprint unter der Runtime
Schritte
- Den Blueprint schreiben. Ein Manifest
caldera.agent.yaml, die Dateien des Agents und ein Health-Befehl. Siehe Blueprints und Das Manifest. - Eine Version hochladen und veröffentlichen, im Workspace (Blueprints, der Blueprint, "Version hochladen", dann "Veröffentlichen"). Eine veröffentlichte Version ändert sich nie.
- Einen Install-Code ausstellen ("Installieren"): Version und Agent-Name wählen. Caldera zeigt zwei Befehle.
- Auf dem Rechner: die zwei Befehle ausführen:
caldera.pyzladen und prüfen, dannpython3 caldera.pyz init <code> --url https://app.calderaapp.io. Das Werkzeug zeigt, was eingerichtet wird, fragt auf dem Rechner nach den deklarierten Geheimnissen (sie erreichen Caldera nie) und löst erst dann den Code ein. Es schreibt das Verzeichnis, installiert eine systemd-User-Unit und startet sie. - Prüfen:
python3 caldera.pyz status --dir <dir>und die Seite des Agents. - Die Unabhängigkeitsprobe machen.
Die Einzelheiten jedes Schritts stehen unter Die Runtime und Blueprints.
Ein Muster: ein dauerhaft laufender Prozess
Ein Agent, der zur Prozess-Runtime passt, ist ein Programm mit eigener Zeitplanung,
zum Beispiel ein Prozess mit einem Thread je Aufgabe. Er schreibt alle 30 Sekunden und
bei jeder Änderung atomar eine Status-Datei, mit einem Heartbeat, den sein
Health-Befehl liest. Pause heißt, dass die Runtime den Prozess stoppt; "Jetzt
ausführen" ist eine Datei, die der Agent jede Sekunde prüft. Seine Geheimnisse und
Daten bleiben, wo sie waren, außerhalb des Bundles, und das Manifest deklariert nur
die Pfade, die ein Update überleben müssen. Offline pausiert caldera pause auf dem
Rechner.
Die Unabhängigkeitsprobe
Gehört zum Verbinden jedes Agents. Das Ergebnis im eigenen Repository des Agents festhalten, denn dort liegt der Reporter.
Weg A:
CALDERA_URLauf einen Host setzen, den es nicht gibt (zum Beispielhttps://caldera.invalid), und den Reporter-Service neu starten.- Einen Lauf starten. Er muss zu Ende laufen; das Log darf nur sagen, dass Caldera nicht erreichbar ist.
- Zuerst in Caldera eine Pause setzen, dann Caldera wie in Schritt 1 unerreichbar machen. Der eigene Kanal des Agents muss die Pause aufheben können.
CALDERA_URLwiederherstellen, neu starten; die nächste Meldung kommt binnen eines Intervalls an.
Was nie passieren darf: ein Lauf wartet auf Caldera, eine Pause lässt sich nur aus Caldera aufheben, oder ein Fehler im Reporter hält den Scheduler des Agents an.
Weg B (Runtime):
- Die URL der Runtime auf nichts richten oder das Netz sperren. Der Prozess des
Agents muss weiterlaufen;
status,pause,resumeundrollbackmüssen funktionieren. python3 caldera.pyz pause --dir <dir>und danachresumemüssen offline funktionieren.- Die Runtime zu stoppen darf den Agent nicht stoppen.