Executable compose files
Executable compose files
Systemd polyglot
A while ago I came up with an interesting polyglot file; a systemd unit definition file which is also an executable Node.js script and can execute itself:
#!/usr/bin/env node
;console.log(process.argv[2]==="+"?"foo":"bar")
;process.exit(0);
;/*
[Unit]
Description="Polyglot"
[Service]
Type=oneshot
ExecStart=/usr/bin/env node /etc/systemd/system/polyglot.service +
[Install]
WantedBy="default.target"
;*/
It can be placed at /etc/systemd/system/polyglot.service and if executed as a script will print bar. If started as a systemd unit, it will print foo:
Starting "Polyglot"...
foo
polyglot.service: Deactivated successfully.
Finished "Polyglot".
The executable bit doesn’t have to be set for it to be executed like that. While kind of cool, I couldn’t come up with a real use case for this. Also, in my day job, I lately tend to edit and use docker compose files more often than systemd unit files.
Compose polyglot
So I asked myself, can we make docker compose files executable too? Well…, while also quite cursed, of course we can! Here a basic example:
#!/usr/bin/env bash
x-exec(){ :;}; x-exec : | #
echo "foo" && exit 0
services:
web:
image: nginx
Make sure to keep the space in x-exec : on the second line so that bash doesn’t complain. Formatters tend to remove such things.
This file, when made executable, is simultaneously a valid bash script, a valid yaml file and a valid docker compose file. The reason why it works as a compose file is because of compose files’ extensions:
Extensions can be used to make your Compose file more efficient and easier to maintain.
Use the prefix
x-as a top-level element to modularize configurations that you want to reuse. Compose ignores any fields that start withx-, this is the sole exception where Compose silently ignores unrecognized fields.
In order for this to be a bit nicer, I wanted the script to be located below the compose keys. I was able to do this with a heredoc:
#!/usr/bin/env bash
x-exec(){ :;}; x-exec : | #
:; : <<'x-script: |'
services:
web:
image: nginx
x-script: |
echo "hello world" && exit 0
The heredoc is just used as a way to comment out the yaml from the “bash perspective” without having to prepend lines with #.
Of course, any arbitrary command can be executed in the script section. Combined with uv and cut, we can make it a python script:
#!/usr/bin/env bash
x-exec(){ :;}; x-exec : | #
:; : <<'x-script: |'
services:
web:
image: nginx
ports:
- 127.0.0.1:8989:80
x-script: |
cut -c 3- <<'x-eof:' | uv run -
# /// script
# dependencies = ["docker-composer"]
# ///
from docker_composer import DockerCompose
base = DockerCompose(file="compose.yml")
base.up().call()
x-eof:
The above script brings up itself as a compose project when executed as ./compose.yml.
Yes, this is weird and totally cursed.