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 Gruppebootstrap-agentdie 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 einmalcould not connect, wartete und hatte in allen drei Neustarts danach Erfolg. Eine Wiederholung incurlhilft nicht:curl --retrymit--retry-connrefusedwiederholt bei einem Socket, den es noch nicht gibt, nicht (Fehler 7 nach 0,1 Sekunden, gemessen).After=allein hilft auch nicht, weilType=simpleals gestartet gilt, bevor der Socket offen ist. Warten Sie mit einer Obergrenze, wie das Beispiel; Software, die bei fehlendem Socket endet, kannRestart=on-failuremitRestartSec=2nehmen. Restart=on-failureist 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:
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-readygeschrieben undcompletegemeldet; keines der sieben Pakete wurde bestätigt, und es ging keinconfirmedhinaus. - Die Datei bestätigt. Der Platzhalter-Dienst (eigene Benutzer-ID, Gruppe
wlpc, kein root) schrieb die Datei; 21 Millisekunden später protokollierte der Agenttarget reached: acking the packages, dannsuccess 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:
- Die Gruppe
wlpcist die Schreibberechtigung. Die Unit Ihrer Software nennt sie inSupplementaryGroups=wlpc; das geht auch mitDynamicUser=yes. - Eine abgeschottete Unit braucht außerdem
ReadWritePaths=/run/wlpc.DynamicUser=yesschließtProtectSystem=strictein, und damit ist/runfür die Unit schreibgeschützt. - Schreiben Sie eine temporäre Datei in
/run/wlpcund benennen Sie sie intarget-confirmedum, 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. Die2in2775gibt jeder Datei im Verzeichnis die Gruppewlpc.
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:
confirmedwird abgerechnet und muss heißen „verbunden mit der Konfiguration, die das Gateway jetzt hat“. Die Datei sagtconnected, aber nicht, für welche Konfiguration. - Wann: nachdem sich
/etc/iot-config/profile-readygeändert hat (PathChanged=Ihrer.path-Unit startet Ihre Software dann) und Ihre Software sich mit der neuen Konfiguration verbunden hat. Nach einem Neustart ist/runleer; 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}, mitNderprofile_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.