Skip to content

Commit 434ad9a

Browse files
committed
Use patch instead of update to replace sidecars with nop image
1 parent c3c6299 commit 434ad9a

File tree

1 file changed

+61
-28
lines changed

1 file changed

+61
-28
lines changed

pkg/pod/entrypoint.go

Lines changed: 61 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -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
275314
func 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.
298337
func 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

Comments
 (0)