From 08900f5f11ae0e8d66bad1929550b5c0ed82de2f Mon Sep 17 00:00:00 2001 From: faizanfirdousi Date: Thu, 10 Sep 2026 22:29:56 +0530 Subject: [PATCH] fix(kubernetes): extract images from initContainers and CronJob templates Bring the standard kubernetes plugin to parity with kubernetes_multicluster (#6808). Signed-off-by: faizanfirdousi --- .../plugin/kubernetes/provider/deployment.go | 16 ++- .../kubernetes/provider/deployment_test.go | 99 +++++++++++++++++++ 2 files changed, 112 insertions(+), 3 deletions(-) diff --git a/pkg/app/pipedv1/plugin/kubernetes/provider/deployment.go b/pkg/app/pipedv1/plugin/kubernetes/provider/deployment.go index b60aaa6162..641b5e559d 100644 --- a/pkg/app/pipedv1/plugin/kubernetes/provider/deployment.go +++ b/pkg/app/pipedv1/plugin/kubernetes/provider/deployment.go @@ -21,15 +21,25 @@ import ( // FindContainerImages finds all container images that are referenced by the given manifest. // // It looks for container images in the following fields: -// - spec.template.spec.containers.image -// -// TODO: we should consider other fields like spec.template.spec.initContainers.image, spec.jobTempate.spec.template.spec.containers.image +// - spec.template.spec.containers[*].image +// - spec.template.spec.initContainers[*].image +// - spec.jobTemplate.spec.template.spec.containers[*].image +// - spec.jobTemplate.spec.template.spec.initContainers[*].image func FindContainerImages(m Manifest) []string { var images []string if n := nestedStringSlice(m.body.Object, "spec", "template", "spec", "containers", "image"); len(n) > 0 { images = append(images, n...) } + if n := nestedStringSlice(m.body.Object, "spec", "template", "spec", "initContainers", "image"); len(n) > 0 { + images = append(images, n...) + } + if n := nestedStringSlice(m.body.Object, "spec", "jobTemplate", "spec", "template", "spec", "containers", "image"); len(n) > 0 { + images = append(images, n...) + } + if n := nestedStringSlice(m.body.Object, "spec", "jobTemplate", "spec", "template", "spec", "initContainers", "image"); len(n) > 0 { + images = append(images, n...) + } slices.Sort(images) return slices.Compact(images) diff --git a/pkg/app/pipedv1/plugin/kubernetes/provider/deployment_test.go b/pkg/app/pipedv1/plugin/kubernetes/provider/deployment_test.go index 52c9a99764..921597fc61 100644 --- a/pkg/app/pipedv1/plugin/kubernetes/provider/deployment_test.go +++ b/pkg/app/pipedv1/plugin/kubernetes/provider/deployment_test.go @@ -527,6 +527,105 @@ spec: `, expected: []string{"gcr.io/pipecd/helloworld:v0.5.0", "gcr.io/pipecd/sidecar:v0.5.0"}, }, + { + name: "deployment with initContainers returns images from both containers and initContainers", + manifest: ` +apiVersion: apps/v1 +kind: Deployment +metadata: + name: with-init + labels: + app: with-init +spec: + replicas: 1 + selector: + matchLabels: + app: with-init + template: + metadata: + labels: + app: with-init + spec: + initContainers: + - name: init-migrator + image: gcr.io/pipecd/migrator:v1.0.0 + containers: + - name: app + image: gcr.io/pipecd/helloworld:v0.5.0 + ports: + - containerPort: 9085 +`, + expected: []string{"gcr.io/pipecd/helloworld:v0.5.0", "gcr.io/pipecd/migrator:v1.0.0"}, + }, + { + name: "cronjob returns images from spec.jobTemplate.spec.template.spec.containers", + manifest: ` +apiVersion: batch/v1 +kind: CronJob +metadata: + name: hello +spec: + schedule: "*/5 * * * *" + jobTemplate: + spec: + template: + spec: + containers: + - name: hello + image: gcr.io/pipecd/hello-job:v2.0.0 + restartPolicy: OnFailure +`, + expected: []string{"gcr.io/pipecd/hello-job:v2.0.0"}, + }, + { + name: "cronjob with initContainers returns images from all jobTemplate paths", + manifest: ` +apiVersion: batch/v1 +kind: CronJob +metadata: + name: hello-with-init +spec: + schedule: "0 * * * *" + jobTemplate: + spec: + template: + spec: + initContainers: + - name: init-job + image: gcr.io/pipecd/init-job:v1.1.0 + containers: + - name: main-job + image: gcr.io/pipecd/main-job:v1.2.0 + restartPolicy: OnFailure +`, + expected: []string{"gcr.io/pipecd/init-job:v1.1.0", "gcr.io/pipecd/main-job:v1.2.0"}, + }, + { + name: "duplicates across paths are deduplicated", + manifest: ` +apiVersion: apps/v1 +kind: Deployment +metadata: + name: dedup-test +spec: + replicas: 1 + selector: + matchLabels: + app: dedup-test + template: + metadata: + labels: + app: dedup-test + spec: + initContainers: + - name: init-a + image: gcr.io/pipecd/shared:v1.0.0 + containers: + - name: main + image: gcr.io/pipecd/shared:v1.0.0 +`, + expected: []string{"gcr.io/pipecd/shared:v1.0.0"}, + }, } for _, tc := range testcases {