Dhall: A Strong Alternative to YAML

Tristan de Cacqueray

Februrary 18, 2021

Overview

If like me, you are tired of writting YAML files, this talk is for you.

Why do we want an alternative?

dhall

a programmable configuration language that you can think of as: JSON + functions + types + imports

$ sudo dnf install -y dhall dhall-json
{ job =
  { name = "koji-build-x86_64"
  , run = "playbooks/rpmbuild.yaml"
  , vars = { arch = "x86_64", build = < scratch | final >.scratch }
  }
}

… corresponds to this YAML:

$ dhall-to-yaml --file ./job.dhall
job:
  name: koji-build-x86_64
  run: playbooks/rpmbuild.yaml
  vars:
    arch: x86_64
    build: scratch

Let bindings

let name = value

in expr
let job =
      let arch = "x86_64"

      let build = < scratch | final >.scratch

      in  { name = "koji-build-${arch}"
          , run = "playbooks/rpmbuild.yaml"
          , vars = { arch, build }
          }

in  { job }

Imports

-- ./koji-job.dhall file content:
let arch = "x86_64"

let build = < scratch | final >.scratch

in  { name = "koji-build-${arch}"
    , run = "playbooks/rpmbuild.yaml"
    , vars = { arch, build }
    }
let job = ./koji-job.dhall

in { job }

Functions

-- ./koji-job.dhall
\(build : < scratch | final >) ->
\(arch : Text) ->
  { name = "koji-build-${arch}"
  , run = "playbooks/rpmbuild.yaml"
  , vars = { arch, build }
  }
$ dhall-to-yaml <<< './koji-job.dhall (< scratch | final >.final) "x86_64"'

… corresponds to this YAML:

name: koji-build-x86_64
run: playbooks/rpmbuild.yaml
vars:
  arch: x86_64
  build: final

Demo

https://softwarefactory-project.io/cgit/software-factory/sf-infra/plain/Infra/OpenShift/deployWithEnv.dhall
  "service-name"
  "quay.io/software-factory/service-name:v1"
  8080
  "service-name.prod.psi.redhat.com"
  (toMap { option = "value", logLevel = "INFO" })

… corresponds to this YAML:

$ dhall-to-yaml --documents --file ./demo.dhall
---
apiVersion: v1
kind: Route
metadata:
  name: service-name
spec:
  host: service-name.prod.psi.redhat.com
  path: /
  port:
    targetPort: 8080
  tls:
    insecureEdgeTerminationPolicy: Redirect
    termination: edge
  to:
    kind: Service
    name: service-name-service
    weight: 100
---
apiVersion: v1
kind: Service
metadata:
  name: service-name-service
spec:
  ports:
    - port: 80
      targetPort: 8080
  selector:
    app: service-name
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: service-name
spec:
  replicas: 1
  selector:
    matchLabels:
      app: service-name
  template:
    metadata:
      labels:
        app: service-name
      name: service-name
    spec:
      containers:
        - env:
            - name: logLevel
              value: INFO
            - name: option
              value: value
          image: quay.io/software-factory/service-name:v1
          name: service-name
          ports:
            - containerPort: 8080

Usage

Food for thought

Questions?