@@ -271,6 +271,45 @@ func init() {
271271 }
272272}
273273
274+ // buildSidecarStopPatch creates a JSON Patch to replace sidecar container images with nop image
275+ func buildSidecarStopPatch (pod * corev1.Pod , nopImage string , ctx context.Context ) ([]byte , error ) {
276+ var patchOps []jsonpatch.JsonPatchOperation
277+
278+ for i , c := range pod .Spec .Containers {
279+ // Check if this container is a sidecar that needs to be stopped
280+ shouldStop := false
281+ for _ , s := range pod .Status .ContainerStatuses {
282+ // If the results-from is set to sidecar logs,
283+ // a sidecar container with name `sidecar-log-results` is injected by the reconciler.
284+ // Do not kill this sidecar. Let it exit gracefully.
285+ if config .FromContextOrDefaults (ctx ).FeatureFlags .ResultExtractionMethod == config .ResultExtractionMethodSidecarLogs && s .Name == pipeline .ReservedResultsSidecarContainerName {
286+ continue
287+ }
288+ // Stop any running container that isn't a step.
289+ // An injected sidecar container might not have the
290+ // "sidecar-" prefix, so we can't just look for that prefix.
291+ if ! IsContainerStep (s .Name ) && s .State .Running != nil && c .Name == s .Name && c .Image != nopImage {
292+ shouldStop = true
293+ break
294+ }
295+ }
296+
297+ if shouldStop {
298+ patchOps = append (patchOps , jsonpatch.JsonPatchOperation {
299+ Operation : "replace" ,
300+ Path : fmt .Sprintf ("/spec/containers/%d/image" , i ),
301+ Value : nopImage ,
302+ })
303+ }
304+ }
305+
306+ if len (patchOps ) == 0 {
307+ return nil , nil
308+ }
309+
310+ return json .Marshal (patchOps )
311+ }
312+
274313// CancelPod cancels the pod
275314func CancelPod (ctx context.Context , kubeClient kubernetes.Interface , namespace , podName string ) error {
276315 // PATCH the Pod's annotations to replace the cancel annotation with the
@@ -296,43 +335,37 @@ func UpdateReady(ctx context.Context, kubeclient kubernetes.Interface, pod corev
296335// StopSidecars updates sidecar containers in the Pod to a nop image, which
297336// exits successfully immediately.
298337func StopSidecars (ctx context.Context , nopImage string , kubeclient kubernetes.Interface , namespace , name string ) (* corev1.Pod , error ) {
299- newPod , err := kubeclient .CoreV1 ().Pods (namespace ).Get (ctx , name , metav1.GetOptions {})
338+ pod , err := kubeclient .CoreV1 ().Pods (namespace ).Get (ctx , name , metav1.GetOptions {})
300339 if k8serrors .IsNotFound (err ) {
301340 // return NotFound as-is, since the K8s error checks don't handle wrapping.
302341 return nil , err
303342 } else if err != nil {
304343 return nil , fmt .Errorf ("error getting Pod %q when stopping sidecars: %w" , name , err )
305344 }
306345
307- updated := false
308- if newPod .Status .Phase == corev1 .PodRunning {
309- for _ , s := range newPod .Status .ContainerStatuses {
310- // If the results-from is set to sidecar logs,
311- // a sidecar container with name `sidecar-log-results` is injected by the reconiler.
312- // Do not kill this sidecar. Let it exit gracefully.
313- if config .FromContextOrDefaults (ctx ).FeatureFlags .ResultExtractionMethod == config .ResultExtractionMethodSidecarLogs && s .Name == pipeline .ReservedResultsSidecarContainerName {
314- continue
315- }
316- // Stop any running container that isn't a step.
317- // An injected sidecar container might not have the
318- // "sidecar-" prefix, so we can't just look for that
319- // prefix.
320- if ! IsContainerStep (s .Name ) && s .State .Running != nil {
321- for j , c := range newPod .Spec .Containers {
322- if c .Name == s .Name && c .Image != nopImage {
323- updated = true
324- newPod .Spec .Containers [j ].Image = nopImage
325- }
326- }
327- }
328- }
346+ // Only attempt to stop sidecars if pod is running
347+ if pod .Status .Phase != corev1 .PodRunning {
348+ return pod , nil
329349 }
330- if updated {
331- if newPod , err = kubeclient .CoreV1 ().Pods (newPod .Namespace ).Update (ctx , newPod , metav1.UpdateOptions {}); err != nil {
332- return nil , fmt .Errorf ("error stopping sidecars of Pod %q: %w" , name , err )
333- }
350+
351+ // Build JSON Patch operations to replace sidecar images
352+ patchBytes , err := buildSidecarStopPatch (pod , nopImage , ctx )
353+ if err != nil {
354+ return nil , fmt .Errorf ("error building patch for stopping sidecars of Pod %q: %w" , name , err )
355+ }
356+
357+ // If no sidecars need to be stopped, return early
358+ if patchBytes == nil {
359+ return pod , nil
334360 }
335- return newPod , nil
361+
362+ // PATCH the Pod's container images to stop sidecars, using the same pattern as UpdateReady and CancelPod
363+ patchedPod , err := kubeclient .CoreV1 ().Pods (namespace ).Patch (ctx , name , types .JSONPatchType , patchBytes , metav1.PatchOptions {})
364+ if err != nil {
365+ return nil , fmt .Errorf ("error stopping sidecars of Pod %q: %w" , name , err )
366+ }
367+
368+ return patchedPod , nil
336369}
337370
338371// IsSidecarStatusRunning determines if any SidecarStatus on a TaskRun
0 commit comments