From 4ac2a1abaccd762512a111304ada61816e9be231 Mon Sep 17 00:00:00 2001 From: Bittrance Date: Fri, 27 Mar 2026 16:34:11 +0100 Subject: [PATCH] pod overrides now work as expected corev1.PodSpec has attributes that are not omitempty (presuambly because they are mandatory) which meant that the override spec would have nil on those attributes, resulting in a broken podspec. --- pkg/resources/pod.go | 14 ++++++++++++- pkg/resources/pod_test.go | 3 +++ test/e2e/e2e_test.go | 43 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 1 deletion(-) diff --git a/pkg/resources/pod.go b/pkg/resources/pod.go index 24e9f41..5a52718 100644 --- a/pkg/resources/pod.go +++ b/pkg/resources/pod.go @@ -378,13 +378,25 @@ func applyPodOverrides(base, overrides corev1.PodSpec) corev1.PodSpec { return base } + // We diff overrides against an empty PodSpec to produce a patch containing only + // fields the user explicitly set (avoiding null fields from zero-value slices/maps + // that would otherwise wipe out base fields like Containers). + emptyJSON, err := json.Marshal(corev1.PodSpec{}) + if err != nil { + return base + } + patch, err := strategicpatch.CreateTwoWayMergePatch(emptyJSON, overridesJSON, corev1.PodSpec{}) + if err != nil { + return base + } + patchMeta, err := strategicpatch.NewPatchMetaFromStruct(&corev1.PodSpec{}) if err != nil { return base } merged, err := strategicpatch.StrategicMergePatchUsingLookupPatchMeta( - baseJSON, overridesJSON, patchMeta) + baseJSON, patch, patchMeta) if err != nil { return base } diff --git a/pkg/resources/pod_test.go b/pkg/resources/pod_test.go index 43a851d..fa4179a 100644 --- a/pkg/resources/pod_test.go +++ b/pkg/resources/pod_test.go @@ -310,6 +310,9 @@ func TestBuildPod_PodOverrides(t *testing.T) { if pod.Spec.NodeSelector["gpu"] != "true" { t.Errorf("expected nodeSelector gpu='true', got '%s'", pod.Spec.NodeSelector["gpu"]) } + if pod.Spec.Containers == nil { + t.Errorf("expected overrides not to touch container") + } } func TestBuildPod_CustomPort(t *testing.T) { diff --git a/test/e2e/e2e_test.go b/test/e2e/e2e_test.go index 960f9b4..dde38d9 100644 --- a/test/e2e/e2e_test.go +++ b/test/e2e/e2e_test.go @@ -441,6 +441,49 @@ spec: _, _ = utils.Run(cmd) }) + It("should add volumes from podOverrides", func() { + notebookName := "e2e-pod-overrides" + + By("creating a MarimoNotebook with podOverrides volumes") + notebookYAML := fmt.Sprintf(` +apiVersion: marimo.io/v1alpha1 +kind: MarimoNotebook +metadata: + name: %s + namespace: %s +spec: + source: "https://github.com/marimo-team/marimo.git" + podOverrides: + volumes: + - name: ssh-pubkey + secret: + secretName: ssh-pubkey + defaultMode: 0600 +`, notebookName, testNamespace) + + yamlFile := filepath.Join("/tmp", notebookName+".yaml") + err := os.WriteFile(yamlFile, []byte(notebookYAML), 0644) + Expect(err).NotTo(HaveOccurred()) + + cmd := exec.Command("kubectl", "apply", "-f", yamlFile) + _, err = utils.Run(cmd) + Expect(err).NotTo(HaveOccurred(), "Failed to create MarimoNotebook") + + By("verifying Pod has the overridden volume") + verifyVolumePresent := func(g Gomega) { + cmd := exec.Command("kubectl", "get", "pod", notebookName, "-n", testNamespace, + "-o", `jsonpath={.spec.volumes[?(@.name=="ssh-pubkey")].secret.secretName}`) + output, err := utils.Run(cmd) + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(output).To(Equal("ssh-pubkey")) + } + Eventually(verifyVolumePresent, 2*time.Minute, time.Second).Should(Succeed()) + + By("cleaning up") + cmd = exec.Command("kubectl", "delete", "marimo", notebookName, "-n", testNamespace) + _, _ = utils.Run(cmd) + }) + It("should create sidecar containers with exposed ports", func() { notebookName := "e2e-sidecar"