Paul Hammant's Blog: Infrastructure as Code DSLs
I had liked one feature of Groovy for a long time that the dev team originally called builders, but that’s been re-used to mean different things since. Maybe even before. The language feature is a copy of Ruby’s method_missing
that superficially looks like it is allowing additional keywords to the language, but it’s really a trick to allow method invocations on an implied context. With curly-braces and a bunch of classes and methods to make this look terse and elegant, we can end up with Groovy scripts that look like they are fully declarative. They’re not really, you can insert regular statements, including conditionals and loops. You might prefer for the pseudo-declarative form to not do that, but it’s always there for you if you want.
I thought I would ask ChatGPT what the language feature is called and Groovy in builder-style DSL syntax that leverages closures seems to coerce GPT into writing the right code based on examples, if you prefix with that. Someone needs a one-word name for this that doesn’t clash with other names, and could end up in other languages. Say “Zig now has first class cl*n?ds style like Groovy, Ruby and Python”.
Elegant Infra as Code (IaC)
fredAndWilma = new IaCscript('QA').containers("fredAndWilma") {
allowIngressFrom("192.168.0.*")
subnet("192.168.1.0/24")
container("fred") {
from("debian12-cloudinit.iso")
listeningPort(80)
allowIngressFrom("192.168.0.*")
allowEgressTo("wilma")
}
container("wilma") {
from("debian12-cloudinit.iso")
listeningPort(8080)
allowIngressFrom("fred")
persistentStorage("wilmaStorage/")
}
startAll()
}
fredAndWilma.print() // should be an enumeration of fred and wilma with start/stop status
fredAndWilma.on("wilma").transfer("fancyAppWC.tgz").runScript("fancyAppWebCache.sh")
fredAndWilma.on("fred").transfer("fancyAppBL.tgz").runScript("fancyAppBizLogic.sh")
Get your prompt right with “Groovy in builder-style DSL syntax that leverages closures” and it will write all the implementation code. There’s ten of so picky “don’t be lazy” clauses to add, but it does get there.
You’d run the script, and it would create local containers (LXC or Docker - not specified). It would also start them so they could be navigated to for further work (those last two lines). Indeed while you retain the right to rerun the script dropping previous provisioned pieces (ephemeral infra), you may also choose to just do the trasnfer().runScript()
for CI:CD into say ‘shared_dev’ env.
So last night I was at EdinburghJS and saw Daniel Grant demonstrate the fantastic Notation. Notation has chosen TypeScript (of course) as the language to provision bits and pieces, and for now it focuses on AWS cloud-app setup. The demo of last night, as of the videos in the README, are for the registration of a Lambda function. Again that’s registration not the implementation of the lambda function itself. Well that can be inline too, but you’d probably separate. Registration means AWS web-api invocation ahead of actual use. Notation also has examples that are worth checking out. Now, TypeScript and JavaScript don’t have the “builder-style DSL syntax that leverages closures” language feature so the examples don’t look even half declarative.
Guaranteed to be wrong, but giving a feel for the Groovy pseudo-declarative way for aws/lambda:
IaCscript.provisionEnv('shared_dev') {
aws() {
router() {
lambda(timeout: 5, memory: 64) {
function('/' MyApplication.greeting)
function('/foo' MyApplication.fooHandler)
}
}
}
}
Of course, I am not going to take this any further. My code is 0.0000001% complete versus all the vendor cloud things, and the on-prem stuff like Proxmox, VmWare, etc.
See also my Principles of Containment blog entry.