It Compiles, It Scrapes, It Talks To Db2
Three Things For IBM i, From One Pile Of Patches
Three weeks ago I wrote that "wait a bit, you'll most probably get it." This is the bit you were waiting for.
The Go 1.25.9 toolchain runs natively on IBM i 7.5. node_exporter runs on top of it and emits real Prometheus metrics. And — as a side effect that turned out to be more useful than the goal — there's now a db2isql you can drop into ~/bin and use as a PASE replacement for STRSQL in green screen. All three are downloadable today.
If you want the short version: scroll to the bottom. If you want to know which IBM i quirks tried to kill me and lost, read on.
The Pile Of Patches
When I started, I promised myself I would not fork Go. I would maintain a re-baseable patch series against upstream, so that when Go 1.26 ships, I run git rebase, fix whatever the upstream Go team broke for me this time, and move on.
That promise survived contact with reality. The series sits at 42 patches against go1.25.9. The number is a coincidence. It is also, I am told, the answer to life, the universe, and everything, which feels appropriate for a Go port to a platform that does its own thing about most of life, the universe, and everything. All 42 apply cleanly. Each one does exactly one thing and has a commit message explaining why. The set covers everything from the one-line arenaBaseOffset fix in patch 3 (which I wrote about three weeks ago) up through patches in the high 30s and low 40s that deal with everything from PEM block rewriting to XCOFF build-info sections to go version -m metadata layout. As one specific example: one of the patches rewrites the string "TRUSTED CERTIFICATE" to "CERTIFICATE" in PEM blobs on the fly, because that's how IBM ships the CA bundle on PASE and crypto/x509.AppendCertsFromPEM is very particular about what it considers a certificate.
I'll spare you the other 40. The shape is always the same: write a probe in C or Go, confirm what PASE actually does, write the smallest possible patch, document, move on.
A few highlights, because some of them are funny:
Patch 18:
-p 1forgo test. PASE's XCOFF loader is not thread-safe acrossfork+exec. Run two parallelcompileinvocations and roughly half the time, one of them returns a loader error that looks like nothing else on Earth. Workaround: tellgo testto be single-threaded. Slow, but the tests pass.Patch 22: DWARF subtype sections disabled by default. When
go buildemits DWARF type info for IBM i, the PASE XCOFF loader takes one look at the result and refuses to load it with the helpful error code0x213c, which is the ASCII for!<, which is theararchive magic, which means the loader has wandered off into the middle of an archive and lost its place. Disabled until I figure out which DWARF subtype it's choking on.Patch 27/28:
cgoresolver forced on. PASE doesn't have/etc/resolv.confin any place Go's pure-Go resolver knows to look. The cgo resolver, which goes through libc and asks PASE nicely, works fine. So we force the cgo resolver on IBM i. Net result:http.Getworks.Patch 30: auto-detect
gcc-10orgcc-12. There is no unversionedgccon PASE. There is agccsymlink, but it points togcc-6, whoseinclude-fixedheaders are from 2017 and redefinesigset_tincompatibly with everything else on the system. You do not wantgcc-6. The patch asks the system "do you havegcc-10?gcc-12?" and picks the newest one that exists.Patch 32:
cmd/goneeds cgo on ibmi. Because of the resolver patch. Becausecmd/godoes DNS. Because everyone does DNS. This took an embarrassing amount of time to figure out.
Some Free Stuff: db2isql
This is the part that surprised me.
On IBM i, when you want to run SQL ad-hoc, you sign on, you type STRSQL, and you're in a green-screen interactive SQL session. It works. It's been working since 1988. Generations of IBM i administrators have muscle-memory for it.
But if you live in PASE — in ssh, in vim, in shell pipelines — STRSQL is a context switch every time. You leave your terminal, you sign on to a 5250 session, you run the query, you copy the result out by hand. There's no |. There's no >. There's no scripting it from a shell for loop.
The Go port supports cgo. The IBM i ships with libdb400.a, the Db2 SQL CLI library. Putting two and two together: I wrote a database/db2i package — in the Go standard library, alongside database/sql itself — that talks to Db2 for i over the CLI. It's not a database/sql driver, strictly speaking. PASE's threading and connection-lifetime constraints don't fit the driver.Driver interface cleanly, so database/db2i is a partial reimplementation of the same shape of API: Open, Query, Exec, Scan, Close. Familiar enough that anyone who has used database/sql will be at home in five minutes. Different enough that it can do what PASE needs without lying to the runtime.
That was supposed to be a private convenience for the node_exporter collectors. Then I wrapped a 200-line CLI around it called db2isql, and now I reach for it before I reach for STRSQL.
It pipes. It redirects. It returns proper exit codes. You can put it in a shell for loop. And anyone who wants to embed Db2 access into their own Go program just imports database/db2i and gets a working API straight from the standard library — no third-party package, no go get, no module bookkeeping.
STRSQL is still there when you want the interactive experience and the F4 prompts. db2isql is for when you want SQL to behave like every other Unix command.
It cost me about a week to write, of which six full days were spent fighting Db2 CLI quirks on PASE that nobody outside IBM has ever documented in one place. Things like:
Thread affinity is mandatory. Db2 CLI on PASE refuses to share connections across OS threads. Go schedules goroutines onto threads however it likes. The driver has to
runtime.LockOSThread()inOpenandruntime.UnlockOSThread()inClose, or the second query after a goroutine migration returns rc=-1 fromSQLAllocConnectand you spend a day debugging it.SQLGetDatais a trap. On PASE PPC64, callingSQLGetDatamore than ~6 times sequentially against the same row returns07006. Calling it against aVARGRAPHICcolumn returns07006immediately. The only safe pattern isSQLBindColonce andSQLFetchin a loop. Which is the documented best practice anyway, but it's nice when "best practice" and "the only thing that works" coincide.SQLSetConnectOption(AUTOCOMMIT)segfaults. Pass anint 1as aSQLPOINTERand PASE PPC64 dereferences it like a pointer. Don't call it. The default is autocommit-on. Move on.
All of these are now written down in my notes, so that the next time I don't have to rediscover them sequentially over six days.
node_exporter, At Last
The whole reason for this project was node_exporter. So let's close the loop.
With native Go installed, building node_exporter for IBM i is a 30-second exercise:
Out of the box, most of the standard collectors don't work — they read /proc, which PASE doesn't have. So I wrote twelve IBM i-specific collectors that go through QSYS2 system services instead:
The database/db2i package is what makes these collectors possible. Each collector is a few dozen lines of Go that opens a Db2 connection, runs a SELECT, and writes Prometheus metrics. The Db2 part is invisible to anyone looking at the resulting /metrics endpoint.
The output looks like every other node_exporter on Earth:
…but it also exposes things node_exporter on a Linux box has never heard of. The LPAR collector emits a single info gauge with everything you'd want to alert on baked in as labels:
node_lpar_info{
machine_type="9009",
machine_model="22A",
machine_serial_number="78D7930",
partition_id="8",
partition_name="vm-99024459-138560990",
ipl_type="B",
ipl_mode="NORMAL",
cpu_sharing_attribute="CAPPED",
dedicated_processors="NO",
hardware_multithreading="YES",
bound_hardware_threads="YES",
attention_light="OFF",
restricted_state="NO",
shared_processor_pool_id="0",
partition_group_id="32776"
} 1Wrap changes(node_lpar_info[5m]) around that in PromQL and you get an alert the moment the attention light comes on, or the partition gets moved by LPM. Things you'd otherwise notice by walking past the HMC.
The sysval collector exposes every system value the OS will tell you about. ~130 numeric and character system values, all carried as Prometheus metrics:
node_system_value{name="QMAXJOB"} 163520
node_system_value{name="QACTJOB"} 200
node_system_value{name="QPWDMINLEN"} 6
node_system_value{name="QPWDMAXLEN"} 8
node_system_value_info{name="QSECURITY",value="50"} 1
node_system_value_info{name="QAUDLVL",value="*SECCFG *SECRUN"} 1
node_system_value_info{name="QCRTAUT",value="*CHANGE"} 1
node_system_value_info{name="QPWDRULES",value="*PWDSYSVAL"} 1If you've ever wanted to alert when somebody quietly drops QSECURITY from 50 to 40, this is how. changes(node_system_value_info{name="QSECURITY"}[1h]) > 0 and you get a Slack ping within the scrape interval. Same trick works for any system value you care about.
Which means: same Prometheus, same Grafana, same dashboards, same alerts. Drop the binary on every IBM i partition you own, point your existing Prometheus at port 9100, and the IBM i finally joins its AIX and Linux siblings on the same dashboard — except now the IBM i is the one with the most interesting labels.
What You Came Here For
Three downloads. Direct links, no landing page, no clickthrough:
Go 1.25.9 for IBM i — go1.25.9-ibmi-port-45-ibmi-ppc64.tbz (checksum: .sha256).
# On the IBM i target, as any PASE user:
cd $HOME
/QOpenSys/pkgs/bin/tar xjf go1.25.9-ibmi-port-45-ibmi-ppc64.tbz
export PATH=$HOME/go-ibmi-1.25.9/bin:$PATH
export GOTMPDIR=$HOME/tmp # /tmp can be cleaned without your consent
mkdir -p $HOME/tmp
go versionYou should see go version go1.25.9 ibmi-port-45 ibmi/ppc64. Prerequisites you'll want from yum: gcc-10, db2-server-utils, ca-certificates-mozilla. The first go build after install takes tens of seconds while it warms its cache from the standard library; subsequent builds are sub-second.
A self-contained README-IBM-i.md ships inside the tarball with full prerequisites, env vars, and known limitations.
Cross-compilation from macOS or Linux x86_64 works (GOOS=ibmi GOARCH=ppc64), but I'm not shipping bootstrap binaries for those hosts in this release. If you need a cross-compiler, email me or write down the comment.
node_exporter for IBM i — node_exporter. Single binary. Drop it in /opt/node_exporter/, run it from a job description, scrape it on :9100.
db2isql — db2isql. Single binary. db2isql "your SQL here". Pipes work. -f json for when you want to feed it into something else.
Common Europe Congress 2026 is there!
The agenda is published! Do you want to know where AIX is going to? It means you MUST visit the Common Europe Congress in Lyon, France. There will be sessions about new AIX features and open source community development. We will talk about AIX and IBM Power automation and Zero Downtime for AIX. Join me in Lyon!
What's Next
The XCOFF build-info section isn't right yet, so go version -m <binary> reports "not a Go executable" against IBM i binaries. The binaries are fine — they just don't carry the build metadata in a section the upstream cmd/go knows how to find. That's the next patch.
After that: the loader race is currently worked around with -p 1. I'd like to actually fix it, by pre-warming the loader before cmd/go forks parallel children. That's a multi-week project, but it'll bring parallel builds back and make make.bash 8× faster on a real machine.
But most importantly, before any of that: the Common Europe Congress 2026 in Lyon, France. This is the first and biggest thing on my calendar. I need to be prepared, which means the next chunk of my time goes there. If you want to talk about the port, the collectors, what's missing, what should come next, or just to see the live demo running on a real LPAR — find me at the Congress. Grab me between sessions, corner me at coffee, wave at me across the room. Whatever works. I'd rather have those conversations face-to-face than over email.
If you build something on top of this, tell me. If something breaks, tell me. That's how you help everyone in the community!
Have fun with Go on IBM i!
Andrey
Hi, I am Andrey Klyachkin, IBM Champion and IBM AIX Community Advocate. This means I don’t work for IBM. Over the last twenty years, I have worked with many different IBM Power customers all over the world, both on-premise and in the cloud. I specialize in automating IBM Power infrastructures, making them even more robust and agile. I co-authored several IBM Redbooks and IBM Power certifications. I am an active Red Hat Certified Engineer and Instructor.
Follow me on LinkedIn, Twitter and YouTube.
You can meet me at events like IBM TechXchange, the Common Europe Congress, and GSE Germany’s IBM Power Working Group sessions.









