Skip to content

Refactor patch logic to use openapiv3 instead of v2/swagger - #446

Merged
tstirrat15 merged 6 commits into
mainfrom
tstirrat/refactor-to-use-openapi-v3
Sep 2, 2026
Merged

Refactor patch logic to use openapiv3 instead of v2/swagger#446
tstirrat15 merged 6 commits into
mainfrom
tstirrat/refactor-to-use-openapi-v3

Conversation

@tstirrat15

@tstirrat15 tstirrat15 commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Alternative to #445

Description

Under the old logic, the controller had to load the entirety of the API's swagger to construct the Strategic Patch Merges. This changes things to use the new OpenAPIv3 APIs provided by k8s, which reduces memory usage significantly, bringing down peak RSS from ~250mb to ~80:

Current numbers

phase            retained    +retained        churn      max rss
----------------------------------------------------------------
baseline          4.2 MiB            -            -     85.8 MiB
discovery         4.3 MiB    +90.2 KiB    531.9 KiB     85.8 MiB
controller        8.7 MiB     +4.4 MiB     12.1 MiB     85.8 MiB
openapi          16.1 MiB     +7.4 MiB     38.7 MiB     85.8 MiB

(as measured using the new script)

Changes

  • Add a patchmeta file that describes a resolver for various GVKs used by the controller
  • Make ApplyPatch look up the descriptions of the objects using that resolver
  • Stand up a resolver on startup instead of loading the entire openAPI description

Testing

Review. See that tests pass and are sane.

@codecov-commenter

codecov-commenter commented Aug 31, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 78.20513% with 17 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
pkg/config/patchmeta.go 83.01% 7 Missing and 2 partials ⚠️
pkg/cmd/run/run.go 0.00% 5 Missing ⚠️
pkg/config/patch.go 50.00% 2 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

@tstirrat15
tstirrat15 force-pushed the tstirrat/refactor-to-use-openapi-v3 branch 2 times, most recently from 3c0f6f0 to f1fb6ac Compare August 31, 2026 18:48
@tstirrat15
tstirrat15 force-pushed the tstirrat/refactor-to-use-openapi-v3 branch 2 times, most recently from bc1b14d to 6a7bfdf Compare August 31, 2026 19:36
@tstirrat15
tstirrat15 marked this pull request as ready for review August 31, 2026 19:38
@tstirrat15
tstirrat15 force-pushed the tstirrat/refactor-to-use-openapi-v3 branch 2 times, most recently from 95a3276 to 8105dfd Compare August 31, 2026 20:41
@tstirrat15
tstirrat15 force-pushed the tstirrat/refactor-to-use-openapi-v3 branch 6 times, most recently from 805259a to 7821663 Compare September 1, 2026 16:07

@tstirrat15 tstirrat15 left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comments

name: grpc
- containerPort: 8080
name: http
# We recommend that you do not configure a liveness probe on a production environment, as this can impact the availability of production databases.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Drive-by cleanup

Comment thread e2e/databases/manifests/mysql.yaml Outdated
Comment on lines +42 to +43
# mysql needs ~100mb for startup; this leaves some headroom.
storage: 500Mi

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to make the tests more stable

// The StatefulSet existing says nothing about the database accepting
// connections. Waiting on a ready replica means a pod that never starts
// surfaces here, instead of 5 minutes later as a connection refused.
if statefulSet.Status.ReadyReplicas < 1 {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some extra defensiveness

Comment thread e2e/e2e_test.go
Comment on lines +424 to +425
corev1.SchemeGroupVersion.WithResource("events"),
corev1.SchemeGroupVersion.WithResource("persistentvolumeclaims"),

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extra debug output that goes into artifacts

Comment thread pkg/cmd/run/run.go
}
}

resources, err := f.OpenAPISchema()

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was responsible for ~100mb of memory usage

Comment thread pkg/cmd/run/run.go
if err != nil {
return err
}
patchMetaResolver := config.NewV3PatchMetaResolver(openapi3.NewRoot(openAPIV3Client))

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We pass this resolver down so that we can fetch the objects as needed

Comment thread pkg/config/patchmeta.go

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is what does the work of fetching those objects from the k8s API

Comment thread pkg/config/patch.go
// Resolved here, at the only point that needs it, and with the
// GVK in hand -- which is what lets the v3 resolver fetch a
// single group-version instead of the whole cluster's schema.
lookupPatchMeta, err := resolver.LookupPatchMeta(gv.WithKind(*typeMeta.Kind))

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And this is where we actually do the lazy fetching

@tstirrat15
tstirrat15 force-pushed the tstirrat/refactor-to-use-openapi-v3 branch from 7821663 to 2c1a206 Compare September 1, 2026 16:20
@tstirrat15
tstirrat15 force-pushed the tstirrat/refactor-to-use-openapi-v3 branch from 2c1a206 to cb33119 Compare September 1, 2026 16:59
Comment on lines +25 to +26
- "--innodb-use-native-aio=0"
- "--innodb-flush-method=fsync"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This also seems to be salient

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we haven't changed any of this in a long time, i'm unclear on why this is needed now. if the explanation here were true, the tests would never have passed?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My assumption is that it's highly dependent on what the backing storage is/does, and therefore sensitive to exactly how CI is set up.

Comment on lines +25 to +26
- "--innodb-use-native-aio=0"
- "--innodb-flush-method=fsync"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we haven't changed any of this in a long time, i'm unclear on why this is needed now. if the explanation here were true, the tests would never have passed?

Comment thread e2e/assertions_test.go Outdated
// AssertDeploymentPatchedFunc asserts that a strategic merge patch actually
// reached the SpiceDB deployment, rather than merely failing to error.
// The container check is the primary part of the assertion.
func AssertDeploymentPatchedFunc(ctx context.Context, namespace string, kclient kubernetes.Interface) func(owner string, labels map[string]string, envName, envValue string) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: isn't this really AssertDeploymentEnvVar?

Comment thread e2e/e2e_test.go Outdated
// failure. The database namespaces matter as much as the per-spec ones: a
// database that never becomes ready fails specs in BeforeEach, and nothing in
// the test namespaces explains why.
var dumpNamespacePrefixes = []string{"test", "postgres-", "mysql-", "cockroachdb-"}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
var dumpNamespacePrefixes = []string{"test", "postgres-", "mysql-", "cockroachdb-"}
var dumpNamespacePrefixes = []string{"test", "postgres", "mysql", "cockroachdb"}

super nit

Comment thread e2e/e2e_test.go
name = pod.Name + "-" + container.Name + "-previous.log"
}

logs, err := k.CoreV1().Pods(namespace).GetLogs(pod.Name, &corev1.PodLogOptions{

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought I had written a Ginkgo helper somewhere to tail pod logs we could re-use

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tail in util_test.go? It seems like it's designed for asserting things about the logs on the side, rather than taking log output and directing it somewhere. I could use it but it's awkward.

resolver := newTestPatchMetaResolver()

for _, gvk := range patchedKinds {
t.Run(gvk.Kind, func(t *testing.T) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

t.Parallel?

@tstirrat15 tstirrat15 mentioned this pull request Sep 2, 2026
@tstirrat15
tstirrat15 added this pull request to the merge queue Sep 2, 2026
Merged via the queue into main with commit 258dbf9 Sep 2, 2026
10 of 11 checks passed
@tstirrat15
tstirrat15 deleted the tstirrat/refactor-to-use-openapi-v3 branch September 2, 2026 23:49
@github-actions github-actions Bot locked and limited conversation to collaborators Sep 2, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants