Address feedback for new /ephemeralcontainers API

* Use deep copies in `PrepareForUpdate()`
* Preserve select metadata from new pod
* Use patch to add ephemeral container `kubectl debug`
* Distinguish between pod vs /ephemeralcontainers NotFound

Kubernetes-commit: 97726a50c138557522def7f753ec8581d00f0b02
This commit is contained in:
Lee Verberne 2021-04-14 18:40:42 +02:00 committed by Kubernetes Publisher
parent 7fd8647b0d
commit 46887fb25e
1 changed files with 26 additions and 7 deletions

View File

@ -18,6 +18,7 @@ package debug
import ( import (
"context" "context"
"encoding/json"
"fmt" "fmt"
"time" "time"
@ -31,7 +32,9 @@ import (
"k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
utilrand "k8s.io/apimachinery/pkg/util/rand" utilrand "k8s.io/apimachinery/pkg/util/rand"
"k8s.io/apimachinery/pkg/util/strategicpatch"
"k8s.io/apimachinery/pkg/watch" "k8s.io/apimachinery/pkg/watch"
"k8s.io/cli-runtime/pkg/genericclioptions" "k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/cli-runtime/pkg/resource" "k8s.io/cli-runtime/pkg/resource"
@ -381,20 +384,36 @@ func (o *DebugOptions) visitPod(ctx context.Context, pod *corev1.Pod) (*corev1.P
// debugByEphemeralContainer runs an EphemeralContainer in the target Pod for use as a debug container // debugByEphemeralContainer runs an EphemeralContainer in the target Pod for use as a debug container
func (o *DebugOptions) debugByEphemeralContainer(ctx context.Context, pod *corev1.Pod) (*corev1.Pod, string, error) { func (o *DebugOptions) debugByEphemeralContainer(ctx context.Context, pod *corev1.Pod) (*corev1.Pod, string, error) {
pods := o.podClient.Pods(pod.Namespace)
klog.V(2).Infof("existing ephemeral containers: %v", pod.Spec.EphemeralContainers) klog.V(2).Infof("existing ephemeral containers: %v", pod.Spec.EphemeralContainers)
podJS, err := json.Marshal(pod)
if err != nil {
return nil, "", fmt.Errorf("error creating JSON for pod: %v", err)
}
debugContainer := o.generateDebugContainer(pod) debugContainer := o.generateDebugContainer(pod)
klog.V(2).Infof("new ephemeral container: %#v", debugContainer) klog.V(2).Infof("new ephemeral container: %#v", debugContainer)
debugPod := pod.DeepCopy()
pod.Spec.EphemeralContainers = append(pod.Spec.EphemeralContainers, *debugContainer) debugPod.Spec.EphemeralContainers = append(debugPod.Spec.EphemeralContainers, *debugContainer)
result, err := pods.UpdateEphemeralContainers(ctx, pod.Name, pod, metav1.UpdateOptions{}) debugJS, err := json.Marshal(debugPod)
if err != nil { if err != nil {
// The pod has already been fetched at this point, so a NotFound error indicates the ephemeralcontainers subresource wasn't found. return nil, "", fmt.Errorf("error creating JSON for debug container: %v", err)
if serr, ok := err.(*errors.StatusError); ok && serr.Status().Reason == metav1.StatusReasonNotFound { }
patch, err := strategicpatch.CreateTwoWayMergePatch(podJS, debugJS, pod)
if err != nil {
return nil, "", fmt.Errorf("error creating patch to add debug container: %v", err)
}
klog.V(2).Infof("generated strategic merge patch for debug container: %s", patch)
pods := o.podClient.Pods(pod.Namespace)
result, err := pods.Patch(ctx, pod.Name, types.StrategicMergePatchType, patch, metav1.PatchOptions{}, "ephemeralcontainers")
if err != nil {
// The apiserver will return a 404 when the EphemeralContainers feature is disabled because the `/ephemeralcontainers` subresource
// is missing. Unlike the 404 returned by a missing pod, the status details will be empty.
if serr, ok := err.(*errors.StatusError); ok && serr.Status().Reason == metav1.StatusReasonNotFound && serr.ErrStatus.Details.Name == "" {
return nil, "", fmt.Errorf("ephemeral containers are disabled for this cluster (error from server: %q).", err) return nil, "", fmt.Errorf("ephemeral containers are disabled for this cluster (error from server: %q).", err)
} }
return nil, "", fmt.Errorf("error updating ephemeral containers: %v", err) return nil, "", err
} }
return result, debugContainer.Name, nil return result, debugContainer.Name, nil