Luther Monson, Staff Software Engineer at SUSE

Luther Monson

Go by way of PHP · Containers · VMs · Windows · Kubernetes

From 52% to 100%: Measuring a Go Client Against the Proxmox API Schema

I built a stdlib-only mage target that pulls Proxmox's own API schema and regex-scans go-proxmox for HTTP call sites to report coverage. The tool was wrong more often than the code was.

8-Minute Read

Line chart of go-proxmox endpoint coverage from 4% in 2021 to 100% in May 2026

For five years the honest answer to “how much of the Proxmox API does go-proxmox cover?” was “a lot of it? the parts people asked for?”. Issues would come in for endpoints that didn’t exist in the client. I’d have no idea how many more were missing. At the end of May I finally built the thing that answers the question. Three days after the first run the answer was 100%. The more interesting part is how many times the measuring stick was wrong on the way there.

Cloud-Init ISOs in Pure Go with go-proxmox

Building nocloud cloud-init ISOs in memory with go-diskfs, uploading them to Proxmox and mounting them on a VM in one call, with no genisoimage.

8-Minute Read

Flow: makeCloudInitISO, upload to Proxmox storage, mount as CD-ROM, VM boots and cloud-init reads the cidata volume, cleanup

Proxmox’s built-in cloud-init support is fine for the basics: a user, an SSH key, an IP config. It falls apart the second you want your own user-data, vendor-data or a real network-config. The GUI and the ci* options only expose a handful of fields. The escape hatch is cicustom pointing at snippet files, and that means getting files onto the Proxmox host’s filesystem first. The usual alternative is building a nocloud ISO yourself with genisoimage or mkisofs. That means a system…

Staying Logged In to Proxmox: Ticket Renewal, Expiry and Where API Tokens Stop

Proxmox tickets die after two hours. How go-proxmox went from never re-authenticating to renewing tickets in place, plus the one thing API tokens can't do.

7-Minute Read

Timeline of a Proxmox ticket: valid for two hours server side, considered stale by the client after one

Back in 2023 I wrote up how go-proxmox logs in and ended it with a shrug. Once a session existed the client never logged in again. A ticket-based client died at the two hour mark. My advice was “use an API token for anything long running”. It took until this month to fix that properly. It took three PRs from two of us to get there. Here’s the whole arc, plus the one place where an API token isn’t an option at all.

go-diskfs: Getting Rock Ridge Working for Joliet on Windows

I fixed Rock Ridge and added Joliet to go-diskfs so a Go-built cloud-init ISO works for cloudbase-init. Then I found out what Windows actually wanted.

10-Minute Read

Sector map of a cidata ISO built by go-diskfs with a Rock Ridge primary tree and a Joliet supplementary tree sharing the same file extents

go-proxmox has had a CloudInit() helper since 2023. It builds a small nocloud ISO in Go, uploads it to Proxmox and mounts it on the VM as a CD-ROM. It’s always worked fine for Linux guests. It has never worked for Windows guests running cloudbase-init. The reason is a filesystem extension from 1995 called Joliet.

Maintaining a Go Tool That Edits /etc/hosts on Every OS

Notes from maintaining goodhosts, the hosts file CLI and Go library behind vagrant-goodhosts and ddev. It covers Windows quirks, a HostsPerLine bug, and making the CLI testable.

8-Minute Read

hosts file output from hostsfile v0.1.4, v0.1.5 and v0.1.6 for the same sequence of adds

Editing the hosts file sounds like the most boring problem in software. Read a text file, add a line, write it back. Then you find out your binary is being shelled out to from a Ruby Vagrant plugin on a Windows laptop with UAC prompts. Your library is being called in a loop by ddev. And every hosts file you parse was hand-edited by somebody at some point. I’ve been maintaining goodhosts for a few years now. I just spent a chunk of the fall and the holidays on it, so here’s what that…

Proxmox Doesn't Know What Type a Number Is

The Proxmox VE API returns the same field as 1234 in one place and "1234" in another. This is why go-proxmox has StringOrInt, StringOrUint64, StringOrFloat64 and IntOrBool instead of plain Go types.

5-Minute Read

Proxmox VE Logo

Every couple of months somebody opens an issue on go-proxmox with a title that starts with json: cannot unmarshal string into Go struct field. The most recent one was fixed last week. It’s the same root cause every time. The Proxmox VE API is backed by Perl, and Perl doesn’t really care whether a scalar is a number or a string. The JSON encoder on the other end writes whatever the scalar happens to be at the time. So a field that is documented as an integer comes back as 2048 from…

Logging In to Proxmox From Go: Tickets, CSRF Tokens and API Tokens

Proxmox VE has two ways to authenticate against its API. Here's how go-proxmox handles each one and why the client is now configured entirely with functional options.

5-Minute Read

Diagram of the ticket login flow and the API token header for the Proxmox VE API

I just spent a week of evenings on the access side of go-proxmox. Realms, groups, users and roles all landed. Before any of that, I reworked how a client gets its credentials in the first place. Proxmox gives you two different ways to authenticate. They behave differently enough that it’s worth writing down how each one works on the wire and what the client does with it.

Waiting on Proxmox: UPIDs, Tasks and WaitFor in Go

Most Proxmox VE API calls that change something hand you a UPID instead of a result. Here is how go-proxmox turns that string into something you can wait on.

6-Minute Read

Diagram breaking a Proxmox UPID string into node, pid, pstart, starttime, type, id and user

If you start automating Proxmox VE through the API, one thing trips you up first. Almost nothing you ask it to do is finished when the HTTP call returns. Start a VM, clone a template, download an ISO to storage, delete a disk… the response is a single string that looks like a typo. The actual work is happening in a worker process on the node. If your next call depends on that work being done, you have to go find out when it’s done.

Recreating Proxmox Ve Xtermjs in Go

Proxmox's web console is xterm.js over a websocket. Here's how I reverse engineered that protocol and rebuilt the terminal connection in Go with go-proxmox.

9-Minute Read

Proxmox VE Logo

Part of a hobby of mine is running a home lab and using on Proxmox VE to do the virtualization. Since I work in the space I’m slowly trying to build tooling around Proxmox that will let me use the home lab full time for work. Usually my work involves building Kubernetes management tooling. You can imagine waiting for public cloud APIs all day can take away hours of your day. That’s at cost to your employer for both your time and the compute resources.

Practical Cue Example, Produce YAML Config from Go Types

A hands-on Cue tutorial: start from Go types, generate Cue definitions, and produce two different YAML config files from them.

5-Minute Read

I recently had to spend some time to learn Cue and felt the examples/tutorials were a bit lacking. The paradigm shift to the entire language sort of messed with my head, and some things Cue does were a bit foreign to me. To get started, note that I spent all of my time getting this information from two places: their main docs and a community Cuetorials site. This will be a tutorial on how you can use Cue to generate two different YAML documents, all starting with Go types to generate Cue files.

Recent Posts

Categories

About

Luther is a 20+ year software veteran specializing in backend APIs and architecting products. Employed at SUSE as the Team Lead for the Containers on Windows Team working on Rancher + Kubernetes