-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathexec.go
92 lines (83 loc) · 2.72 KB
/
exec.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
package k8s_exec_pod
import (
"github.com/Shanghai-Lunara/pkg/zaplogger"
corev1 "k8s.io/api/core/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/remotecommand"
)
// isValidShell checks if the shell is an allowed one
func isValidShell(validShells []string, shell string) bool {
zaplogger.Sugar().Infow("isValidShell", "shell", shell)
for _, validShell := range validShells {
if validShell == shell {
return true
}
}
return false
}
// Terminal is called from Session as a goroutine
// Waits for the websocket connection to be opened by the client the session to be bound in Session.HandleProxy
func Terminal(k8sClient kubernetes.Interface, cfg *rest.Config, session Session) {
var err error
validShells := []string{"bash", "sh", "powershell", "cmd"}
if isValidShell(validShells, session.Option().Command[0]) {
err = Exec(k8sClient, cfg, session)
} else {
// No shell given or it was not valid: try some shells until one succeeds or all fail
// FIXME: if the first shell fails then the first keyboard event is lost
for _, testShell := range validShells {
opt := session.Option()
opt.Command = []string{testShell}
if err = Exec(k8sClient, cfg, session); err == nil {
zaplogger.Sugar().Error(err)
break
}
}
}
if err != nil {
zaplogger.Sugar().Error(err)
session.Close(err.Error())
return
}
session.Close(ReasonProcessExited)
}
// Exec is called by Terminal
// Executed cmd in the container specified in request and connects it up with the ptyHandler (a Session)
func Exec(k8sClient kubernetes.Interface, cfg *rest.Config, session Session) error {
zaplogger.Sugar().Infof("startProcess Namespace:%s PodName:%s ContainerName:%s Command:%v",
session.Option().Namespace, session.Option().PodName, session.Option().ContainerName, session.Option().Command)
req := k8sClient.CoreV1().RESTClient().Post().
Resource("pods").
Name(session.Option().PodName).
Namespace(session.Option().Namespace).
SubResource("exec").
VersionedParams(&corev1.PodExecOptions{
Container: session.Option().ContainerName,
Command: session.Option().Command,
Stdin: true,
Stdout: true,
Stderr: true,
TTY: true,
}, scheme.ParameterCodec)
zaplogger.Sugar().Infow("Exec", "url", req.URL())
exec, err := remotecommand.NewSPDYExecutor(cfg, "POST", req.URL())
if err != nil {
zaplogger.Sugar().Error(err)
return err
}
//var stdout, stderr bytes.Buffer
err = exec.Stream(remotecommand.StreamOptions{
Stdin: session,
Stdout: session,
Stderr: session,
TerminalSizeQueue: session,
Tty: true,
})
if err != nil {
zaplogger.Sugar().Error(err)
return err
}
return nil
}