Skip to content

Commit a243842

Browse files
authored
hotfix: fix port-forward retry bug (#366)
1 parent 6e052a5 commit a243842

File tree

2 files changed

+42
-44
lines changed

2 files changed

+42
-44
lines changed

pkg/handler/connect.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ func (c *ConnectOptions) portForward(ctx context.Context, portPair []string) err
276276
var readyChan = make(chan struct{})
277277
podName := podList[0].GetName()
278278
// try to detect pod is delete event, if pod is deleted, needs to redo port-forward
279-
//go util.CheckPodStatus(childCtx, cancelFunc, podName, c.clientset.CoreV1().Pods(c.Namespace))
279+
go util.CheckPodStatus(childCtx, cancelFunc, podName, c.clientset.CoreV1().Pods(c.Namespace))
280280
go util.CheckPortStatus(childCtx, cancelFunc, readyChan, strings.Split(portPair[1], ":")[0])
281281
if *first {
282282
go func() {

pkg/util/pod.go

+41-43
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,12 @@ import (
1818
"github.com/pkg/errors"
1919
log "github.com/sirupsen/logrus"
2020
corev1 "k8s.io/api/core/v1"
21-
k8serrors "k8s.io/apimachinery/pkg/api/errors"
2221
"k8s.io/apimachinery/pkg/apis/meta/v1"
2322
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2423
"k8s.io/apimachinery/pkg/fields"
2524
"k8s.io/apimachinery/pkg/runtime/schema"
2625
"k8s.io/apimachinery/pkg/util/httpstream"
2726
"k8s.io/apimachinery/pkg/util/sets"
28-
"k8s.io/apimachinery/pkg/util/wait"
2927
"k8s.io/apimachinery/pkg/watch"
3028
"k8s.io/cli-runtime/pkg/genericiooptions"
3129
"k8s.io/cli-runtime/pkg/resource"
@@ -171,11 +169,20 @@ func PortForwardPod(config *rest.Config, clientset *rest.RESTClient, podName, na
171169
return err
172170
}
173171

174-
if err = forwarder.ForwardPorts(); err != nil {
175-
log.Debugf("Forward port error: %s", err.Error())
172+
defer forwarder.Close()
173+
174+
var errChan = make(chan error, 1)
175+
go func() {
176+
errChan <- forwarder.ForwardPorts()
177+
}()
178+
179+
select {
180+
case err = <-errChan:
181+
log.Debugf("Forward port error: %v", err)
176182
return err
183+
case <-stopChan:
184+
return nil
177185
}
178-
return nil
179186
}
180187

181188
func GetTopOwnerReference(factory util.Factory, ns, workload string) (*resource.Info, error) {
@@ -330,36 +337,42 @@ func FindContainerByName(pod *corev1.Pod, name string) (*corev1.Container, int)
330337
}
331338

332339
func CheckPodStatus(ctx context.Context, cancelFunc context.CancelFunc, podName string, podInterface v12.PodInterface) {
340+
var verifyAPIServerConnection = func() {
341+
err := retry.OnError(
342+
retry.DefaultBackoff,
343+
func(err error) bool {
344+
return err != nil
345+
},
346+
func() error {
347+
ctx1, cancelFunc1 := context.WithTimeout(ctx, time.Second*10)
348+
defer cancelFunc1()
349+
_, err := podInterface.Get(ctx1, podName, v1.GetOptions{})
350+
return err
351+
})
352+
if err != nil {
353+
log.Debugf("Failed to get Pod %s: %v", podName, err)
354+
cancelFunc()
355+
}
356+
}
357+
333358
for ctx.Err() == nil {
334359
func() {
335-
defer time.Sleep(time.Millisecond * 200)
360+
defer time.Sleep(time.Second * 5)
336361

337362
w, err := podInterface.Watch(ctx, v1.ListOptions{
338363
FieldSelector: fields.OneTermEqualSelector("metadata.name", podName).String(),
339364
})
340365
if err != nil {
341-
if !k8serrors.IsForbidden(err) && !errors.Is(err, context.Canceled) {
342-
log.Debugf("Failed to watch Pod %s: %v", podName, err)
343-
}
366+
log.Debugf("Failed to watch Pod %s: %v", podName, err)
344367
return
345368
}
346369
defer w.Stop()
347370

348-
_, err = podInterface.Get(ctx, podName, v1.GetOptions{})
349-
if err != nil {
350-
if !k8serrors.IsForbidden(err) && !errors.Is(err, context.Canceled) {
351-
log.Debugf("Failed to get Pod %s: %v", podName, err)
352-
}
353-
return
354-
}
371+
verifyAPIServerConnection()
355372
select {
356373
case e, ok := <-w.ResultChan():
357374
if !ok {
358-
_, err = podInterface.Get(ctx, podName, v1.GetOptions{})
359-
if err != nil && !errors.Is(err, context.Canceled) {
360-
log.Debugf("Failed to get Pod %s: %v", podName, err)
361-
cancelFunc()
362-
}
375+
verifyAPIServerConnection()
363376
return
364377
}
365378
switch e.Type {
@@ -368,11 +381,7 @@ func CheckPodStatus(ctx context.Context, cancelFunc context.CancelFunc, podName
368381
cancelFunc()
369382
return
370383
case watch.Error:
371-
_, err = podInterface.Get(ctx, podName, v1.GetOptions{})
372-
if err != nil && !errors.Is(err, context.Canceled) {
373-
log.Debugf("Failed to get Pod %s: %v", podName, err)
374-
cancelFunc()
375-
}
384+
verifyAPIServerConnection()
376385
return
377386
case watch.Added, watch.Modified, watch.Bookmark:
378387
// do nothing
@@ -397,25 +406,14 @@ func CheckPortStatus(ctx context.Context, cancelFunc context.CancelFunc, readyCh
397406
}
398407

399408
for ctx.Err() == nil {
400-
err := retry.OnError(wait.Backoff{
401-
Steps: 6,
402-
Duration: time.Second,
403-
}, func(err error) bool {
404-
return err != nil
405-
}, func() error {
406-
var lc net.ListenConfig
407-
conn, err := lc.Listen(ctx, "tcp", net.JoinHostPort("127.0.0.1", localGvisorTCPPort))
408-
if err == nil {
409-
_ = conn.Close()
410-
return errors.New("port is free")
411-
}
412-
return nil
413-
})
414-
if err != nil {
415-
log.Debugf("Can not dial local port: %s: %v", localGvisorTCPPort, err)
409+
var lc net.ListenConfig
410+
conn, err := lc.Listen(ctx, "tcp", net.JoinHostPort("127.0.0.1", localGvisorTCPPort))
411+
if err == nil {
412+
_ = conn.Close()
413+
log.Debugf("Local port: %s is free", localGvisorTCPPort)
416414
return
417415
}
418-
time.Sleep(time.Second * 5)
416+
time.Sleep(time.Second * 1)
419417
}
420418
}
421419

0 commit comments

Comments
 (0)