Releases: schankst/go-xen-api-client
Release list
v0.2.3 - CI, gofmt-clean generated code, docs
Tooling and documentation release - no API or behavior change, and no
schema change (still XAPI release 26.16.1-next,
xenapi.SchemaXAPIRelease unchanged).
CI
- New
Testsworkflow:go build,go vetandgo test -short -raceon
every push and pull request, across a matrix of Go 1.16 (the minimum
go.moddeclares) and current stable Go. - A repository-wide
gofmtcheck runs alongside it. regenerate.ymlnow pins the generators to stable Go instead of
followinggo.mod's 1.16. The generators format their own output, so
the toolchain running them decides what the committed files look like,
and gofmt's rules change between Go releases (Go 1.19 reformatted doc
comments). The 1.16 minimum for consumers of the library is covered by
the test matrix instead.
Generated code
xenapi.goandgen_errors.gorender into memory and run the result
throughgo/formatbefore writing, so*_gen.goanderror.goare
gofmt-clean by construction rather than depending on whitespace tuning
in the templates.- Everything was regenerated accordingly. The diff is whitespace-only:
apart from intra-line spacing (_method + " -> "became
_method+" -> "), the only change is the blank//line gofmt inserts
before an indented block in a doc comment. No declaration, signature or
value changed.
Documentation
- New
UPDATES_AND_PATCHES.md- finding pending patches: unapplied
pool_updateobjects,
repository-based updates, and outstanding post-update guidances.
- finding pending patches: unapplied
GOOD_TO_KNOW.md: theother_configboot_time/agent_start_time
convention.MAINTAINING.md: a section on formatting of generated code and why
regeneration needs a current toolchain.- README: Go Reference, release, Go version, license and CI badges.
- Code of Conduct, issue templates, and a pull request template.
- LICENSE copyright holder corrected.
v0.2.2 - Event timestamp parsing fix
Bugfix release - no schema change, still XAPI release 26.16.1-next
(xenapi.SchemaXAPIRelease unchanged).
Fixed
EventRecord.Timestamp(fromEvent.Next, i.e.event.next) could
arrive from a live XCP-ng host as an OCaml-style float-as-string Unix
timestamp (e.g."1784931839."- note the trailing dot, from OCaml's
string_of_floaton a whole number) instead of a properly wire-tagged
dateTime.iso8601value.convertTimeToGofailed the entire event on
this mismatch instead of just this one field.convertTimeToGonow falls back tostrconv.ParseFloat+time.Unix
for anydatetime-typed field that isn't already a decodedtime.Time,
mirroring this generator's existing enum-tolerance approach to
schema/wire divergence (baked intoxenapi.go, not a one-off patch).
Why this showed up now
Found building a Task/Event-driven VM start/stop monitor in the
xen CLI: watching a XenAPI Task via
Event.Register/Event.Next (scoped to the task class) hit this on
every single event, silently degrading the monitor to polling-only every
time instead of ever using the event stream it was built to use.
See GOOD_TO_KNOW.md
for the write-up, and convert_test.go for regression tests covering the
normal time.Time case, the OCaml float-string case, a plain-integer
fallback, and the invalid-input error case.
v0.2.1 - Enum tolerance baked into the generator
Through v0.2.0, unknown-enum-value tolerance was a separate post-generation step: xenapi.go generated strict, upstream-style hard-erroring enum parsers, then patch_enums.go rewrote convert_gen.go's default cases afterward. That made sense when the fix was first discovered reactively — now that xenapi.go is fully documented and understood (see v0.2.0's documentation pass), there's no reason not to fix it at the source.
convertEnumTypeToGoFuncTemplate now emits the tolerant default case directly. patch_enums.go is removed, along with its step in regenerate.yml — one less moving part in the regeneration pipeline.
No functional change: a full regeneration produces byte-identical output except for the 72 default-case bodies, which are functionally identical to before (same value = EnumType(strValue) fallback, just emitted directly instead of patched in afterward). Verified against a real XCP-ng host.
v0.2.0 - xmlrpc rewritten from scratch (license fix)
Why
amfranz/go-xmlrpc-client, vendored into xmlrpc/ in v0.1.2, has no license — upstream never had one. Fine as a compiled external module dependency; a real problem once fully copied into this repo. Rather than accept that risk (or just wait on an upstream response), rewrote the package from scratch.
What's different
Same public contract (Client, NewClient, Struct, Base64, Call, minus the Params wrapper type — folded directly into Call's signature), materially different internals:
-
Dropped
net/rpc'sClientCodec. XML-RPC over HTTP is one POST, one response — no multiplexed-connection semantics to justifynet/rpc's channel/sequence-number machinery.Client.Callis now a direct, synchronous round trip. -
Request building now uses
strings.Builderinstead of repeatedstring +=concatenation. Benchmarked both against identical payloads:old new struct, 100 fields 322,683 ns/op, 1413 allocs 14,848 ns/op, 214 allocs ~22x faster array, 5000 elements 133 ms/op, 51,424 allocs, 567 MB 0.53 ms/op, 5,026 allocs, 988 KB ~250x faster, ~573x less memory The old code was quietly O(n²) on payload size — this isn't a cosmetic rewrite, it's a real algorithmic fix.
-
Response parsing replaces regex-based substring extraction over the raw response bytes with a proper recursive-descent walk of the full
<methodResponse>document viaencoding/xml.Decoder. Every token read checks its error immediately and, by construction, cannot loop forever on malformed input (the class of bug fixed reactively in v0.1.3 for the old parser).
Tests
Rewritten test suite: httptest.Server-based integration tests for Client.Call (success, XML-RPC fault, pool-affinity cookie capture/replay, concurrent calls), plus value round-trip and malformed-input tests.
Verified against a real XCP-ng host — identical output to v0.1.5.
What this unblocks
This was the last blocker to eventually making this repo public — no part of it is unlicensed third-party code anymore.
v0.1.5 - Tests, error messages, README status
Addresses the remaining items from upstream's original 'Project status' TODO list:
- Tests:
xmlrpcrequest/response round-trip (string, int, bool, struct, array, nested), specifically including that unknown enum values pass through correctly and that malformed/truncated XML returns an error instead of hanging (the exact class of bug fixed in v0.1.3). Plus a few representativeconvert_gen.goconverter tests. Not exhaustive across all 74 generated files, but covers what has actually broken in this fork's history. - CI:
go test -short ./...added to the regeneration workflow, so these actually run continuously. - Fixed
client_test.go's pre-existingTestAuthentication, which required a live server onlocalhost:40080and would hang/fail under any CI — now skips under-short. - Better error messages:
Error.Error()no longer prints blank fields for error codes that don't carry an object type/UUID. - README: rewrote the 'Project status' section against this fork's actual state (2 of upstream's 5 TODO items were already resolved, one was already true from the start) and documented that this fork is actively maintained.
v0.1.4 - Documentation fixes
Fills in documentation gaps in the hand-maintained scaffolding around the generated API (the generated code itself was already well documented from the XenAPI schema's own descriptions):
- Added a package-level doc comment (
doc.go) —go doc .previously dumped straight into the symbol list with no introduction. - Documented
NewClient,Client(via its generator template, so it survives regeneration),Client.APICall, andAPIResult— all previously undocumented. - Replaced upstream's placeholder
// Code ...-style comments onError's accessor methods with real descriptions (viagen_errors.go's template, so they survive regeneration too). - Replaced
xmlrpc's leftoverTODO: Actual usage documentation herewith an actual note.
No functional changes. Verified against a real XCP-ng host.
v0.1.3 - Parser hang-risk fix
Fixes both go vet findings surfaced by vendoring xmlrpc/ in v0.1.2:
xmlrpc/request.go:buildValueElement's default case built anfmt.Errorfand discarded it instead of surfacing it, silently emitting an incomplete<value></value>for any unsupported Go type. Now panics instead — every caller in this codebase only ever passes known-safe types, so this is a programmer error, not a runtime condition to tolerate.xmlrpc/result.go: what looked like simple unreachable code (a trailingreturnafter an unconditionalfor {}loop) turned out to be masking a real bug —getValue,getStructValue,getStructMember, andgetArrayValuedidn't check the error fromparser.Token()inside their loops. On malformed or truncated XML, this could spin forever re-fetching the same error instead of returning it. Added the missing checks throughout (getStructMembernow returns an error too) and removed the now-genuinely-unreachable trailing returns.
Verified against a real XCP-ng host afterwards — identical output to v0.1.2, no regressions.
v0.1.2 - Vendor the last external dependency
Vendors amfranz/go-xmlrpc-client (the XML-RPC wire-protocol implementation XenAPI's client sits on) into xmlrpc/, dropping the last remaining external module dependency. go.mod now has zero external requires.
Not a reaction to a vulnerability — the library had none, and per its own go.mod no transitive dependencies either. Purely to remove the last external module reference from this fork's supply chain.
No LICENSE file existed upstream at the time of vendoring; attribution to the original author is preserved in xmlrpc/doc.go.
Side effect: go vet now checks the vendored code too (it never did as an external dependency) and flagged two pre-existing minor issues in xmlrpc/request.go and xmlrpc/result.go (unreachable code, a discarded fmt.Errorf() result). Left as-is for this release; candidates for a follow-up cleanup.
v0.1.1 - Security fix
Removes the github.com/sirupsen/logrus dependency, fixing CVE-2025-65637 (GHSA-4f99-4q7p-p3gh) — a DoS in Entry.Writer() on long single-line payloads, present in the pinned v1.6.0.
logrus was only used in client_test.go's TestMain for log.SetOutput(os.Stdout), which the standard library's log package already does identically. Switched to stdlib log and dropped the dependency entirely rather than just bumping the version — no functional change, one less dependency.
v0.1.0
First tagged release of this private fork.
Why this fork exists
Upstream terra-farm/go-xen-api-client
was last released as v0.0.2, generated from an XenAPI schema snapshot
current only through XenServer 7.3 ("inverness", ~2017). Against a modern
XCP-ng host this broke immediately: the schema predates VM operations like
"sysprep", and the generated enum parsers hard-error on any value they
don't recognize instead of tolerating it.
Changes vs. upstream v0.0.2
Bindings regenerated from the current XenAPI schema (release
26.16.1-next at the time of this release — see xenapi.SchemaXAPIRelease).
Regenerating from a schema this much newer than the generator (xenapi.go)
itself required teaching the generator four schema constructs it didn't
understand yet:
lifecyclechanged from a bare array to an object ({state, transitions}).- New opaque result type
"an event batch"(event batching, used by
Event.from) — mapped toxmlrpc.Structsince it isn't a proper record
and this fork doesn't need it typed. - New polymorphic field type
<class> record(Event.snapshot— the
concrete type depends on the event's class at runtime) — likewise mapped
toxmlrpc.Struct. - New
X optiontype pattern (optional values) — added as a generic
nil-tolerant wrapper around the inner type's own converter.
Along the way, some enums (e.g. CertificatePurpose, UpdateGuidances)
turned out to be declared under more than one class in the newer schema; the
generator now tracks already-emitted enum names so it doesn't emit the same
Go type twice.
Tolerate unknown enum values from newer XAPI versions, as a hedge against
anything even newer than the schema above. All generated *ToGo enum
converters in convert_gen.go (72 of them, one per enum type) pass unknown
values through as-is instead of failing the whole record parse.
error.go regenerated from the current upstream error definitions
(ocaml/xapi-consts/api_errors.ml) instead of the 7-year-old hand-copied
list: 414 -> 635 constants. Six stale ones were dropped because the
underlying error codes were removed/consolidated upstream (three
VM_LACKS_FEATURE_* variants collapsed into one generic VM_LACKS_FEATURE;
POOL_JOINING_HOST_CANNOT_CONTAIN_NETWORK_BOND / SR_ATTACHED_ON_SLAVE /
SR_DETACHED_ON_MASTER no longer exist upstream). Constant names are now
mechanically derived (ERR_ + uppercased OCaml identifier) instead of
hand-picked, so they can't drift out of sync again.
Automated weekly regeneration via .github/workflows/regenerate.yml —
checks upstream xenapi.json for drift and, on success, auto-commits, bumps
the version, tags, and pushes. Fails loudly and opens an issue instead if it
hits a schema construct the generator has never seen. See README for details
and its limits.
Module path changed to github.com/schankst/go-xen-api-client (from
github.com/terra-farm/go-xen-api-client) so it can be pulled in directly
via go get/require without a replace directive.
Versioning
This module's Git tags are its own SemVer, independent of XenAPI's own
versioning — see README's "Versioning" section for why, and for how
xenapi.SchemaXAPIRelease tracks which live XAPI version a given tag was
verified against.