Zum Inhalt

English

Software starten und bestätigen

Für Hersteller, deren eigene Software (die Betriebssoftware) die Konfiguration nutzt, die der Agent holt. Der Agent startet Ihre Software nicht. Zwei Dinge verbinden beide: eine Markierungsdatei, die Ihrem Image sagt, dass die Konfiguration gespeichert ist, und eine zweite Markierung, die Ihre Software schreibt, sobald sie mit ihrem Ziel verbunden ist.

Bereit und bestätigt

Der Agent meldet der Plattform zwei verschiedene Dinge.

Schritt Bedeutung Wer es sieht
complete Die Konfiguration ist auf dem Gateway gespeichert. Das heißt „bereit“: Ihre Software darf starten. Die Plattform setzt das Gerät auf PROVISIONED. Ihr Image sieht die Datei /etc/iot-config/profile-ready.
confirmed Ihre Software ist mit ihrer Zielplattform verbunden. Die Plattform setzt das Gerät auf ACTIVE. Das ist der einzige Schritt, der abgerechnet wird, einmal pro Gerät.

Abgerechnet wird nur confirmed. Das Speichern der Konfiguration (complete) und beliebig viele Check-ins werden nicht abgerechnet. Ein Gerät, dessen Software die Bestätigungsdatei unten nie schreibt, wird nie abgerechnet und bleibt PROVISIONED.

Ihre Software mit einer Path-Unit starten

Der Agent ersetzt /etc/iot-config/profile-ready nach jeder neu gespeicherten Konfiguration, und erst, nachdem die Konfiguration selbst sicher geschrieben ist. Nach einem Neustart stellt er die gespeicherte Konfiguration wieder her und schreibt die Markierung nicht noch einmal. Eine Path-Unit braucht deshalb PathExists= und PathChanged=: Die erste startet Ihre Software beim Boot, wenn schon eine Konfiguration gespeichert ist, die zweite, wenn später eine neue Version gespeichert wird.

Das Release-Archiv enthält beide Units als Beispiele unter examples/; das Rezept installiert sie nicht. Kopieren Sie sie unter eigenen Namen:

# your-software.path
[Unit]
Description=Start the operating software when a WLPC configuration is stored

[Path]
PathExists=/etc/iot-config/profile-ready
PathChanged=/etc/iot-config/profile-ready
Unit=your-software.service

[Install]
WantedBy=paths.target
# your-software.service (das Beispiel: ein Aufruf des lokalen Sockets, dann die Markierung)
[Unit]
Description=Operating software
After=bootstrap-agent.service
Wants=bootstrap-agent.service

[Service]
Type=oneshot
RemainAfterExit=yes
DynamicUser=yes
SupplementaryGroups=bootstrap-agent wlpc
ReadWritePaths=/run/wlpc
ExecStart=/bin/sh -c 'n=0; while :; do /usr/bin/curl -sS --max-time 10 --unix-socket /run/bootstrap-agent/api.sock http://localhost/v1/status && exit 0; rc=$$?; [ "$$rc" = 7 ] && [ "$$n" -lt 30 ] || exit "$$rc"; n=$$((n + 1)); sleep 2; done'
ExecStart=/bin/sh -c "echo '{\"state\":\"connected\"}' > /run/wlpc/.target-confirmed.tmp && mv -f /run/wlpc/.target-confirmed.tmp /run/wlpc/target-confirmed"

Das Beispiel macht einen Aufruf, schreibt die Markierung (siehe Das Ziel bestätigen; Ihre Software schreibt sie erst, wenn sie verbunden ist, das Beispiel sofort) und endet. Deshalb ist es Type=oneshot mit RemainAfterExit=yes: Ein Dienst, der einfach endet, während die Markierung noch existiert, wird von PathExists= sofort wieder gestartet, bis das Start-Limit von systemd ihn stoppt und die .path-Unit als fehlgeschlagen markiert (gemessen). Ihre eigene Software ist ein dauerhaft laufender Dienst (Type=simple, mit Restart=on-failure) und braucht beides nicht.

Aktivieren Sie die .path-Unit, nicht den Dienst.

Drei Tatsachen aus einem Test auf dem Laborgerät mit einem Platzhalter für Ihre Software:

  • Die Markierung wird mit Modus 0600 gespeichert und gehört dem Agenten. Ein Dienst mit eigener Benutzer-ID, wie oben mit DynamicUser=yes, kann sie nicht lesen. Das muss er auch nicht: Nur ihr Vorhandensein startet den Dienst. Die Konfiguration liest der Dienst über den Socket, wo die Mitgliedschaft in der Gruppe bootstrap-agent die Berechtigung ist (siehe Referenz der lokalen API).
  • Der Dienst kann starten, bevor der Socket des Agenten da ist. Die Agent-Unit wartet auf network-online.target, deshalb startet sie nach einem Neustart etwa 18 Sekunden nach Ihrer .path-Unit (gemessen: 18,5 bis 18,7 s in drei Neustarts). Der Socket ist 4,1 bis 4,6 Sekunden nach dem Start des Agenten durch systemd offen (0,85 s bei einem späteren Neustart des Dienstes, wenn die Platine ruhig ist). Das Beispiel oben, 0,4 s nach dem Agenten gestartet, bekam einmal could not connect, wartete und hatte in allen drei Neustarts danach Erfolg. Eine Wiederholung in curl hilft nicht: curl --retry mit --retry-connrefused wiederholt bei einem Socket, den es noch nicht gibt, nicht (Fehler 7 nach 0,1 Sekunden, gemessen). After= allein hilft auch nicht, weil Type=simple als gestartet gilt, bevor der Socket offen ist. Warten Sie mit einer Obergrenze, wie das Beispiel; Software, die bei fehlendem Socket endet, kann Restart=on-failure mit RestartSec=2 nehmen.
  • Restart=on-failure ist ein Vorschlag. Der Boot-Test lief mit dem Beispiel oben, nicht mit Ihrer Software.

Das Ziel bestätigen

Wenn Ihre Software mit ihrer Zielplattform verbunden ist, schreibt sie Folgendes nach /run/wlpc/target-confirmed:

{"state":"connected"}

Der Agent beobachtet die Datei (ohne Polling). Sagt der Inhalt connected, bestätigt er jedes Paket der gespeicherten Konfiguration mit applied: true, und sind alle Pakete bestätigt, meldet er confirmed. Er prüft die Datei außerdem einmal beim Start. Auf dem Laborgerät ging die Bestätigung in weniger als einer Sekunde nach dem Schreiben der Datei hinaus, und die Pakete wechselten von keinem bestätigten zu allen sieben bestätigten; das Gerät zeigte danach ACTIVE und HEALTHY.

Die Reihenfolge, gemessen mit cproto-v0.2.0-rc.2 auf dem Laborgerät:

  • Ohne die Datei wird eine neue Konfiguration gespeichert, aber nicht bestätigt. Bei entfernter Datei wurde eine Template-Änderung gespeichert, profile-ready geschrieben und complete gemeldet; keines der sieben Pakete wurde bestätigt, und es ging kein confirmed hinaus.
  • Die Datei bestätigt. Der Platzhalter-Dienst (eigene Benutzer-ID, Gruppe wlpc, kein root) schrieb die Datei; 21 Millisekunden später protokollierte der Agent target reached: acking the packages, dann success reported to the platform. Alle sieben Pakete waren bestätigt.
  • Ist die Datei da, wird eine neue Konfiguration sofort bestätigt, in derselben Sekunde, in der sie gespeichert wird (Releases bis cproto-v0.2.0-rc.2; siehe Die Datei für jede neue Konfiguration neu schreiben).

Wer /run/wlpc schreiben darf

Ihre Software schreibt die Datei ohne root, als Mitglied der Gruppe wlpc. Der Agent liest sie nur. Das Verzeichnis gibt es nicht von selbst; diese tmpfiles-Regel legt es an:

d /run/wlpc 2775 root wlpc -
  • Die Gruppe wlpc ist die Schreibberechtigung. Die Unit Ihrer Software nennt sie in SupplementaryGroups=wlpc; das geht auch mit DynamicUser=yes.
  • Eine abgeschottete Unit braucht außerdem ReadWritePaths=/run/wlpc. DynamicUser=yes schließt ProtectSystem=strict ein, und damit ist /run für die Unit schreibgeschützt.
  • Schreiben Sie eine temporäre Datei in /run/wlpc und benennen Sie sie in target-confirmed um, damit der Agent nie eine halbe Datei liest.
  • Lassen Sie die Datei für andere lesbar (0644; die Standard-umask 0022 ergibt das). Der Agent ist nicht in der Gruppe wlpc. Die 2 in 2775 gibt jeder Datei im Verzeichnis die Gruppe wlpc.

Gemessen auf dem Laborgerät mit einer Unit mit DynamicUser=yes (eigene Benutzer-ID, kein root): Mit der Gruppe und ReadWritePaths= wurde die Datei geschrieben (Modus 0644, Gruppe wlpc); ohne ReadWritePaths= scheiterte das Schreiben mit Read-only file system, ohne die Gruppe mit Permission denied. In drei Neustarts des Laborgeräts schrieb der Beispieldienst oben die Datei jedes Mal unter seiner eigenen Benutzer-ID (Gruppe wlpc, Modus 0644, Inhalt {"state":"connected"}). Der Benutzer des Agenten, mit den Gruppen des Agenten und in der Abschottung des Agenten, konnte sie lesen, eine Kopie mit Modus 0600 nicht. Der Agent liest die Datei nur, solange Pakete nicht bestätigt sind; im Reihenfolge-Test oben hat er auf eine so geschriebene Datei reagiert.

Der Agent bemerkt auch ein Verzeichnis, das erst nach seinem Start angelegt wird: In einem früheren Test wurde das Verzeichnis nach dem Start des Agenten angelegt, und die Bestätigung kam trotzdem innerhalb einer Sekunde.

Stand im Release

Ab cproto-v0.2.0-rc.2 enthält tmpfiles/bootstrap-agent.conf im Archiv die Zeile oben, und der Beispieldienst im Ordner examples/ schreibt die Datei so, wie hier gezeigt. Das Rezept in unserem Layer legt die Gruppe wlpc an. Ein Image, das das Rezept nicht nutzt, legt die Gruppe selbst an.

Ohne diese Datei wird nichts ACTIVE, und nichts wird abgerechnet

Der Agent bestätigt nie von selbst. Schreibt nichts auf Ihrem Image die Datei, bleibt das Gerät PROVISIONED, es wird kein confirmed gemeldet, und das Gerät wird nicht abgerechnet. Die Einstellung GATEWAY_AGENT_CONFIRM_MARKER ändert den Pfad; der Name ist historisch.

Die Datei für jede neue Konfiguration neu schreiben

Ihre Software muss /run/wlpc/target-confirmed nach jeder neu gespeicherten Konfiguration erneut schreiben, sobald sie mit dem Ziel dieser Konfiguration verbunden ist. Eine Datei, die für eine frühere Konfiguration geschrieben wurde, bestätigt die neue nicht.

  • Warum: confirmed wird abgerechnet und muss heißen „verbunden mit der Konfiguration, die das Gateway jetzt hat“. Die Datei sagt connected, aber nicht, für welche Konfiguration.
  • Wann: nachdem sich /etc/iot-config/profile-ready geändert hat (PathChanged= Ihrer .path-Unit startet Ihre Software dann) und Ihre Software sich mit der neuen Konfiguration verbunden hat. Nach einem Neustart ist /run leer; Ihre Software schreibt die Datei deshalb bei jedem Start, sobald sie verbunden ist, wie das Beispiel.
  • Optional die Version nennen: {"state":"connected","profile_version":N}, mit N der profile_version, die Ihre Software über die lokale API gelesen hat. Eine Datei mit Version bestätigt nur diese Version, egal wann sie geschrieben wurde. Nutzen Sie das, wenn Ihr Gateway mit falscher Uhrzeit starten kann (keine Echtzeituhr).

Releases bis cproto-v0.2.0-rc.2 nehmen noch eine alte Datei an

Bis cproto-v0.2.0-rc.2 prüft der Agent die Datei erneut, wenn eine neue Konfiguration gespeichert ist, und ein altes connected bestätigt die neue Konfiguration sofort, bevor Ihre Software sie angewendet hat. Das nächste Release zählt die Datei nur, wenn sie nach dem Speichern der aktuellen Konfiguration geschrieben wurde oder deren Version nennt. Schreiben Sie die Datei schon jetzt wie oben beschrieben; dann ändert sich mit dem nächsten Release für Sie nichts.

Was nicht gemeldet wird

Der Agent sendet nur applied: true. Eine Konfiguration, die Ihre Software nicht anwenden kann, erzeugt bei der Plattform weder eine Bestätigung noch einen Fehler; die Plattform sieht nur, dass confirmed ausbleibt. Ihre Software kann applied: false an die lokale API senden; der Agent behält es auf dem Gerät, gibt es aber nicht weiter, und eine Datei mit connected überschreibt es mit applied: true. Siehe applied: false und Zwei Wege zu bestätigen.