diff --git a/staging/src/k8s.io/kubectl/pkg/cmd/debug/debug.go b/staging/src/k8s.io/kubectl/pkg/cmd/debug/debug.go index 4928d1c2324..6a473180c35 100644 --- a/staging/src/k8s.io/kubectl/pkg/cmd/debug/debug.go +++ b/staging/src/k8s.io/kubectl/pkg/cmd/debug/debug.go @@ -77,6 +77,10 @@ var ( # Create an interactive debugging session in pod mypod and immediately attach to it. kubectl debug mypod -it --image=busybox + # Create an interactive debugging session for the pod in the file pod.yaml and immediately attach to it. + # (requires the EphemeralContainers feature to be enabled in the cluster) + kubectl debug -f pod.yaml -it --image=busybox + # Create a debug container named debugger using a custom automated debugging image. kubectl debug --image=myproj/debug-tools -c debugger mypod @@ -123,6 +127,7 @@ type DebugOptions struct { Profile string Applier ProfileApplier + explicitNamespace bool attachChanged bool shareProcessedChanged bool @@ -130,6 +135,8 @@ type DebugOptions struct { genericclioptions.IOStreams WarningPrinter *printers.WarningPrinter + + resource.FilenameOptions } // NewDebugOptions returns a DebugOptions initialized with default values. @@ -160,6 +167,7 @@ func NewCmdDebug(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra. } addDebugFlags(cmd, o) + cmdutil.AddJsonFilenameFlag(cmd.Flags(), &o.FilenameOptions.Filenames, "identifying the resource to debug") return cmd } @@ -212,7 +220,7 @@ func (o *DebugOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []st } // Namespace - o.Namespace, _, err = f.ToRawKubeConfigLoader().Namespace() + o.Namespace, o.explicitNamespace, err = f.ToRawKubeConfigLoader().Namespace() if err != nil { return err } @@ -272,8 +280,8 @@ func (o *DebugOptions) Validate() error { } // Name - if len(o.TargetNames) == 0 { - return fmt.Errorf("NAME is required for debug") + if len(o.TargetNames) == 0 && len(o.FilenameOptions.Filenames) == 0 { + return fmt.Errorf("NAME or filename is required for debug") } // Pull Policy @@ -327,6 +335,7 @@ func (o *DebugOptions) Run(f cmdutil.Factory, cmd *cobra.Command) error { r := f.NewBuilder(). WithScheme(scheme.Scheme, scheme.Scheme.PrioritizedVersionsAllGroups()...). + FilenameParam(o.explicitNamespace, &o.FilenameOptions). NamespaceParam(o.Namespace).DefaultNamespace().ResourceNames("pods", o.TargetNames...). Do() if err := r.Err(); err != nil { @@ -691,18 +700,15 @@ func (o *DebugOptions) computeDebugContainerName(pod *corev1.Pod) string { if len(o.Container) > 0 { return o.Container } - name := o.Container - if len(name) == 0 { - cn, containerByName := "", containerNameToRef(pod) - for len(cn) == 0 || (containerByName[cn] != nil) { - cn = fmt.Sprintf("debugger-%s", nameSuffixFunc(5)) - } - if !o.Quiet { - fmt.Fprintf(o.Out, "Defaulting debug container name to %s.\n", cn) - } - name = cn + + cn, containerByName := "", containerNameToRef(pod) + for len(cn) == 0 || (containerByName[cn] != nil) { + cn = fmt.Sprintf("debugger-%s", nameSuffixFunc(5)) } - return name + if !o.Quiet { + fmt.Fprintf(o.Out, "Defaulting debug container name to %s.\n", cn) + } + return cn } func containerNameToRef(pod *corev1.Pod) map[string]*corev1.Container { diff --git a/test/cmd/debug.sh b/test/cmd/debug.sh index 61300603784..5efbdc8efdc 100755 --- a/test/cmd/debug.sh +++ b/test/cmd/debug.sh @@ -25,6 +25,18 @@ run_kubectl_debug_pod_tests() { create_and_use_new_namespace kube::log::status "Testing kubectl debug (pod tests)" + ### Pod Troubleshooting by ephemeral containers + + # Pre-Condition: Pod "nginx" is created + kubectl run target "--image=${IMAGE_NGINX:?}" "${kube_flags[@]:?}" + kube::test::get_object_assert pod "{{range.items}}{{${id_field:?}}}:{{end}}" 'target:' + # Command: create a copy of target with a new debug container + kubectl debug target -it --image=busybox --attach=false -c debug-container "${kube_flags[@]:?}" + # Post-Conditions + kube::test::get_object_assert pod/target '{{range.spec.ephemeralContainers}}{{.name}}:{{end}}' 'debug-container:' + # Clean up + kubectl delete pod target "${kube_flags[@]:?}" + ### Pod Troubleshooting by Copy # Pre-Condition: Pod "nginx" is created @@ -63,6 +75,19 @@ run_kubectl_debug_pod_tests() { # Clean up kubectl delete pod target target-copy "${kube_flags[@]:?}" + # Pre-Condition: Pod "nginx" is created + kubectl run target "--image=${IMAGE_NGINX:?}" "${kube_flags[@]:?}" + kube::test::get_object_assert pod "{{range.items}}{{${id_field:?}}}:{{end}}" 'target:' + kube::test::get_object_assert pod/target '{{(index .spec.containers 0).name}}' 'target' + # Command: copy the pod and replace the image of an existing container + kubectl get pod/target -o yaml > "${KUBE_TEMP}"/test-pod-debug.yaml + kubectl debug -f "${KUBE_TEMP}"/test-pod-debug.yaml --image=busybox --container=target --copy-to=target-copy "${kube_flags[@]:?}" -- sleep 1m + # Post-Conditions + kube::test::get_object_assert pod "{{range.items}}{{${id_field:?}}}:{{end}}" 'target:target-copy:' + kube::test::get_object_assert pod/target-copy "{{(len .spec.containers)}}:{{${image_field:?}}}" '1:busybox' + # Clean up + kubectl delete pod target target-copy "${kube_flags[@]:?}" + set +o nounset set +o errexit }