joetjen.net
EN DE
Configuration language

Values

Every value in CASC has a type the parser knows. Numbers, durations, sizes, dates and addresses arrive typed — nothing has to be parsed a second time by the application.

Format 1.0

At a glance

TypeExamples
nil, booleannil true false
integer-17 1_000_000 0xDEAD_BEEF 0o755 0b1101
float3.1415 5e+22 -2E-2 inf -inf
atominfo :info enabled? :nil
string"escaped\n" 'literal' """multi-line"""
date, time1979-05-27 07:32:00 1979-05-27T07:32:00Z
IP address127.0.0.1 10.0.0.0/8 ::1 fe80::1/64
duration500ms 1h30m 1.5h 2d
byte size512MiB 1.5GiB 10GB
list[1, 2, 3] ["a" "b"]
tuple(52.52, 13.405)

Nil and booleans

nil, true and false are keywords. There is no null, yes or on: those are ordinary atoms.

flags = [nil, true, false, null, yes]
%{"flags" => [nil, true, false, :null, :yes]}

Numbers

Integers take an optional sign and may be written in hexadecimal (0x), octal (0o) or binary (0b). Floats need digits on both sides of the point or an exponent; 1e3 is a float. _ separates digit groups anywhere. inf, +inf and -inf are the infinities.

n = [-17, +99, 0xDEAD_BEEF, 0o755, 0b1101, 1_000_000, 3.1415, 5e+22, -2E-2, inf, -inf]
%{"n" => [-17, 99, 3735928559, 493, 13, 1000000, 3.1415, 5.0e22, -0.02,
         :infinity, :neg_infinity]}

Atoms

A bare word in value position is an atom — a symbolic name, the way log levels and modes are usually written. A leading : is optional, and required to turn a reserved word into an atom.

levels = [info, :info, enabled?, ready!, handle-otp, :nil]
%{"levels" => [:info, :info, :enabled?, :ready!, :"handle-otp", nil]}

Strings

Three forms, for three jobs:

  • "double" — escapes \n \r \t \" \\ \uXXXX, and interpolation of @{}, ${}, %{}, !{} and !tag(…).
  • 'single' — literal: no escapes, no interpolation. Good for patterns and anything full of backslashes.
  • """triple""" — multi-line. The newline after the opening quotes is dropped and the common indentation removed, so the text can be indented with the file.
@who = "world"
greeting = "hello, @{who}\n"
pattern = '^\d+ @{not interpolated}$'
motd = """
    Welcome to the service.
      Status: operational
    """
%{"greeting" => "hello, world\n",
  "pattern" => "^\\d+ @{not interpolated}$",
  "motd" => "Welcome to the service.\n  Status: operational\n"}

Dates and times

Unquoted ISO 8601: a date, a time with seconds (fractions allowed), or both joined by T. A date-time with Z or an offset is an instant, normalised to UTC; without one it is a local date-time.

at = [1979-05-27T07:32:00Z, 1979-05-27T07:32:00.999+02:00, 1979-05-27T07:32:00, 1979-05-27, 07:32:00.5]
%{"at" => [~U[1979-05-27 07:32:00Z], ~U[1979-05-27 05:32:00.999Z],
          ~N[1979-05-27 07:32:00], ~D[1979-05-27], ~T[07:32:00.5]]}

IP addresses

IPv4 and IPv6 addresses are values, unquoted, each with an optional /prefix for a network. An octet above 255 is a load error, not a string.

allow = [127.0.0.1, 10.0.0.0/8, ::1/128, fe80::1]

Durations

A number followed directly by a unit: ns, us (or µs), ms, s, m, h, d. Units combine from largest to smallest, each once, with whole numbers; a single unit may have a fraction.

timeout = 500ms
window = 1h30m
same = 1.5h
retention = 2d
%{"timeout" => {:duration, 500000000},
  "window" => {:duration, 5400000000000},
  "same" => {:duration, 5400000000000},
  "retention" => {:duration, 172800000000000}}

30m1h (ascending), 1h1h (repeated) and 1.5h30m (a fraction in a compound) are load errors.

Byte sizes

Decimal units B kB MB GB TB PB count in thousands, binary units KiB MiB GiB TiB PiB in 1024s. Units are case-insensitive; fractions are allowed.

sizes = [512MiB, 1.5GiB, 10GB, 1kib]
%{"sizes" => [{:bytes, 536870912}, {:bytes, 1610612736},
             {:bytes, 10000000000}, {:bytes, 1024}]}

Lists and tuples

A list […] holds any values; commas, spaces and newlines all separate elements, in any mix. A tuple (…) is a fixed group — a coordinate, a pair — and is always replaced as a whole, never merged.

hosts = [
  "a.internal"
  "b.internal", "c.internal"
]
office = (52.5200, 13.4050)
matrix = [[1, 2], (3, 4)]
%{"hosts" => ["a.internal", "b.internal", "c.internal"],
  "office" => {52.52, 13.405},
  "matrix" => [[1, 2], {3, 4}]}