Skip to content

Commit 1d3c0ed

Browse files
authored
Merge pull request #2 from /issues/120
Fall back to SPDY for exec if WebSockets aren't supported
2 parents 5ed88f8 + 3c925a4 commit 1d3c0ed

File tree

1 file changed

+27
-3
lines changed

1 file changed

+27
-3
lines changed

internal/pkg/kube/exec.go

+27-3
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@ import (
77
"context"
88
"fmt"
99
"io"
10+
"net/url"
1011

1112
v1 "k8s.io/api/core/v1"
13+
"k8s.io/apimachinery/pkg/util/httpstream"
1214
"k8s.io/client-go/kubernetes"
1315
restclient "k8s.io/client-go/rest"
1416
"k8s.io/client-go/tools/remotecommand"
@@ -35,18 +37,40 @@ func RunCommand(ctx context.Context, client kubernetes.Interface, config *restcl
3537
SubResource("exec").
3638
VersionedParams(opts, scheme.ParameterCodec)
3739

38-
exec, err := remotecommand.NewWebSocketExecutor(config, "POST", req.URL().String())
40+
exec, err := createExecutor(req.URL(), config)
3941
if err != nil {
40-
return fmt.Errorf("new executor: %w", err)
42+
return fmt.Errorf("failed to create executor: %w", err)
4143
}
44+
4245
err = exec.StreamWithContext(ctx, remotecommand.StreamOptions{
4346
Stdin: stdin,
4447
Stdout: stdout,
4548
Stderr: stderr,
4649
})
4750
if err != nil {
48-
return fmt.Errorf("stream exec: %w", err)
51+
return fmt.Errorf("failed to stream exec: %w", err)
4952
}
5053

5154
return nil
5255
}
56+
57+
// createExecutor returns the Executor or an error if one occurred.
58+
// Adapted from a function of the same name in kubectl: https://github.com/kubernetes/kubectl/blob/d0bc9691f3166ac2586b3c948f455f78987e34de/pkg/cmd/exec/exec.go#L137
59+
func createExecutor(url *url.URL, config *restclient.Config) (remotecommand.Executor, error) {
60+
exec, err := remotecommand.NewSPDYExecutor(config, "POST", url)
61+
if err != nil {
62+
return nil, err
63+
}
64+
// WebSocketExecutor must be "GET" method as described in RFC 6455 Sec. 4.1 (page 17).
65+
websocketExec, err := remotecommand.NewWebSocketExecutor(config, "GET", url.String())
66+
if err != nil {
67+
return nil, err
68+
}
69+
exec, err = remotecommand.NewFallbackExecutor(websocketExec, exec, func(err error) bool {
70+
return httpstream.IsUpgradeFailure(err) || httpstream.IsHTTPSProxyError(err)
71+
})
72+
if err != nil {
73+
return nil, err
74+
}
75+
return exec, nil
76+
}

0 commit comments

Comments
 (0)