Verweise
Drei Arten von Verweisen holen Werte von anderswo — aus Variablen, der Umgebung und anderen Schlüsseln — und teilen sich eine Syntax für Defaults, Wächter, Indizes und Filter. Tags und Resolver wandeln um und holen ab.
Drei Arten
| Form | Liest | Aufgelöst |
|---|---|---|
@{name} | eine mit @name = … deklarierte Variable | gegen alle Variablen des Ladevorgangs |
${NAME} | eine Umgebungsvariable | beim Laden |
%{a.b.c} | einen anderen Schlüssel der Konfiguration | gegen den fertigen, zusammengeführten Baum |
Ein Verweis, der den ganzen Wert bildet, behält den Typ dessen, was er liest — %{server.port} ist eine Ganzzahl. In einer Zeichenkette mit doppelten Anführungszeichen wird er als Text eingesetzt.
Defaults, Wächter und Indizes
Alle drei Arten nehmen dieselben Suffixe. Ohne Suffix ist ein Verweis auf etwas Undefiniertes ein Ladefehler.
| Suffix | Bedeutung |
|---|---|
@{x:default} | default verwenden, wenn undefiniert |
@{x:+alt} | alt, wenn definiert, sonst "" |
@{x:?"message"} | den Ladevorgang mit dieser Meldung abbrechen, wenn undefiniert |
@{x[1]} | Index in eine Liste (ab 0), kombinierbar mit einem Default |
@{x | trim} | Filter anwenden, von links nach rechts, nach dem Suffix |
Ein shell-artiges :-default gibt es bewusst nicht. Ein Default wird als CASC-Wert gelesen, ${PORT:8080} fällt also auf die Ganzzahl 8080 zurück.
Variablen
@name = value deklariert eine öffentliche Variable, sichtbar in jeder Datei des Ladevorgangs — in den Dateien, die diese importieren, und in denen, die sie importiert. @*name deklariert eine private, nur in der eigenen Datei sichtbare Variable; sie verdeckt dort eine öffentliche gleichen Namens.
@hosts = ["x", "y"]
@*suffix = ".internal"
primary = "@{hosts[0]}@{suffix}"
second = @{hosts[1]}
all = @{hosts}
mode = @{mode:"standalone"}
note = @{suffix:+"private suffix set"}%{"primary" => "x.internal", "second" => "y", "all" => ["x", "y"],
"mode" => "standalone", "note" => "private suffix set"}Variablen erscheinen nicht im Ergebnis. Sie werden gegen den gesamten Ladevorgang aufgelöst, nicht in Lesereihenfolge: Eine Variable darf oberhalb ihrer Deklaration verwendet werden, und bei doppelter Deklaration gewinnt die letzte.
Umgebung
Eine nicht gesetzte oder leere Umgebungsvariable gilt als undefiniert. Was aus der Umgebung kommt, ist immer eine Zeichenkette; ein Tag wandelt sie um. Ein Verweis mit [] am Ende teilt den Wert an , und ; in eine Liste.
region = ${REGION}
retries = !int(${MAX_RETRIES:3})
hosts = ${HOSTS[]}
second = ${HOSTS[1]}
allowed = ${ALLOWED_HOSTS[]:["localhost"]}%{"region" => "eu-west", "retries" => 3, "hosts" => ["a", "b", "c"],
"second" => "b", "allowed" => ["localhost"]}Bedingte Anweisungen
${?NAME} in einer eigenen Zeile behält die nächste Anweisung nur, wenn NAME gesetzt und nicht leer ist — genau eine Anweisung, die auch ein ganzer Block sein darf.
${?ENABLE_METRICS}
metrics {
port = 9568
path = "/metrics"
}Konfigurationsverweise
%{path} liest einen anderen Schlüssel. Er wird zuletzt aufgelöst, gegen den fertigen Baum — nach allen Imports, Überschreibungen und Sigils — und sieht daher den endgültigen Wert, egal wo er gesetzt wurde. Ein Zyklus von Verweisen ist ein Ladefehler.
health.url = "http://%{server.host}:%{server.port}/health"
server.host = "api.internal"
server.port = 8080
admin = %{contact.admin:"ops@example.com"}%{"health" => %{"url" => "http://api.internal:8080/health"},
"server" => %{"host" => "api.internal", "port" => 8080},
"admin" => "ops@example.com"}Filter
Filter bereinigen eine Zeichenkette beim Einlesen. Die Menge ist abgeschlossen: trim, downcase, upcase, trim_prefix: "…" und trim_suffix: "…". Alles andere ist ein Ladefehler, ebenso ein Filter auf etwas anderes als eine Zeichenkette. Argumente in einfachen Anführungszeichen machen Filter auch innerhalb doppelt gequoteter Zeichenketten nutzbar.
scheme = ${SCHEME | trim_suffix: "://" | downcase}
region = ${REGION:" us-east-1 " | trim}
endpoint = "${SCHEME | trim_suffix: '://' | downcase}://api.internal"%{"scheme" => "https", "region" => "us-east-1",
"endpoint" => "https://api.internal"}Zusammengesetzte Namen
Der Name in einem Verweis darf selbst eine Zeichenkette mit Interpolation sein. So liest eine Schleife pro Element eine eigene Umgebungsvariable. Einen Verkettungsoperator gibt es darüber hinaus bewusst nicht.
@which = "HOST"
host = ${"APP_@{which}"} # reads APP_HOST
@ids = ["1", "2"]
for @id in @{ids} as tokens {
"@{id}" = ${"TOKEN_@{id}"} # reads TOKEN_1, TOKEN_2
}Tags und Resolver
Ein Tag !name(value) wandelt sein eines Argument um; Tags lassen sich verschachteln. Eingebaut sind !int, !float, !bool, !duration, !bytes, !trim, !downcase, !upcase und !module. Eine fehlgeschlagene Umwandlung ist ein Ladefehler.
port = !int(${PORT:"8080"})
debug = !bool(${DEBUG:"false"})
ttl = !duration("5m")
cache = !bytes("512MiB")%{"port" => 8080, "debug" => false,
"ttl" => {:duration, 300000000000}, "cache" => {:bytes, 536870912}}Ein Resolver !{name:payload} holt einen Wert von anderswo — aus einem Secret-Store, einem Parameterdienst. CASC bringt keinen mit: Die Anwendung registriert jeden einzelnen und entscheidet damit genau, was eine Konfigurationsdatei erreichen darf. Dasselbe gilt für weitere Tags und für Import-Schemata.
*password = !{vault:secret/db/password}