I’ve been using https://cuelang.org/ a lot for my configuration needs. It’s still a young project but it’s pretty awesome. You can write partial schemas (with both concrete values and abstract constraints) and have cue do the checking and unification for you automatically.
For example, you might have an application:
- expecting a volume to be mounted at a specific location, or
- with specific constraints on runtime environment variables
So now instead of waiting for my application to crash sometime after I deploy it, I see an error message at deploy time (i.e. when I try to export the .cue files to JSON or TOML).
Over the years I’ve tried to solve this kind of problem with various combinations of sed, jq, kustomize, helm, raw string templating, and other even less appropriate tools. I’ve been very happy to replace them all with cue.
I went through the fly docs and put together the schema below. Also shared it in the cue playground: CUE Playground
Hope others find it helpful!
package fly_config
#portHandler: "tls" | "http"
#portValue: =~"^[0-9]+$"
#port: {
handlers: [#portHandler, ...]
port: #portValue
}
#duration: (string & =~"^[0-9]+s$") | int
#concurrency: {
hard_limit: *25 | int
soft_limit: *20 | int
}
#check: {
grace_period: *"1s" | #duration
interval: *"15s" | #duration
timeout: *"2s" | #duration
}
#tcpCheck: {
#check
port: #portValue
restart_limit: *6 | int
}
#httpCheck: {
#check
method: string
path: string
protocol: "http" | "https"
tls_skip_verify: bool
headers: {string}
}
#mounts: {
source: string // The source is a volume name that this app should mount. Any volume with this name, in the same region as the app and that isn't already mounted, may be mounted. A volume of this name must exist in some region for the application to deploy.
destination: string // The destination is directory where the source volume should be mounted on the running app.
}
#experimental: {
private_network?: bool
}
#service: {
concurrency: #concurrency
internal_port: *8080 | int
protocol: *"tcp" | "udp"
ports: [#port, ...]
tcp_checks: [#tcpCheck, ...]
mounts?: #mounts
experimental?: #experimental
}
#app: {
app?: string
kill_signal?: *"SIGINT" | "SIGTERM" | "SIGQUIT" | "SIGUSR1" | "SIGUSR2" | "SIGKILL" | "SIGSTOP"
kill_timeout?: *5 | (<=86400 & int)
services?: [#service, ...]
}
#app
PS Some folks in the cue community are experimenting with generating application source code (complete with types, where appropriate!) to work with cue-specified values at runtime. This has been very helpful in my projects, where I want to make sure the code I’m deploying is deployed with the configuration it expects.