Skip to content

fix: heap sizing and signing policy changes without a CA restart (#592, #588) - #593

Merged
slauger merged 2 commits into
developfrom
fix/javaargs-and-policy-mount
Sep 4, 2026
Merged

slauger merged 2 commits into
developfrom
fix/javaargs-and-policy-mount

Conversation

@slauger

@slauger slauger commented Sep 3, 2026

Copy link
Copy Markdown
Owner

Two fixes, one commit each.

#592 -- javaArgs default made the heap derivation dead code

resolveJavaArgs sizes the JVM heap at 90 percent of the pod's memory limit when javaArgs is unset. The CRD default made that unreachable: the field was never empty, so every Server ran with -Xms512m -Xmx1024m regardless of its limit. A Server given 8Gi used 1Gi of it.

Third instance of one mistake after #550 (image repository/tag) and #576 (pullPolicy). A default removes the empty state a fallback depends on, so it belongs in the chart where it is visible rather than in the CRD where it disables code.

Worth noting how it survived: three unit tests already covered resolveJavaArgs, including the memory-derived branch, and all passed. They call the function directly and so prove nothing about whether the field can be empty in a real cluster. Replaced them with a round-trip through the API server, which fails against the old CRD and names the materialised value:

javaArgs must come back empty so the heap can be derived, got "-Xms512m -Xmx1024m"

This also restores the auto-tuning statement in the README and feature list, which I had corrected in #591 to match the broken behaviour rather than the intended one.

Upgrade note: existing Servers carry javaArgs materialised from the old default and keep it until the field is cleared. A helm upgrade clears it; hand-written resources need it removed.

#588 -- policy edits restarted the CA

The policy Secret was mounted with SubPath, which the kubelet never refreshes, so the operator compensated with a hash annotation on the pod template. With the CA Deployment on the Recreate strategy, every SigningPolicy edit meant a short outage -- no signing, no CRL -- for a change that alters no running state.

Nothing downstream needed it: openvox-autosign is executed per CSR and reads the file each time. Only the mount did.

Now mounted as a directory, the way the CRL Secret already is for the same reason, with the file passed via --config. The hash annotation is gone.

Trade-off: a change takes effect within the kubelet sync period, up to about a minute, instead of immediately after a restart. For a rule deciding which CSRs get signed, that is the better end of the trade -- and it is stated in the concept page rather than left as a surprise.

Test changes

The old test asserted the annotation exists. It now asserts the opposite and that the mount carries no SubPath, since reintroducing one would silently bring the whole problem back. The rendered puppet.conf is checked for the config path as well: a wrong path denies every CSR and would otherwise surface only in an end-to-end run.

Verification

make test (with envtest), make manifests and golangci-lint 2.13.2 are clean. The autosign-policy e2e scenario exercises the new mount path end to end.

Closes #592
Closes #588

resolveJavaArgs sizes the JVM heap at 90 percent of the pod's memory limit
when javaArgs is unset. The CRD default made that unreachable: the field was
never empty, the explicit branch always won, and every Server ran with
-Xms512m -Xmx1024m no matter how much memory it was given. A Server with 8Gi
used 1Gi of it.

Third instance of one mistake after #550 and #576. A nested or plain default
removes the empty state a fallback depends on, so the default belongs in the
chart where it is visible, not in the CRD where it disables code.

The existing unit tests did not catch this and could not: they call
resolveJavaArgs directly and therefore pass whether or not the field can ever
be empty in a real cluster. Added the round-trip through the API server
instead, which fails against the old CRD with the materialised value in the
message.

Restores the auto-tuning statement in the README and the feature list, which
I had corrected to match the broken behaviour rather than the intended one.

Closes #592
Every SigningPolicy edit rolled the CA pod. The policy Secret was mounted
with SubPath, which the kubelet never refreshes, so the operator compensated
with a hash annotation on the pod template. Because the CA Deployment uses
the Recreate strategy, that meant a short outage - no signing, no CRL - for a
change that alters no running state. On a VM-based Puppet, editing autosign
configuration has no serving impact at all.

Nothing downstream required the restart: openvox-autosign is executed per CSR
and reads the file each time. Only the mount did.

Mount the Secret as a directory instead, the way the CRL Secret already is
for the same reason, and pass the file to the binary with --config. The hash
annotation is gone, so a policy edit no longer touches the pod template.

The trade-off is timing: a change now takes effect within the kubelet sync
period, up to about a minute, rather than immediately after a restart. For a
rule deciding which CSRs get signed, that is the better end of the trade.

The former test asserted the annotation exists; it now asserts the opposite
and that the mount carries no SubPath, since a SubPath would silently
reintroduce the whole problem. The rendered puppet.conf is checked for the
config path too - a wrong one denies every CSR and would otherwise only
surface in an end-to-end run.

Closes #588
@slauger
slauger merged commit c3b7f4b into develop Sep 4, 2026
50 of 51 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant