fix kubectl in interactive mode losing some line of logs

Signed-off-by: olalekan odukoya <odukoyaonline@gmail.com>

Kubernetes-commit: f338a70f252123aa0a01cb4d53087d88295b0d41
This commit is contained in:
olalekan odukoya 2026-01-03 01:38:00 +01:00 committed by Kubernetes Publisher
parent d4872b694a
commit dc1910f50a

View file

@ -18,6 +18,7 @@ package run
import (
"context"
"errors"
"fmt"
"time"
@ -26,7 +27,7 @@ import (
"k8s.io/klog/v2"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"
@ -474,7 +475,7 @@ func handleAttachPod(f cmdutil.Factory, podClient corev1client.PodsGetter, ns, n
}
if pod.Status.Phase == corev1.PodSucceeded || pod.Status.Phase == corev1.PodFailed {
return logOpts(f, pod, opts)
return logOpts(context.Background(), f, pod, opts, nil)
}
opts.Pod = pod
@ -485,26 +486,50 @@ func handleAttachPod(f cmdutil.Factory, podClient corev1client.PodsGetter, ns, n
opts.AttachFunc = attach.DefaultAttachFunc
}
// Fetch and display any logs that were printed before attach connects.
ctrName, err := opts.GetContainerName(pod)
if err == nil {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
if logErr := logOpts(ctx, f, pod, opts, &corev1.PodLogOptions{
Container: ctrName,
Follow: false,
}); logErr != nil {
if opts.ErrOut != nil {
//nolint:errcheck
fmt.Fprintf(opts.ErrOut, "warning: couldn't fetch pre-attach logs: %v\n", logErr)
}
}
cancel()
}
if err := opts.Run(); err != nil {
fmt.Fprintf(opts.ErrOut, "warning: couldn't attach to pod/%s, falling back to streaming logs: %v\n", name, err)
return logOpts(f, pod, opts)
return logOpts(context.Background(), f, pod, opts, nil)
}
return nil
}
// logOpts logs output from opts to the pods log.
func logOpts(restClientGetter genericclioptions.RESTClientGetter, pod *corev1.Pod, opts *attach.AttachOptions) error {
ctrName, err := opts.GetContainerName(pod)
if err != nil {
return err
func logOpts(ctx context.Context, restClientGetter genericclioptions.RESTClientGetter, pod *corev1.Pod, opts *attach.AttachOptions, podOpts *corev1.PodLogOptions) error {
if podOpts == nil {
ctrName, err := opts.GetContainerName(pod)
if err != nil {
return err
}
podOpts = &corev1.PodLogOptions{}
podOpts.Container = ctrName
}
requests, err := polymorphichelpers.LogsForObjectFn(restClientGetter, pod, &corev1.PodLogOptions{Container: ctrName}, opts.GetPodTimeout, false)
requests, err := polymorphichelpers.LogsForObjectFn(restClientGetter, pod, podOpts, opts.GetPodTimeout, false)
if err != nil {
return err
}
for _, request := range requests {
if err := logs.DefaultConsumeRequest(context.Background(), request, opts.Out); err != nil {
if err := logs.DefaultConsumeRequest(ctx, request, opts.Out); err != nil {
if podOpts != nil && podOpts.Follow && (errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded)) {
return nil
}
return err
}
}
@ -663,7 +688,7 @@ var ErrPodCompleted = fmt.Errorf("pod ran to completion")
func podCompleted(event watch.Event) (bool, error) {
switch event.Type {
case watch.Deleted:
return false, errors.NewNotFound(schema.GroupResource{Resource: "pods"}, "")
return false, apierrors.NewNotFound(schema.GroupResource{Resource: "pods"}, "")
}
switch t := event.Object.(type) {
case *corev1.Pod:
@ -680,7 +705,7 @@ func podCompleted(event watch.Event) (bool, error) {
func podSucceeded(event watch.Event) (bool, error) {
switch event.Type {
case watch.Deleted:
return false, errors.NewNotFound(schema.GroupResource{Resource: "pods"}, "")
return false, apierrors.NewNotFound(schema.GroupResource{Resource: "pods"}, "")
}
switch t := event.Object.(type) {
case *corev1.Pod:
@ -695,7 +720,7 @@ func podSucceeded(event watch.Event) (bool, error) {
func podRunningAndReady(event watch.Event) (bool, error) {
switch event.Type {
case watch.Deleted:
return false, errors.NewNotFound(schema.GroupResource{Resource: "pods"}, "")
return false, apierrors.NewNotFound(schema.GroupResource{Resource: "pods"}, "")
}
switch t := event.Object.(type) {
case *corev1.Pod: