Skip to content

Commit 495b0dd

Browse files
authored
Merge pull request kubernetes#89818 from verb/cli-debug-typed
kubectl debug: support different kinds
2 parents 69e9c6b + 8414d18 commit 495b0dd

File tree

1 file changed

+52
-31
lines changed
  • staging/src/k8s.io/kubectl/pkg/cmd/debug

1 file changed

+52
-31
lines changed

staging/src/k8s.io/kubectl/pkg/cmd/debug/debug.go

Lines changed: 52 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ type DebugOptions struct {
7474
Image string
7575
Interactive bool
7676
Namespace string
77-
PodNames []string
77+
TargetNames []string
7878
PullPolicy corev1.PullPolicy
7979
Quiet bool
8080
Target string
@@ -89,9 +89,9 @@ type DebugOptions struct {
8989
// NewDebugOptions returns a DebugOptions initialized with default values.
9090
func NewDebugOptions(streams genericclioptions.IOStreams) *DebugOptions {
9191
return &DebugOptions{
92-
Args: []string{},
93-
IOStreams: streams,
94-
PodNames: []string{},
92+
Args: []string{},
93+
IOStreams: streams,
94+
TargetNames: []string{},
9595
}
9696
}
9797

@@ -139,10 +139,10 @@ func (o *DebugOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []st
139139

140140
// Arguments
141141
argsLen := cmd.ArgsLenAtDash()
142-
o.PodNames = args
142+
o.TargetNames = args
143143
// If there is a dash and there are args after the dash, extract the args.
144144
if argsLen >= 0 && len(args) > argsLen {
145-
o.PodNames, o.Args = args[:argsLen], args[argsLen:]
145+
o.TargetNames, o.Args = args[:argsLen], args[argsLen:]
146146
}
147147

148148
// Attach
@@ -187,7 +187,7 @@ func (o *DebugOptions) Validate(cmd *cobra.Command) error {
187187
}
188188

189189
// Name
190-
if len(o.PodNames) == 0 {
190+
if len(o.TargetNames) == 0 {
191191
return fmt.Errorf("NAME is required for debug")
192192
}
193193

@@ -209,38 +209,35 @@ func (o *DebugOptions) Validate(cmd *cobra.Command) error {
209209

210210
// Run executes a kubectl debug.
211211
func (o *DebugOptions) Run(f cmdutil.Factory, cmd *cobra.Command) error {
212+
ctx := context.Background()
213+
212214
r := o.builder.
213215
WithScheme(scheme.Scheme, scheme.Scheme.PrioritizedVersionsAllGroups()...).
214-
NamespaceParam(o.Namespace).DefaultNamespace().ResourceNames("pods", o.PodNames...).
216+
NamespaceParam(o.Namespace).DefaultNamespace().ResourceNames("pods", o.TargetNames...).
215217
Do()
216218
if err := r.Err(); err != nil {
217219
return err
218220
}
219221

220-
ctx := context.Background()
221222
err := r.Visit(func(info *resource.Info, err error) error {
222223
if err != nil {
223224
// TODO(verb): configurable early return
224225
return err
225226
}
226227

227-
pods := o.podClient.Pods(info.Namespace)
228-
ec, err := pods.GetEphemeralContainers(ctx, info.Name, metav1.GetOptions{})
229-
if err != nil {
230-
// The pod has already been fetched at this point, so a NotFound error indicates the ephemeralcontainers subresource wasn't found.
231-
if serr, ok := err.(*errors.StatusError); ok && serr.Status().Reason == metav1.StatusReasonNotFound {
232-
return fmt.Errorf("ephemeral containers are disabled for this cluster (error from server: %q).", err)
233-
}
234-
return err
228+
var (
229+
debugPod *corev1.Pod
230+
containerName string
231+
visitErr error
232+
)
233+
switch obj := info.Object.(type) {
234+
case *corev1.Pod:
235+
debugPod, containerName, visitErr = o.visitPod(ctx, obj)
236+
default:
237+
visitErr = fmt.Errorf("%q not supported by debug", info.Mapping.GroupVersionKind)
235238
}
236-
klog.V(2).Infof("existing ephemeral containers: %v", ec.EphemeralContainers)
237-
238-
debugContainer := o.generateDebugContainer(info.Object.(*corev1.Pod))
239-
klog.V(2).Infof("new ephemeral container: %#v", debugContainer)
240-
ec.EphemeralContainers = append(ec.EphemeralContainers, *debugContainer)
241-
_, err = pods.UpdateEphemeralContainers(ctx, info.Name, ec, metav1.UpdateOptions{})
242-
if err != nil {
243-
return fmt.Errorf("error updating ephemeral containers: %v", err)
239+
if visitErr != nil {
240+
return visitErr
244241
}
245242

246243
if o.Attach {
@@ -251,6 +248,7 @@ func (o *DebugOptions) Run(f cmdutil.Factory, cmd *cobra.Command) error {
251248
TTY: o.TTY,
252249
Quiet: o.Quiet,
253250
},
251+
// TODO(verb): kubectl prints an incorrect "Session ended" message for debug containers.
254252
CommandName: cmd.Parent().CommandPath() + " attach",
255253

256254
Attach: &attach.DefaultRemoteAttach{},
@@ -262,12 +260,7 @@ func (o *DebugOptions) Run(f cmdutil.Factory, cmd *cobra.Command) error {
262260
opts.Config = config
263261
opts.AttachFunc = attach.DefaultAttachFunc
264262

265-
attachablePod, err := polymorphichelpers.AttachablePodForObjectFn(f, info.Object, opts.GetPodTimeout)
266-
if err != nil {
267-
return err
268-
}
269-
err = handleAttachPod(ctx, f, o.podClient, attachablePod.Namespace, attachablePod.Name, debugContainer.Name, opts)
270-
if err != nil {
263+
if err := handleAttachPod(ctx, f, o.podClient, debugPod.Namespace, debugPod.Name, containerName, opts); err != nil {
271264
return err
272265
}
273266
}
@@ -278,6 +271,33 @@ func (o *DebugOptions) Run(f cmdutil.Factory, cmd *cobra.Command) error {
278271
return err
279272
}
280273

274+
// visitPod handles debugging for pod targets by (depending on options):
275+
// 1. Creating an ephemeral debug container in an existing pod, OR
276+
// 2. Making a copy of pod with certain attributes changed (NOT YET IMPLEMENTED)
277+
// visitPod returns a pod and debug container name for subsequent attach, if applicable.
278+
func (o *DebugOptions) visitPod(ctx context.Context, pod *corev1.Pod) (*corev1.Pod, string, error) {
279+
pods := o.podClient.Pods(pod.Namespace)
280+
ec, err := pods.GetEphemeralContainers(ctx, pod.Name, metav1.GetOptions{})
281+
if err != nil {
282+
// The pod has already been fetched at this point, so a NotFound error indicates the ephemeralcontainers subresource wasn't found.
283+
if serr, ok := err.(*errors.StatusError); ok && serr.Status().Reason == metav1.StatusReasonNotFound {
284+
return nil, "", fmt.Errorf("ephemeral containers are disabled for this cluster (error from server: %q).", err)
285+
}
286+
return nil, "", err
287+
}
288+
klog.V(2).Infof("existing ephemeral containers: %v", ec.EphemeralContainers)
289+
290+
debugContainer := o.generateDebugContainer(pod)
291+
klog.V(2).Infof("new ephemeral container: %#v", debugContainer)
292+
ec.EphemeralContainers = append(ec.EphemeralContainers, *debugContainer)
293+
_, err = pods.UpdateEphemeralContainers(ctx, pod.Name, ec, metav1.UpdateOptions{})
294+
if err != nil {
295+
return nil, "", fmt.Errorf("error updating ephemeral containers: %v", err)
296+
}
297+
298+
return pod, debugContainer.Name, nil
299+
}
300+
281301
func containerNames(pod *corev1.Pod) map[string]bool {
282302
names := map[string]bool{}
283303
for _, c := range pod.Spec.Containers {
@@ -398,6 +418,7 @@ func waitForEphemeralContainer(ctx context.Context, podClient corev1client.PodsG
398418
return result, err
399419
}
400420

421+
// TODO(verb): handle other types of containers
401422
func handleAttachPod(ctx context.Context, f cmdutil.Factory, podClient corev1client.PodsGetter, ns, podName, ephemeralContainerName string, opts *attach.AttachOptions) error {
402423
pod, err := waitForEphemeralContainer(ctx, podClient, ns, podName, ephemeralContainerName)
403424
if err != nil {

0 commit comments

Comments
 (0)