2025 — present · Go · Ansible · cross-compiled binaries
glr
An open-source Ansible collection for managing GitLab Runners — with the modules written in Go, not Python.
glr is an Ansible collection for the full GitLab Runner lifecycle: creating
runner tokens through the GitLab API, registering and verifying runners,
merging settings into config.toml idempotently, and installing or removing
the system service. It's published on
GitHub under my m0rthis handle, with a
copy on GitLab. It used to live under my
old arcticwraith handle.
Why Go instead of Python
Two reasons. The honest one: I'd grown to dislike writing Python. The better
one: GitLab Runner is itself written in Go, so my modules can import the
config structs straight from the gitlab-runner source code. When a module
merges settings into config.toml, it's marshaling the runner's own types —
not maintaining a hand-written shadow copy of the schema that drifts every
time upstream adds a field.
Every module is idempotent in the Ansible sense — repeated runs only report
changed when something actually changed — which is easy to guarantee when
the module owns the config parsing itself.
The bigger idea it was chasing
I wanted automation where the platform didn't dictate the language — where Windows didn't automatically mean PowerShell and Linux didn't automatically mean Python modules. One Go implementation, compiled for both, behaving identically. glr mostly gets there: each release ships static binaries for Linux (amd64, arm64, arm, 386, ppc64le, s390x) and Windows (amd64, arm64, 386), with a thin wrapper dispatching to the right one.
Mostly. Ansible's assumptions pushed back — separate binaries per platform
meant the Windows modules had to be named win_register and so on, splitting
the very interface I was trying to unify.
The other thing I never made peace with is Ansible's execution model itself: modules get shipped to the destination host and interpreted there, so every target needs the right interpreter in the right state before automation can even begin. I much prefer a self-contained controller commanding the fleet — the model I already reach for everywhere else. It's why I like Kubernetes and ArgoCD, where a controller reconciles the fleet toward declared state, and why I'd pick Terraform over Ansible for provisioning. Both frictions feed an idea I keep coming back to: an Ansible-like platform written in Go from the ground up — cross-platform by default, driven by a controller instead of interpreted on the target.
Two companion repos came out of the work, both public:
gansible, a lightweight Go
helper for writing Ansible-compatible modules, and
glrcommon, the shared code
behind the runner modules.