mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-01 07:47:56 +00:00
Graduate PortForwardWebsockets to Beta
This commit is contained in:
parent
c3689b9f8b
commit
3ae3b4ea55
@ -600,6 +600,7 @@ const (
|
|||||||
// owner: @seans3
|
// owner: @seans3
|
||||||
// kep: http://kep.k8s.io/4006
|
// kep: http://kep.k8s.io/4006
|
||||||
// alpha: v1.30
|
// alpha: v1.30
|
||||||
|
// beta: v1.31
|
||||||
//
|
//
|
||||||
// Enables PortForward to be proxied with a websocket client
|
// Enables PortForward to be proxied with a websocket client
|
||||||
PortForwardWebsockets featuregate.Feature = "PortForwardWebsockets"
|
PortForwardWebsockets featuregate.Feature = "PortForwardWebsockets"
|
||||||
@ -805,6 +806,7 @@ const (
|
|||||||
|
|
||||||
// owner: @seans3
|
// owner: @seans3
|
||||||
// kep: http://kep.k8s.io/4006
|
// kep: http://kep.k8s.io/4006
|
||||||
|
// alpha: v1.29
|
||||||
// beta: v1.30
|
// beta: v1.30
|
||||||
//
|
//
|
||||||
// Enables StreamTranslator proxy to handle WebSockets upgrade requests for the
|
// Enables StreamTranslator proxy to handle WebSockets upgrade requests for the
|
||||||
@ -1104,7 +1106,7 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
|
|||||||
|
|
||||||
PodSchedulingReadiness: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // GA in 1.30; remove in 1.32
|
PodSchedulingReadiness: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // GA in 1.30; remove in 1.32
|
||||||
|
|
||||||
PortForwardWebsockets: {Default: false, PreRelease: featuregate.Alpha},
|
PortForwardWebsockets: {Default: true, PreRelease: featuregate.Beta},
|
||||||
|
|
||||||
ProcMountType: {Default: false, PreRelease: featuregate.Alpha},
|
ProcMountType: {Default: false, PreRelease: featuregate.Alpha},
|
||||||
|
|
||||||
|
@ -21,21 +21,21 @@ import (
|
|||||||
"k8s.io/klog/v2"
|
"k8s.io/klog/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ httpstream.Dialer = &fallbackDialer{}
|
var _ httpstream.Dialer = &FallbackDialer{}
|
||||||
|
|
||||||
// fallbackDialer encapsulates a primary and secondary dialer, including
|
// FallbackDialer encapsulates a primary and secondary dialer, including
|
||||||
// the boolean function to determine if the primary dialer failed. Implements
|
// the boolean function to determine if the primary dialer failed. Implements
|
||||||
// the httpstream.Dialer interface.
|
// the httpstream.Dialer interface.
|
||||||
type fallbackDialer struct {
|
type FallbackDialer struct {
|
||||||
primary httpstream.Dialer
|
primary httpstream.Dialer
|
||||||
secondary httpstream.Dialer
|
secondary httpstream.Dialer
|
||||||
shouldFallback func(error) bool
|
shouldFallback func(error) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewFallbackDialer creates the fallbackDialer with the primary and secondary dialers,
|
// NewFallbackDialer creates the FallbackDialer with the primary and secondary dialers,
|
||||||
// as well as the boolean function to determine if the primary dialer failed.
|
// as well as the boolean function to determine if the primary dialer failed.
|
||||||
func NewFallbackDialer(primary, secondary httpstream.Dialer, shouldFallback func(error) bool) httpstream.Dialer {
|
func NewFallbackDialer(primary, secondary httpstream.Dialer, shouldFallback func(error) bool) httpstream.Dialer {
|
||||||
return &fallbackDialer{
|
return &FallbackDialer{
|
||||||
primary: primary,
|
primary: primary,
|
||||||
secondary: secondary,
|
secondary: secondary,
|
||||||
shouldFallback: shouldFallback,
|
shouldFallback: shouldFallback,
|
||||||
@ -47,7 +47,7 @@ func NewFallbackDialer(primary, secondary httpstream.Dialer, shouldFallback func
|
|||||||
// httstream.Connection and the negotiated protocol version accepted. If the initial
|
// httstream.Connection and the negotiated protocol version accepted. If the initial
|
||||||
// primary dialer fails, this function attempts the secondary dialer. Returns an error
|
// primary dialer fails, this function attempts the secondary dialer. Returns an error
|
||||||
// if one occurs.
|
// if one occurs.
|
||||||
func (f *fallbackDialer) Dial(protocols ...string) (httpstream.Connection, string, error) {
|
func (f *FallbackDialer) Dial(protocols ...string) (httpstream.Connection, string, error) {
|
||||||
conn, version, err := f.primary.Dial(protocols...)
|
conn, version, err := f.primary.Dial(protocols...)
|
||||||
if err != nil && f.shouldFallback(err) {
|
if err != nil && f.shouldFallback(err) {
|
||||||
klog.V(4).Infof("fallback to secondary dialer from primary dialer err: %v", err)
|
klog.V(4).Infof("fallback to secondary dialer from primary dialer err: %v", err)
|
||||||
|
@ -136,20 +136,28 @@ type defaultPortForwarder struct {
|
|||||||
genericiooptions.IOStreams
|
genericiooptions.IOStreams
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *defaultPortForwarder) ForwardPorts(method string, url *url.URL, opts PortForwardOptions) error {
|
func createDialer(method string, url *url.URL, opts PortForwardOptions) (httpstream.Dialer, error) {
|
||||||
transport, upgrader, err := spdy.RoundTripperFor(opts.Config)
|
transport, upgrader, err := spdy.RoundTripperFor(opts.Config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
dialer := spdy.NewDialer(upgrader, &http.Client{Transport: transport}, method, url)
|
dialer := spdy.NewDialer(upgrader, &http.Client{Transport: transport}, method, url)
|
||||||
if cmdutil.PortForwardWebsockets.IsEnabled() {
|
if !cmdutil.PortForwardWebsockets.IsDisabled() {
|
||||||
tunnelingDialer, err := portforward.NewSPDYOverWebsocketDialer(url, opts.Config)
|
tunnelingDialer, err := portforward.NewSPDYOverWebsocketDialer(url, opts.Config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
// First attempt tunneling (websocket) dialer, then fallback to spdy dialer.
|
// First attempt tunneling (websocket) dialer, then fallback to spdy dialer.
|
||||||
dialer = portforward.NewFallbackDialer(tunnelingDialer, dialer, httpstream.IsUpgradeFailure)
|
dialer = portforward.NewFallbackDialer(tunnelingDialer, dialer, httpstream.IsUpgradeFailure)
|
||||||
}
|
}
|
||||||
|
return dialer, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *defaultPortForwarder) ForwardPorts(method string, url *url.URL, opts PortForwardOptions) error {
|
||||||
|
dialer, err := createDialer(method, url, opts)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
fw, err := portforward.NewOnAddresses(dialer, opts.Address, opts.Ports, opts.StopChannel, opts.ReadyChannel, f.Out, f.ErrOut)
|
fw, err := portforward.NewOnAddresses(dialer, opts.Address, opts.Ports, opts.StopChannel, opts.ReadyChannel, f.Out, f.ErrOut)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -32,7 +32,9 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/util/intstr"
|
"k8s.io/apimachinery/pkg/util/intstr"
|
||||||
"k8s.io/cli-runtime/pkg/genericiooptions"
|
"k8s.io/cli-runtime/pkg/genericiooptions"
|
||||||
"k8s.io/client-go/rest/fake"
|
"k8s.io/client-go/rest/fake"
|
||||||
|
"k8s.io/client-go/tools/portforward"
|
||||||
cmdtesting "k8s.io/kubectl/pkg/cmd/testing"
|
cmdtesting "k8s.io/kubectl/pkg/cmd/testing"
|
||||||
|
cmdutil "k8s.io/kubectl/pkg/cmd/util"
|
||||||
"k8s.io/kubectl/pkg/scheme"
|
"k8s.io/kubectl/pkg/scheme"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -983,3 +985,38 @@ func TestCheckUDPPort(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCreateDialer(t *testing.T) {
|
||||||
|
url, err := url.Parse("http://localhost:8080/index.html")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to parse test url: %v", err)
|
||||||
|
}
|
||||||
|
config := cmdtesting.DefaultClientConfig()
|
||||||
|
opts := PortForwardOptions{Config: config}
|
||||||
|
// First, ensure that no environment variable creates the fallback dialer.
|
||||||
|
dialer, err := createDialer("GET", url, opts)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to create dialer: %v", err)
|
||||||
|
}
|
||||||
|
if _, isFallback := dialer.(*portforward.FallbackDialer); !isFallback {
|
||||||
|
t.Errorf("expected fallback dialer, got %#v", dialer)
|
||||||
|
}
|
||||||
|
// Next, check turning on feature flag explicitly also creates fallback dialer.
|
||||||
|
t.Setenv(string(cmdutil.PortForwardWebsockets), "true")
|
||||||
|
dialer, err = createDialer("GET", url, opts)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to create dialer: %v", err)
|
||||||
|
}
|
||||||
|
if _, isFallback := dialer.(*portforward.FallbackDialer); !isFallback {
|
||||||
|
t.Errorf("expected fallback dialer, got %#v", dialer)
|
||||||
|
}
|
||||||
|
// Finally, check explicit disabling does NOT create the fallback dialer.
|
||||||
|
t.Setenv(string(cmdutil.PortForwardWebsockets), "false")
|
||||||
|
dialer, err = createDialer("GET", url, opts)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to create dialer: %v", err)
|
||||||
|
}
|
||||||
|
if _, isFallback := dialer.(*portforward.FallbackDialer); isFallback {
|
||||||
|
t.Errorf("expected fallback dialer, got %#v", dialer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user