@@ -74,7 +74,7 @@ type DebugOptions struct {
74
74
Image string
75
75
Interactive bool
76
76
Namespace string
77
- PodNames []string
77
+ TargetNames []string
78
78
PullPolicy corev1.PullPolicy
79
79
Quiet bool
80
80
Target string
@@ -89,9 +89,9 @@ type DebugOptions struct {
89
89
// NewDebugOptions returns a DebugOptions initialized with default values.
90
90
func NewDebugOptions (streams genericclioptions.IOStreams ) * DebugOptions {
91
91
return & DebugOptions {
92
- Args : []string {},
93
- IOStreams : streams ,
94
- PodNames : []string {},
92
+ Args : []string {},
93
+ IOStreams : streams ,
94
+ TargetNames : []string {},
95
95
}
96
96
}
97
97
@@ -139,10 +139,10 @@ func (o *DebugOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []st
139
139
140
140
// Arguments
141
141
argsLen := cmd .ArgsLenAtDash ()
142
- o .PodNames = args
142
+ o .TargetNames = args
143
143
// If there is a dash and there are args after the dash, extract the args.
144
144
if argsLen >= 0 && len (args ) > argsLen {
145
- o .PodNames , o .Args = args [:argsLen ], args [argsLen :]
145
+ o .TargetNames , o .Args = args [:argsLen ], args [argsLen :]
146
146
}
147
147
148
148
// Attach
@@ -187,7 +187,7 @@ func (o *DebugOptions) Validate(cmd *cobra.Command) error {
187
187
}
188
188
189
189
// Name
190
- if len (o .PodNames ) == 0 {
190
+ if len (o .TargetNames ) == 0 {
191
191
return fmt .Errorf ("NAME is required for debug" )
192
192
}
193
193
@@ -209,38 +209,35 @@ func (o *DebugOptions) Validate(cmd *cobra.Command) error {
209
209
210
210
// Run executes a kubectl debug.
211
211
func (o * DebugOptions ) Run (f cmdutil.Factory , cmd * cobra.Command ) error {
212
+ ctx := context .Background ()
213
+
212
214
r := o .builder .
213
215
WithScheme (scheme .Scheme , scheme .Scheme .PrioritizedVersionsAllGroups ()... ).
214
- NamespaceParam (o .Namespace ).DefaultNamespace ().ResourceNames ("pods" , o .PodNames ... ).
216
+ NamespaceParam (o .Namespace ).DefaultNamespace ().ResourceNames ("pods" , o .TargetNames ... ).
215
217
Do ()
216
218
if err := r .Err (); err != nil {
217
219
return err
218
220
}
219
221
220
- ctx := context .Background ()
221
222
err := r .Visit (func (info * resource.Info , err error ) error {
222
223
if err != nil {
223
224
// TODO(verb): configurable early return
224
225
return err
225
226
}
226
227
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 )
235
238
}
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
244
241
}
245
242
246
243
if o .Attach {
@@ -251,6 +248,7 @@ func (o *DebugOptions) Run(f cmdutil.Factory, cmd *cobra.Command) error {
251
248
TTY : o .TTY ,
252
249
Quiet : o .Quiet ,
253
250
},
251
+ // TODO(verb): kubectl prints an incorrect "Session ended" message for debug containers.
254
252
CommandName : cmd .Parent ().CommandPath () + " attach" ,
255
253
256
254
Attach : & attach.DefaultRemoteAttach {},
@@ -262,12 +260,7 @@ func (o *DebugOptions) Run(f cmdutil.Factory, cmd *cobra.Command) error {
262
260
opts .Config = config
263
261
opts .AttachFunc = attach .DefaultAttachFunc
264
262
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 {
271
264
return err
272
265
}
273
266
}
@@ -278,6 +271,33 @@ func (o *DebugOptions) Run(f cmdutil.Factory, cmd *cobra.Command) error {
278
271
return err
279
272
}
280
273
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
+
281
301
func containerNames (pod * corev1.Pod ) map [string ]bool {
282
302
names := map [string ]bool {}
283
303
for _ , c := range pod .Spec .Containers {
@@ -398,6 +418,7 @@ func waitForEphemeralContainer(ctx context.Context, podClient corev1client.PodsG
398
418
return result , err
399
419
}
400
420
421
+ // TODO(verb): handle other types of containers
401
422
func handleAttachPod (ctx context.Context , f cmdutil.Factory , podClient corev1client.PodsGetter , ns , podName , ephemeralContainerName string , opts * attach.AttachOptions ) error {
402
423
pod , err := waitForEphemeralContainer (ctx , podClient , ns , podName , ephemeralContainerName )
403
424
if err != nil {
0 commit comments