@@ -16,6 +16,7 @@ import (
16
16
17
17
corev1 "k8s.io/api/core/v1"
18
18
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
19
+ "k8s.io/apimachinery/pkg/util/httpstream"
19
20
"k8s.io/client-go/kubernetes"
20
21
"k8s.io/client-go/rest"
21
22
"k8s.io/client-go/tools/portforward"
@@ -456,12 +457,10 @@ func (tunnel *Tunnel) establish(ctx context.Context) (string, error) {
456
457
457
458
l .Debug ("using URL to create portforward" , "url" , portForwardCreateURL )
458
459
459
- // Construct the spdy client required by the client-go portforward library.
460
- transport , upgrader , err := spdy .RoundTripperFor (tunnel .restConfig )
460
+ dialer , err := createDialer ("POST" , portForwardCreateURL , tunnel .restConfig )
461
461
if err != nil {
462
- return "" , fmt .Errorf ("unable to create the spdy client %w" , err )
462
+ return "" , fmt .Errorf ("unable to create the dialer %w" , err )
463
463
}
464
- dialer := spdy .NewDialer (upgrader , & http.Client {Transport : transport }, "POST" , portForwardCreateURL )
465
464
466
465
// Construct a new PortForwarder struct that manages the instructed port forward tunnel.
467
466
ports := []string {fmt .Sprintf ("%d:%d" , localPort , tunnel .remotePort )}
@@ -530,3 +529,21 @@ func (tunnel *Tunnel) getAttachablePodForService(ctx context.Context) (string, e
530
529
}
531
530
return podList .Items [0 ].Name , nil
532
531
}
532
+
533
+ // Inspired by https://github.com/kubernetes/kubernetes/blob/680ea07dbb2c6050d13b93660fa4d27d2d28d6eb/staging/src/k8s.io/kubectl/pkg/cmd/portforward/portforward.go#L139-L156
534
+ func createDialer (method string , url * url.URL , config * rest.Config ) (httpstream.Dialer , error ) {
535
+ transport , upgrader , err := spdy .RoundTripperFor (config )
536
+ if err != nil {
537
+ return nil , err
538
+ }
539
+ dialer := spdy .NewDialer (upgrader , & http.Client {Transport : transport }, method , url )
540
+ tunnelingDialer , err := portforward .NewSPDYOverWebsocketDialer (url , config )
541
+ if err != nil {
542
+ return nil , err
543
+ }
544
+ // First attempt tunneling (websocket) dialer, then fallback to spdy dialer.
545
+ dialer = portforward .NewFallbackDialer (tunnelingDialer , dialer , func (err error ) bool {
546
+ return httpstream .IsUpgradeFailure (err ) || httpstream .IsHTTPSProxyError (err )
547
+ })
548
+ return dialer , nil
549
+ }
0 commit comments