Direkt zum Hauptinhalt

Hauptkonfiguration - bffh.dhall

BFFH verwendet Dhall für die Struktur von Ressourcen (z.B. Maschinen), Rollen, Aktoren und Initiatoren. Die Konfiguration von BFFH befindet sich in der Datei bffh.dhall. Die Datei kann auch umbenannt werden. Wichtig ist, dass sie dann überall korrekt referenziert wird (z.B. in Service Scripts). Der betreffende Quellcode findet sich in GitLab.

Tipps & Tricks in Dhall

Dhall ist eine umfangreiche Sprache für die Konfiguration und erlaubt äußerst komplexe Datenstrukturen. Vieles davon wird für FabAccess vermutlich nur im kleineren Rahmen benötigt, jedoch besteht die grundlegende Kompatibilität auch für komplizierte Gebilde. Im Rahmen dieser Dokumentationen gehen wir nur auf grundlegende, wichtige und besonders praktische Konfigurationsaspekte ein.

Ein nutzbringenden Cheatsheet für Dhall findet sich unter https://docs.dhall-lang.org/howtos/Cheatsheet.html

Literal für leere Einträge

Dhall-Objekte können auch leer übergeben werden. Dafür gibt es eine spezielle Syntax: {=}. Siehe https://hackage.haskell.org/package/dhall-1.42.1/docs/Dhall-Tutorial.html#g:6

Beispiel:

initiators = {=}

Literal "Some"

Die folgenden beiden Angaben sind inhaltlich gleich. Das Wörtchen "Some" macht in unserem Beispiel den Wert port optional. Diese Notation kann verwendet werden, um innerhalb einer Konfiguration darauf hinzuweisen, dass ein Wert fest gesetzt werden könnte, aber aktuell nicht von Nöten ist. Siehe https://hackage.haskell.org/package/dhall-1.42.1/docs/Dhall-Tutorial.html#g:5

Beispiel:

listens = [{ address = "127.0.0.1" }]
listens = [{ address = "127.0.0.1", port = Some 59661 }]

Kommentare

Zeilen, die mit -- beginnen, werden automatisch als Kommentar gewertet. Das kann auch verwendet werden, um z.B. nicht mit dem Literal "Some" zu arbeiten. So können wir z.B. eine Originalzeile auskommentieren und darunter unsere angepasste Zeile schreiben.

Beispiel:

--listens = [{ address = "127.0.0.1", port = 59661 }]
listens = [{ address = "127.0.0.1" }]

Zeichenketten erzeugen

Werte können zusammengefügt werden (concatenation). Das geht zum Beispiel mit dem Syntax ++ wie folgt:

certfile = env:BFFH_CFG_PATH as Text ++ "/cert/bffh-selfsigned.crt"

Oder als Verkettungsbefehl:

hobbies = concatSep ", " [ "piano", "reading", "skiing" ]

Dhall-Konfigurationen verschlanken

Folgende Möglichkeiten der Vereinfachung und Granulierung von Dhall-Dateien stellen wir vor. Wir berufen uns unter anderem auf die Dokumentation https://github.com/dhall-lang/dhall-lang/blob/master/standard/imports.md

Variablen/Konstanten innerhalb einer Datei setzen

Folgendes Beispiel erzeugt ein Listing VARS, welches drei Variablen enthält, die vereinheitlicht angesprochen werden können. Variablen lassen sich auf diese Art und Weise beliebig tief schachteln. Zu beachten ist das kleine Wörtchen in, welches im darauffolgenden Block (Record) eine Ersetzung bzw. Referenzierung anstrebt.

let VARS = {
	BFFH_CFG_PATH = "/opt/fabinfra/bffh-data/",
	MQTT_USER = "fabinfra101",
	MQTT_PASSWD = "fablocal"
	}
in 
{
    listens = [
        { address = "0.0.0.0", port = 59661 },
    ],
    certfile = VARS.BFFH_CFG_PATH ++ "cert/bffh-selfsigned.crt",
    keyfile = VARS.BFFH_CFG_PATH ++ "cert/bffh-selfsigned.key",
    mqtt_url = "mqtt://" ++ VARS.MQTT_USER ++ ":" ++ VARS.MQTT_PASSWD ++ "@0.0.0.0:1883",
    db_path = VARS.BFFH_CFG_PATH ++ "bffh.db"
}

Umgebungsvariablen verwenden

Wir setzen z.B. ein einer Bash-Umgebung einen Variablenwert und führen ein Kommando aus, welches die nachfolgende Dhall-Datei verwendet. Der Prozess, der die Dhall-Datei interpretiert, sucht in seiner übergebenen Umgebung (Environment) nach passenden Variablen und ersetzt die Werte entsprechend.

Als Rohtext in Dhall:

# bash
export BFFH_CFG_PATH="/opt/fabinfra/bffh-data"
bffh_cfg = env:BFFH_CFG_PATH as Text

oder als aufgelöster Pfad in Dhall:

# bash
export BFFH_CFG_PATH="~/bffh-data"
bffh_cfg = env:BFFH_CFG_PATH as Location

Inhalte aus URLs importieren

Folgender Syntax lädt den Content der entfernten URL als Variableninhalt:

let concatSep = http://prelude.dhall-lang.org/Prelude/Text/concatSep sha256:fa909c0b2fd4f9edb46df7ff72ae105ad0bd0ae00baa7fe53b0e43863f9bd34a

Importe können mit Integritätsprüfungen geschützt werden, wenn ein SHA-256-Hash angehängt wird (wie beim obigen concatSep-Import). Dadurch verhindern wir Manipulation von außerhalb.

Dhall-Dateien innerhalb anderer Dhall-Dateien referenzieren (verschachteln)

Importierte Ausdrücke können transitiv andere Ausdrücke importieren. Eine exemplarische Datei  ./schema.dhall kann andere Dateien importieren:

{ 
    name : ./schema/name.dhall, 
    age  : ./schema/age.dhall, 
    hobbies : ./schema/hobbies.dhall
}

... und wenn ./schema/hobbies.dhall einen relativen Import enthielte wie z.B.:

List ./hobby.dhall

... dann würde sich der relative Import von ./hobby.dhall tatsächlich auf ./schema/hobby.dhall beziehen. Dies ist als "Importverkettung" bekannt: die Auflösung von Importen relativ zur Position des aktuellen Ausdrucks.

Dhall-Dateien parsen, prüfen und formatieren

Dhall-Dateien können mit einer eigenen Bibliothek geparsed und auf Fehler geprüft werden. Das Resultat kann zudem neu formatiert ausgegeben werden - auch unter den Stichworten Beautify oder Prettyprint bekannt. Hierfür muss die Bibliothek dhall installiert werden.

sudo apt install dhall

Falls die Installation scheitert, kann das Paket auch manuell installiert werden (siehe https://pkgs.org/search/?q=dhall) - Beispiel für Raspberry Pi mit Debian Bookworm:

wget http://ports.ubuntu.com/pool/universe/h/haskell-dhall/dhall_1.32.0-1build1.1_arm64.deb
dpkg -i dhall_1.32.0-1build1.1_arm64.deb

Das Folgende Kommando setzt zunächst die Konfigurationsdatei als Variable. Wenn diese Datei erfolgreich geparsed werden konnte, dann formatieren wir diese und überschreiben dann die Originaldatei - beim Scheitern unternehmen wir nichts.

Warnung:
Durch das automatische Formatieren werden alle etwaigen Kommentare entfernt. Falls der FabAccess Config Generator genutzt wird, gehen dabei u.a. auch die Anfangs- und End-Tags --- ||| GENERATOR START und --- ||| GENERATOR END verloren!

Unterreferenzierte Dhall-Dateien werden nicht automatisch mitgeprüft. Eine Rekursion findet also nicht statt. D.h. jede Dhall-Datei muss einzeln geprüft/formatiert werden.

CFG="/opt/fabinfra/bffh-data/config/bffh.dhall" && \
dhall format < $CFG && \
dhall format < $CFG > $CFG.bup && \
rm $CFG && \
mv $CFG.bup $CFG

Siehe auch Konfiguration von BFFH auf Synax und Inhalt prüfen für eine BFFH-spezifische Kontrolle der Daten.

Syntax-Highlighting: Dhall-Dateien schöner bearbeiten

Für verschiedene Editoren gibt es Highlighter-Plugins, dabei unter anderem für Vim, VS Code und Emacs. Siehe hier. Eine Referenz findet sich auch in https://docs.dhall-lang.org/howtos/Text-Editor-Configuration.html.

Für Vim funktioniert das zum Beispiel so:

curl -fLo ~/.vim/autoload/plug.vim --create-dirs https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim
vim ~/.vimrc
call plug#begin()
Plug 'vmchale/dhall-vim'
call plug#end()

Beim nächsten Öffnen des Editors führen wir das Kommando :PlugInstall aus, installieren damit das Plugin und öffnen dann beliebige Dhall-Dateien und sehen, dass uns Syntax-Highlighting nun zur Verfügung steht.

Damit die Datei als Dhall erkannt wird, muss die Dateiendung *.dhall lauten.

grafik.png
Beispiel-Screenshot für Vim

Die Konfiguration von BFFH

Den FabAccess Server zu konfigurieren ist zweifellos eine der wichtigsten Aufgaben und erfordert die Auseinandersetzung mit einigen Konzepten.

Übersicht über alle Einstellungen

In der Config gespeichert werden grundlegende, pflichtmäßig anzugebende Informationen zu ...

Allgemeine Einstellungen

listens::List

Enthält eine Liste aus Einträgen mit einer Adresse (address::String (notwendig)), auf die BFFH bei der Verbindung für die API hört sowie einer Portangabe (port::Integer (optional)). Die Adresse kann eine IPv4, IPv6 oder ein Hostname sein. Wird der Port nicht angegeben, dann wird der Standardport verwendet. Dieser Port lautet für BFFH 59661.

Achtung: Wenn BFFH keinen Port für die angegebene Kombination binden kann, wird ein Fehler protokolliert, aber mit den übrigen Ports fortgefahren.

Beispiele:

listens = [
    { address = "127.0.0.1", port = Some 59661 },
    { address = "::1", port = 59661 },
    { address = "steak.fritz.box", port = 59661 }
],

mqtt_url::String

Enthält die Adresse des MQTT-Servers, mit dem sich BFFH verbindet.

Die Adresse hat das Format <protocol>://[user]:[password]@<server>:[port]

  • protocol (notwendig) - kann eins der folgenden Werte annehmen: mqtt,tcp,mqtts,ssl
  • user (optional)
  • password (optional)
  • server (notwendig) -kann IP-Adresse oder Hostname sein
  • port (optional) - Der Standardport ist 1883

Beispiele:

mqtt_url = "tcp://localhost:1883" 
mqtt_url = "mqtts://user:password@server.tld:port"

Achtung: Der MQTT-Server muss laufen und erreichbar sein, sonst startet BFFH nicht. Wird die MQTT-Verbindung getrennt, während BFFH läuft, stürzt BFFH nicht ab und protokolliert stattdessen die Verbindungsfehler in die Log-Ausgabe.

certfile::String und keyfile::String

Unsere Kommunikation über Cap'n Proto erfolgt grundsätzlich verschlüsselt. Dafür benötigen wir ein TLS-Zertifikat. Details, wie man ein TLS-Zertifikat generiert: Server - Anleitung zum selber kompilieren.

BFFH benötigt ein PEM-kodiertes Zertifikat und den zugehörigen Schlüssel als zwei separate Dateien. BFFH verwendet TLS ausschließlich in Version 1.2 bzw 1.3.

Beispiel:

certfile = "/opt/fabinfra/bffh-data/cert/bffh-selfsigned.crt"
keyfile = "/opt/fabinfra/bffh-data/cert/bffh-selfsigned.key"

db_path::String

Enthält den Pfad für die interne Datenbank, die BFFH verwendet. BFFH wird beim Start zwei Dateien erstellen, falls nicht bereits existent: <db_path> und <db_path>-lock. BFFH erstellt selber keine fehlenden Verzeichnisse. Es sollte sichergestellt werden, dass BFFH Schreibzugriff auf das entsprechende Verzeichnis hat. In der internen Datenbank werden die aktuellen Ressourcenzustände gespeichert (welche Ressource ist z.B. gerade durch einen Nutzer INUSE) und welche Nutzer mit Rollen, Passwörtern und Cardkeys zugreifen dürfen. Diese interne Datenbank kann teilweise exportiert werden (Benutzerdatenbank kann als *.toml Datei ausgegeben werden). Wir empfehlen die Ablage im Standardverzeichnis /var/lib/bffh/.

Beispiel:

db_path = "/var/lib/bffh/bffh.db"

Die Datenbankdatei kann prinizipiell gelöscht werden, jedoch gehen dabei die gespeicherten aktuellen Ressourcenzustände und Nutzer verloren. Die Nutzer können über eine aktuelle users.toml wieder importiert werden. Dass die Maschinenzustände verloren gehen, ist je nach Werkstattsetup u.U. einfach zu verkraften.

auditlog_path::String

Pfadangabe zur Auditdatei, die BFFH im laufenden Prozess schreibt. Die Ausgabe erfolgt im JSON-Format. Siehe Audit Log (Revisionsprotokoll) für Details zum Audit. Die Datei kann zum Beispiel mit Tools wie Grafana Loki ausgelesen werden. Wir empfehlen deshalb den Pfad so zu definieren, dass entsprechende Dienste korrekte Leseberechtigungen auf die Datei haben. Der bei Linux-Systemen verwendete Standardpfad for Log-Dateien ist per se /var/log/.

Beispiel:

auditlog_path = "/var/log/bffh-audit.json"

Falls BFFH wegen einem Berechtigungsfehler nicht startet, kann folgender Trick angewendet werden.

Error:
  × audit log failed
  ╰─▶ Permission denied (os error 13)

Lösung: die fehlende Datei neu und leer erzeugen und manuell die passende Berechtigungen setzen:

sudo touch /var/log/bffh-audit.json
sudo chown bffh:root /var/log/bffh-audit.json
sudo chmod 750 /var/log/bffh-audit.json

Alternativ kann auch mit setfacl eine ACL angelegt werden. Hierzu gibt es ein nettes Tool unter https://techgeeks.io/unix/acl-generator.

sudo setfacl -R -m u:bffh:rw-,d:u:bffh:rw- /var/log/bffh-audit.json

Konfiguration von Rollen (roles) und Berechtigungen

roles::Record

Enthält die Einträge der definierten Rollen. Rollen haben eine Liste von Berechtigungen und können vererbt werden. Die Berechtigung kann ein Platzhalter in der Berechtigungsliste sein. Jede Rolle muss eine Role-ID haben. Unterhalb des Eintrags roles schachteln sich Listen vom Typ parents::List (optional) und vom Typ permissions::List (notwendig).

Für die Vergabe von Rollennamen ist die Groß- und Kleinschreibung zu beachten! Wir empfehlen generell die Kleinschreibung.

Standardberechtigungen

BFFH verfügt über einige Standardberechtigungen, die der Verwaltung und den Admin-Rechten zugewiesen werden können.

bffh.users.info - Nutzerliste bekommen und Infos über diese Accounts erhalten
bffh.users.manage - Nutzerliste bekommen und Nutzer verwalten
bffh.users.admin - Globale Administration: Nutzer hinzufügen, löschen, ändern (z.B. Passwort-Reset)

Modellieren von Berechtigungen

Allgemeines Schema
space.type.category.permission.model

Administrator
space.machines.printers.*

Offene Berechtigung
space.machines.printers.read.*

Allgemeine Erläuterungen zum Pfadformat und Platzhaltern (*, +)
BFFH verwendet eine pfadähnliche Zeichenkette als Erlaubnisformat, getrennt durch einen . Punkt. So besteht zum Beispiel this.is.a.permission aus den Teilen this, is, a und permission. Bei der Anforderung von Berechtigungen, z. B. in Ressourcen, muss immer eine genaue Berechtigung angegeben werden, also z. B. test.write.

Bei der Erteilung von Berechtigungen, z. B. in Rollen, können entweder eine genaue Berechtigung angegeben oder die beiden Platzhalter * und + verwendet werden. Diese Wildcards verhalten sich ähnlich wie Regex- oder Bash-Wildcards:

  • * gewährt alle Berechtigungen in diesem Teilbaum. So wird perms.read.* für jedes von passen:
    • perms.read
    • perms.read.machineA
    • perms.read.machineB
    • perms.read.machineC.manage
  • + gewährt alle Berechtigungen unter des Wertes. So wird perms.read.+* für jedes von passen:
    • perms.read.machineA
    • perms.read.machineB
    • perms.read.machineC.manage
    • aber nicht perms.read

Wildcards sind wahrscheinlich am nützlichsten, um Ressourcen zu gruppieren, z.B. 3D-Drucker und eine Bandsäge:

  1. Write (schreiben) Berechtigungen
    • machines.printers.write.prusa.sl1
    • machines.printers.write.prusa.i3
    • machines.printers.write.anycubic
    • machines.bandsaws.write.bandsaw1
  2. Manage (verwalten) Berechtigungen
    • machines.printers.manage.prusa.sl1
    • machines.printers.manage.prusa.i3
    • machines.printers.manage.anycubic
    • machines.bandsaws.manage.bandsaw1
  3. Admin Berechtigungen
    • machines.printers
      • Für alle Drucker
    • machines.bandsaws
      • Für alle Bandsägen

Dann erteilen wir den Rollen die entsprechenden Rechte:

  • Nutze beliebige 3D-Drucker:
    • machines.printers.write.+
  • Erlaube nur die Nutzung "billiger" Drucker:
    • machines.printers.write.anycubic.*
    • machines.printers.write.prusa.i3
  • Erlaube das Verwalten der Drucker:
    • machines.printers.+
  • Erlaubte das Administrieren aller Drucker:
    • machines.printers.*

Auf diese Weise klappt es trotzdem mit der Aufteilung, wenn später ein weitere Anycubic Drucker gekauft wird:

  • machines.printers.write.anycubic.i3
  • machines.printers.write.anycubic.megax

Beispiel:

roles =
{
    testrole = 
    {
        permissions = [ "lab.test.*" ]
    },
    somerole =
    { 
        parents = [ "testparent" ],
        permissions = [ "lab.some.admin" ]
    }, 
    testparent =
    {
        permissions =
        [
            "lab.some.write",
            "lab.some.read",
            "lab.some.disclose"
        ]
    }
}

Wichtige Informationen zu den Berechtigungen

  • Jeder Ressource müssen alle Berechtigungsstufen zugewiesen sein (read, write, disclose, manage).
  • Berechtigungsstufen sind nicht additiv, d.h. ein Benutzer mit der Berechtigung manage erhält nicht automatisch read oder write Berechtigung.
  • disclose ist im Moment nicht vollständig implementiert. Benutzer, die keine disclose Berechtigung haben, werden in keiner Weise über diese Ressource informiert und sie wird vor ihnen im Client verborgen. Es ist deshalb am sinnvollsten, wenn read und disclose die gleiche Berechtigung zugewiesen bekommen, zum Beispiel disclose = "lab.test.read".
  • Benutzern ohne read wird eine Resource mit Namen, Beschreibung, Kategorie und Wiki angezeigt, aber nicht ihr aktueller Zustand. Der aktuelle Benutzer der Ressource wird nicht offengelegt.

Konfiguration von Ressourcen

machines::Record

Enthält die Einträge der definierten Ressourcen. Jede Ressource muss eine Ressource-ID haben, um in anderen Teilen dieser Konfiguration oder über die API auf die Ressource verweisen zu können. Und jede Ressource muss einen Namen haben.

Allgemeine Informationen

Um weitere Informationen über die Ressource bereitzustellen, können Namen, Kategorien, Beschreibungen oder ein externer Wiki-Link eingefügt werden:

  • name::String (notwendig) - ein Klarname, zum Beispiel ein Spitzname für eine Maschine oder eine Modellbezeichnung (Unicode-Support)
  • description::String (optional) - eine allgemeine, kurze Beschreibung der Ressource (Unicode-Support)
  • wiki::String (optional) - Link zu einer Wiki- bzw. Dokumentationsseite
  • category::String (optional) - eine beliebige Kategorie, z.B. "Holzwerkstatt" oder "Handgerät, elektrisch"(Unicode-Support)

Was heißt Unicode-Support?
Durch diese Eigenschaft können wir neben einfachen Bezeichnungen auch beliebige Sonderzeichen einfügen. Das erlaubt unter anderem die Verwendung von Emojis, die innerhalb der Client-Anwendung visuell unterstützen können. Dafür kann ein beliebiger Emoji-Picker genutzt werden, zum Beispiel https://www.freetool.dev/emoji-picker. D.h. wir können z.B.
description = "Saug dir Energie ;-) 🪫", konfigurieren. Das sieht dann in Borepin so aus:

grafik.png

Zugewiesene Berechtigungen

Die Ressourcen haben verschiedene Wahrnehmungsebenen, mit denen interagiert werden kann:

  • disclose::String (notwendig) - Offenlegen: Benutzer kann die Ressource in der Übersichtsliste sehen
  • read::String (notwendig) - Lesen: Der Benutzer kann Informationen über die Ressource und ihren Zustand lesen
  • write::String (notwendig) - Schreiben: Der Benutzer kann die Ressource benutzen
  • manage::String (notwendig) - Verwalten: Der Benutzer kann als Manager mit dem System interagieren (Prüfen, Freigeben, Transferieren)

Beispiel:

machines = 
{ 
    machine_123 = 
    { 
        name = "Testmachine",
        description = Some "A test machine",
        wiki = "https://someurl"

        disclose = "lab.test.read",
        read = "lab.test.read",
        write = "lab.test.write",
        manage = "lab.test.admin"
    }
}

Im Beispiel heißt unser Ressource-ID machine_123.

Konfiguration von Aktoren (actors)

actors::Record

Enthält eine Liste von Aktoren. Aktoren werden durch ein Modul module::String (notwendig) und einen oder mehrere Parameter params::Record definiert. Aktuell von Haus aus unterstützte Aktoren (ohne zusätzliche Plugins) sind Dummy Actor, Shelly Actor und Process Actor.

Konkret nutzbare Aktoren-Beispiele finden sich hier.

Aktoren werden durch ein Modul und einen oder mehrere Parameter definiert. Die Liste kann bzw. muss leer sein, wenn keine Aktoren verwendet werden:

actors = {=}

Sonst kann die Liste einen oder mehrere Aktoren mit ihrem Name (Actor-ID) enthalten:

Dummy Actor

Für Testzwecke kann ein interner Dummy-Initiator genutzt werden. Der „Dummy“-Initiator versucht alle paar Sekunden, einen Rechner als den angegebenen Benutzer zu verwenden und zurückzugeben. Er ist gut geeignet, um das System zu testen, führt aber zu Spam im Log und ist daher standardmäßig deaktiviert.

Beispiel:

actors = { 
   Dummy_123 = 
      { 
          module = "Dummy", 
          params = {=}
      } 
   }

Im Beispiel heißt unser Actor-ID Dummy_123.

Shelly Actor

Dieser Aktor verbindet BFFH über einen MQTT-Server mit einem Shelly Gerät. Der Parameter topic::String (optional) des Shelly kann auf das Shelly-spezifische MQTT-Topic gesetzt werden. Wird kein topic definiert, dann verwendet der Actor automatisch die definierte Actor-ID.

Anleitung zum Auffinden des Shelly Topic

Beispiel:

actors = 
{
    Shelly_123 = 
    { 
        module = "Shelly", 
        params = 
        {
            topic = "shellyplug-s-123456"
        }
    }
}

Im Beispiel heißt unser Actor-ID Shelly_123.

Process Actor

Dieser Aktor ermöglicht es, eigene Prozesse (z.B. Python, Bash, Perl, Java ...) mit dem BFFH Server zu verbinden.

cmd::String (notwendig) - Pfad der ausführbaren Datei
args::String (optional) - Argumente der ausführbaren Datei. Hier übergebene Argumente werden durch Leerzeichen getrennt, so dass in unserem Beispiel 5 separate Argumente übergeben werden.

Beispiel:

actors = 
{
    Bash_123 =
    { 
        module = "Process", 
        params =
            { 
                cmd = "./examples/actor.sh",
                args = "your ad could be here"
            }
    }
}

Im Beispiel heißt unser Actor-ID Bash_123.

Wichtige Info: BFFH baut aus den Argumenten cmd und args einen vollständigen Befehl, der ausgeführt wird und fügt automatisch zwei weitere Argumente am Ende hinzu - nämlich den zu erzielenden Status state (z.B. INUSE oder GIVEBACK) und den Benutzername userid. Der vollständige Befehl, der als Prozess ausgeführt wird, lautet folglich $ ${cmd} ${args} ${state} ${userid}.

actor_connections::List

Verknüpfung von Ressourcen mit Aktoren. Einer Ressource können mehrere Aktoren zugewiesen werden, aber ein Aktor kann nur einer Ressource zugewiesen werden.

Das Mapping actor_connections wird als Liste von Einträgen gespeichert. Die Parameter:

  • machine::String (notwendig) - die Ressource-ID
  • actor::String (notwendig) - die Actor-ID

Beispiele:

Eine leere Liste von Aktorenverknüpfungen:

actor_connections = [] : List { machine : Text, initiator : Text },

Eine Liste mit drei Mappings:

actor_connections = 
[
    { machine = "Testmachine", actor = "Shelly_123" },
    { machine = "Another", actor = "Bash_123" },
    { machine = "Yetmore", actor = "Bash_234" }
]

Konfiguration von Initiatoren (initiators)

Initiatoren werden fast genauso konfiguriert wie Aktoren. Es gibt aktuell die beiden Initiatorentypen Dummy Initiator und Process Initiator. Konkret nutzbare Initiatoren-Beispiele finden sich hier.

initiators::Record

Enthält eine Liste von Initiatoren. Initiatoren werden durch ein Modul und einen oder mehrere Parameter definiert. Die Liste kann bzw. muss leer sein, wenn keine Initiatoren verwendet werden:

initiators = {=}

Sonst kann die Liste einen oder mehrere Initiatoren mit ihrem Name (Initiator-ID) enthalten:

Dummy Initiator

Für Testzwecke kann ein interner Dummy-Initiator genutzt werden:

Der „Dummy“-Initiator versucht alle paar Sekunden, einen Rechner als den angegebenen Benutzer zu verwenden und zurückzugeben. Er ist gut geeignet, um das System zu testen, führt aber zu Spam im Log und ist daher standardmäßig deaktiviert.

Die Initiator-Parameter:

uid::String (notwendig) - Nutzername

Beispiel:

initiators = { 
   Initiator_123 = 
      { 
          module = "Dummy", 
          params = 
          { 
              uid = "Testuser" 
          } 
      } 
   }
Process Initiator

Dieser Initiator vom module::String Typ Process ermöglicht es, eigene Prozesse (z.B. Python, Bash, Perl, Java ...) mit dem BFFH Server zu verbinden. 

Das Mapping actor_connections wird als Liste von Einträgen gespeichert. Die Parameter:

cmd::String (notwendig) - Pfad der ausführbaren Datei
args::String (optional) - Argumente der ausführbaren Datei. Hier übergebene Argumente werden durch Leerzeichen getrennt, so dass in unserem Beispiel 5 separate Argumente übergeben werden.

Beispiel:

initiators = 
{
    Bash_567 =
    { 
        module = "Process", 
        params =
            { 
                cmd = "./examples/init.py",
                args = "your ad could be here"
            }
    }
}

Im Beispiel heißt unser Initiator-ID Bash_567.

Wichtige Info: BFFH baut aus den Argumenten cmd und args einen vollständigen Befehl, der ausgeführt wird und fügt automatisch zwei weitere Argumente am Ende hinzu - nämlich den zu erzielenden Status state (z.B. INUSE oder GIVEBACK) und den Benutzername userid. Der vollständige Befehl, der als Prozess ausgeführt wird, lautet folglich $ ${cmd} ${args} ${state} ${userid}.

init_connections::List

Verknüpfung von Ressourcen mit Initiatoren. Einer Ressource können mehrere Initiatoren zugewiesen werden, aber ein Initiator kann nur einer Ressource zugewiesen werden.

Das Mapping init_connections wird als Liste von Einträgen gespeichert. Die Parameter:

  • initiator::String (notwendig) - die Initiator-ID
  • actor::String (notwendig) - die Actor-ID

Beispiele:

Eine leere Liste von Initiatorverknüpfungen:

init_connections = [] : List { machine : Text, initiator : Text },

Eine Liste mit einzelnen Mapping:

init_connections = [
    { machine = "Testmachine", initiator = "Initiator_123" }
],

FabFire

spacename::String

Der Name des Spaces (die offene Werkstatt, das FabLab, der HackerSpace, etc.) wird im URN-Schema urn:fabaccess:lab:{spacename} verwendet. Wird er nicht definiert, wird der Wert "generic" vergeben. Diese Angaben benötigen wir für QR-Codes von Ressourcen oder für DESFire Karten zur Nutzung von FabFire.

Beispiel:

spacename = "FabAccess DemoSpace"

instanceurl::String

Wird für eine allgemeine Space Info genutzt und als URN im Code genutzt: urn:fabaccess:lab:{spacename}\x00{instanceurl}. Dieser Wert wird aktuell nicht verwendet, muss jedoch ausgefüllt werden, damit die Konfiguration bffh.dhall valide ist! Es wird empfohlen die URL mit dem Protokoll vollständig anzugeben, also mit http:// oder https://.

Beispiel:

instanceurl = "https://demo.fab-access.org"

Hinweise zur Vergabe von IDs

Wir verwenden in der Konfiguration IDs wie Ressource-ID, Actor-ID, Initiator-ID oder Role-ID. Diese IDs müssen folgendes Namensschema einhalten:

  • ASCII Format
  • Alphanumerisch
  • muss mit einem Buchstaben beginnen

Minimal funktionierende Standardkonfiguration

Wie bereits eingangs erwähnt, werden alle obigen Einstellungen für die Konfiguration benötigt. Für die minimale Startfähigkeit eines BFFH Servers kann folgendes Konfigurationssample verwendet werden. Dabei muss auch der MQTT-Server unbedingt laufen und erreichbar sein, sonst startet BFFH nicht. Ein Standardsample (etwas abweichend) kann auch per bffhd --print-default ausgegeben werden (siehe Cheat Sheet).

{
spacename = "fabaccess.sample.space",
instanceurl = "https://fabaccess.sample.space", 
listens = [{address = "127.0.0.1"}],
certfile = "/etc/bffh/bffh-selfsigned.cert",
keyfile = "/etc/bffh/bffh-selfsigned.key",
mqtt_url = "mqtt://127.0.0.1:1883",
db_path = "/var/lib/bffh/bffh.db",
auditlog_path = "/var/log/bffh-audit.json", 
roles = {=},
machines = {=},
actors = {=},
actor_connections = [] : List { machine : Text, initiator : Text },
initiators = {=},
init_connections = [] : List { machine : Text, initiator : Text },
}

Konfiguration per Config Generator

Siehe Einfache Konfiguration mit dem FabAccess Config Generator

Konfiguration von BFFH auf Synax und Inhalt prüfen

Konfiguration erstellt, aber unsicher, ob sie vollständig und syntaktisch korrekt ist? Wir können das per bffhd --check --config /opt/fabinfra/bffh-data/config/bffh.dhall überprüfen. Siehe hier. Das Kommando kann mit dem --check Parameter unabhängig und vor dem Neustart von BFFH ausgeführt werden und verhindert so die Unverfügbarkeit des Service bei Fehlkonfiguration (alternativ kann auch ein Staging-System für derartige Tests angelegt werden). Etwaige Fehlkonfigurationen werden auch erkannt, da geprüft wird, ob wichtige Konfigurationschlüssel fehlen, unvollständig oder falsch sind.

Siehe auch Dhall-Dateien parsen, prüfen und formatieren für die reine Überprüfung des Syntax und das automatische Umformatieren (Prettyprint).