Skip to content

Instantly share code, notes, and snippets.

@rawsyntax
Created May 15, 2026 16:23
Show Gist options
  • Select an option

  • Save rawsyntax/76c7b7b6d7e5a76f6d8fff4a077585d5 to your computer and use it in GitHub Desktop.

Select an option

Save rawsyntax/76c7b7b6d7e5a76f6d8fff4a077585d5 to your computer and use it in GitHub Desktop.
AMS service-log client: why the local openapi-generator snapshot is the wrong default

AMS service-log client: why the local openapi-generator snapshot is the wrong default

Don't vendor generated OpenAPI clients when the SDK already has the types

Was reviewing a merge request in uhc-account-manager (AMS) today — OCM-24913 — that removes a dependency on gitlab.cee.redhat.com/service/ocm-service-log and replaces it with a locally vendored OpenAPI snapshot + code generation. The motivation is legit: gitlab.cee.redhat.com is behind the Red Hat VPN, and Konflux CI runs on a public cluster that can't reach it. So the module has to go.

The fix they landed: fetch the OpenAPI spec from the live API (https://api.openshift.com/api/service_logs/v1/openapi), run openapi-generator-cli against it, commit the output into pkg/client/uhc/service_log/openapi/, and provide a Makefile to refresh it periodically. ~40 generated files, a .travis.yml nobody will ever run, a git_push.sh that will never be executed, and a drift risk every time the upstream API changes.

This pattern already exists in AMS for rbac/ and candlepin/ — clients for internal Red Hat services that have no public equivalents. For those, the local snapshot is the right call. For ocm-service-log, it isn't.

The thing is, ocm-sdk-go already has this

ocm-sdk-go is the canonical Go client for OCM services. It has a servicelogs/v1 package. And AMS already depends on ocm-sdk-go v0.1.500 — it's in go.mod. So is ocm-api-model/clientapi v0.0.454, which is where the actual types live (ocm-sdk-go re-exports them as type aliases).

The type you want is LogEntry from github.com/openshift-online/ocm-sdk-go/servicelogs/v1. It has every field AMS actually uses: ID(), Severity(), ServiceName(), Summary(), Description(), ClusterUUID(), InternalOnly(), LogType(), Timestamp(). All present.

No new dependency. No VPN-blocked module. No generated noise. The dep is already there.

Why it's not a one-line swap

The type shapes are different enough that it's a real migration, not a find-and-replace.

The openapi-generator output gives you a flat struct with pointer fields:

createdLog := &slapi.ClusterLog{}
json.Unmarshal(response.Bytes(), createdLog)
// access: *createdLog.Id, *createdLog.Severity

The ocm-api-model type uses private fields with accessor methods and a custom jsoniter-based unmarshaler:

var createdLog v1.LogEntry
v1.UnmarshalLogEntry(bytes.NewReader(response.Bytes()), &createdLog)
// access: createdLog.ID(), createdLog.Severity()

The mock also needs to change — you can't do &LogEntry{Id: util.ToPtr(...)} since the fields are private. You use the builder:

v1.NewLogEntry().ID("...").Severity(v1.SeverityInfo).Summary("...").Build()

So the actual work is:

  1. Swap the import to slv1 "github.com/openshift-online/ocm-sdk-go/servicelogs/v1"
  2. Replace json.Unmarshal(response.Bytes(), createdLog) with slv1.UnmarshalLogEntry(bytes.NewReader(response.Bytes()), createdLog) in three places
  3. Change *created.Idcreated.ID() in pkg/triggers/actions.go
  4. Rewrite the mock's struct literal to use the builder
  5. Delete all of pkg/client/uhc/service_log/ — the whole thing

Net result: ~50 line change, minus 40 generated files. Worth it.

The broader pattern question

AMS has a pattern of vendoring local OpenAPI snapshots for external dependencies. For services that don't have a public Go module (rbac, candlepin), that's fine — you have no better option. But for OCM services specifically, ocm-sdk-go exists precisely to avoid this. The question to ask before reaching for openapi-generator is: does ocm-sdk-go already have this?

For service logs, the answer is yes. The generated types in ocm-api-model are what ocm-sdk-go is built on, and they're generated from the same upstream API spec using ocm-api-metamodel — the OCM-specific codegen tool that produces idiomatic Go with proper builders, accessors, and custom JSON handling instead of the generic openapi-generator output.

If you're building something that talks to an OCM API endpoint, check ocm-sdk-go first. The snapshot pattern is a fallback, not a default.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment