Skip to content

fix: use JSON patches to preserve unknown pod fields#19

Open
LoneExile wants to merge 1 commit into
piraeusdatastore:masterfrom
LoneExile:fix/update-k8s-api-sidecar-containers
Open

fix: use JSON patches to preserve unknown pod fields#19
LoneExile wants to merge 1 commit into
piraeusdatastore:masterfrom
LoneExile:fix/update-k8s-api-sidecar-containers

Conversation

@LoneExile
Copy link
Copy Markdown

Summary

The admission webhook silently strips restartPolicy: Always from init containers, breaking Kubernetes native sidecar containers (GA since K8s 1.33). This causes KubeVirt VMs to get stuck at Init:0/1 because the guest-console-log sidecar never transitions to running mode.

Environment

Component Version
linstor-scheduler-extender v0.3.2 (k8s.io/api v0.25.6)
piraeus-operator v2.10.2
linstor-affinity-controller v1.3.0
Kubernetes v1.35.0
KubeVirt v1.7.1

Root Cause

The webhook uses kubewebhook/v2 which deserializes every pod into a typed corev1.Pod struct compiled against k8s.io/api v0.25.6 (K8s 1.25). The restartPolicy field on Container was added in k8s.io/api v0.28.0 (K8s 1.28). During the deserialize → mutate → re-serialize cycle, all
fields unknown to the old types are silently dropped — even when the webhook makes no changes to those fields.

Since the webhook has no namespaceSelector or objectSelector, it intercepts all pod CREATEs cluster-wide, stripping restartPolicy from every pod's init containers.

Fix

Replaced the kubewebhook/v2 framework with direct admission/v1 API usage and targeted JSON patches.

Before: Webhook deserializes pod → modifies schedulerName → re-serializes entire pod → framework diffs to produce patch (patch includes removal of unknown fields)

After: Webhook deserializes pod for reading only (to check volumes/PVCs) → returns a targeted JSON Patch (RFC 6902) that only sets /spec/schedulerName → unknown fields are never touched

This approach:

  • Requires zero K8s dependency updates — works with existing k8s.io/api v0.25.6
  • Is future-proof — will never strip fields regardless of K8s version
  • Removes the kubewebhook/v2 dependency entirely

Changes

  • cmd/linstor-scheduler-admission/linstor-scheduler-admission.go — Rewritten to use admission/v1 API with JSON patch responses
  • go.mod / go.sum — Removed github.com/slok/kubewebhook/v2 and transitive deps

Testing

Tested on a cluster (K8s v1.35.0, KubeVirt v1.7.1, 11 nodes):

  1. Deployed the fix
  2. Created a pod with restartPolicy: Always on an init container → preserved (was stripped before)
  3. Restarted a KubeVirt VM → pod came up 2/2 Running with guest-console-log sidecar working correctly (was stuck at Init:0/1 before)

Related Issues

Copy link
Copy Markdown
Member

@WanzenBug WanzenBug left a comment

Choose a reason for hiding this comment

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

Looks good to me.

@WanzenBug
Copy link
Copy Markdown
Member

Please ensure that the DCO is signed of.

Replace kubewebhook framework with direct admission/v1 API and JSON
patches. The old approach deserializes pods into typed Go structs
(k8s.io/api v0.25.6) which silently drops fields added in newer K8s
versions — notably initContainers[].restartPolicy (native sidecars,
added in K8s 1.28). This caused KubeVirt VMs to get stuck at Init:0/1
when the guest-console-log sidecar's restartPolicy was stripped.

The new approach reads the pod for decision-making but returns a
targeted JSON patch that only modifies schedulerName, never touching
fields we didn't explicitly set.

Signed-off-by: Apinant U-suwantim <Hello@Apinant.dev>
@LoneExile LoneExile force-pushed the fix/update-k8s-api-sidecar-containers branch from 5d0fec3 to a7a01b5 Compare March 3, 2026 16:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants