Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 61 additions & 28 deletions pkg/pod/entrypoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,45 @@ func init() {
}
}

// buildSidecarStopPatch creates a JSON Patch to replace sidecar container images with nop image
func buildSidecarStopPatch(pod *corev1.Pod, nopImage string, ctx context.Context) ([]byte, error) {
var patchOps []jsonpatch.JsonPatchOperation

for i, c := range pod.Spec.Containers {
// Check if this container is a sidecar that needs to be stopped
shouldStop := false
for _, s := range pod.Status.ContainerStatuses {
// If the results-from is set to sidecar logs,
// a sidecar container with name `sidecar-log-results` is injected by the reconciler.
// Do not kill this sidecar. Let it exit gracefully.
if config.FromContextOrDefaults(ctx).FeatureFlags.ResultExtractionMethod == config.ResultExtractionMethodSidecarLogs && s.Name == pipeline.ReservedResultsSidecarContainerName {
continue
}
// Stop any running container that isn't a step.
// An injected sidecar container might not have the
// "sidecar-" prefix, so we can't just look for that prefix.
if !IsContainerStep(s.Name) && s.State.Running != nil && c.Name == s.Name && c.Image != nopImage {
shouldStop = true
break
}
}

if shouldStop {
patchOps = append(patchOps, jsonpatch.JsonPatchOperation{
Operation: "replace",
Path: fmt.Sprintf("/spec/containers/%d/image", i),
Value: nopImage,
})
}
}

if len(patchOps) == 0 {
return nil, nil
}

return json.Marshal(patchOps)
}

// CancelPod cancels the pod
func CancelPod(ctx context.Context, kubeClient kubernetes.Interface, namespace, podName string) error {
// PATCH the Pod's annotations to replace the cancel annotation with the
Expand All @@ -296,43 +335,37 @@ func UpdateReady(ctx context.Context, kubeclient kubernetes.Interface, pod corev
// StopSidecars updates sidecar containers in the Pod to a nop image, which
// exits successfully immediately.
func StopSidecars(ctx context.Context, nopImage string, kubeclient kubernetes.Interface, namespace, name string) (*corev1.Pod, error) {
newPod, err := kubeclient.CoreV1().Pods(namespace).Get(ctx, name, metav1.GetOptions{})
pod, err := kubeclient.CoreV1().Pods(namespace).Get(ctx, name, metav1.GetOptions{})
if k8serrors.IsNotFound(err) {
// return NotFound as-is, since the K8s error checks don't handle wrapping.
return nil, err
} else if err != nil {
return nil, fmt.Errorf("error getting Pod %q when stopping sidecars: %w", name, err)
}

updated := false
if newPod.Status.Phase == corev1.PodRunning {
for _, s := range newPod.Status.ContainerStatuses {
// If the results-from is set to sidecar logs,
// a sidecar container with name `sidecar-log-results` is injected by the reconiler.
// Do not kill this sidecar. Let it exit gracefully.
if config.FromContextOrDefaults(ctx).FeatureFlags.ResultExtractionMethod == config.ResultExtractionMethodSidecarLogs && s.Name == pipeline.ReservedResultsSidecarContainerName {
continue
}
// Stop any running container that isn't a step.
// An injected sidecar container might not have the
// "sidecar-" prefix, so we can't just look for that
// prefix.
if !IsContainerStep(s.Name) && s.State.Running != nil {
for j, c := range newPod.Spec.Containers {
if c.Name == s.Name && c.Image != nopImage {
updated = true
newPod.Spec.Containers[j].Image = nopImage
}
}
}
}
// Only attempt to stop sidecars if pod is running
if pod.Status.Phase != corev1.PodRunning {
return pod, nil
}
if updated {
if newPod, err = kubeclient.CoreV1().Pods(newPod.Namespace).Update(ctx, newPod, metav1.UpdateOptions{}); err != nil {
return nil, fmt.Errorf("error stopping sidecars of Pod %q: %w", name, err)
}

// Build JSON Patch operations to replace sidecar images
patchBytes, err := buildSidecarStopPatch(pod, nopImage, ctx)
if err != nil {
return nil, fmt.Errorf("error building patch for stopping sidecars of Pod %q: %w", name, err)
}

// If no sidecars need to be stopped, return early
if patchBytes == nil {
return pod, nil
}
return newPod, nil

// PATCH the Pod's container images to stop sidecars, using the same pattern as UpdateReady and CancelPod
patchedPod, err := kubeclient.CoreV1().Pods(namespace).Patch(ctx, name, types.JSONPatchType, patchBytes, metav1.PatchOptions{})
if err != nil {
return nil, fmt.Errorf("error stopping sidecars of Pod %q: %w", name, err)
}

return patchedPod, nil
}

// IsSidecarStatusRunning determines if any SidecarStatus on a TaskRun
Expand Down