/
pod_exec.go
109 lines (90 loc) · 2.28 KB
/
pod_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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
/*
* Copyright (c) 2019, 2023, Oracle and/or its affiliates.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
package management
import (
"context"
"errors"
"io"
"strings"
"time"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/remotecommand"
utilexec "k8s.io/client-go/util/exec"
)
type ExecRequest struct {
Pod string
Container string
Namespace string
Command []string
Arg []string
Timeout time.Duration
}
// PodExec executes a command in a Pod.
func PodExec(ctx context.Context, req *ExecRequest, config *rest.Config) (int, string, string, error) {
kubeClient := kubernetes.NewForConfigOrDie(config)
timeout := req.Timeout
if timeout < time.Second*10 {
timeout = time.Second * 10
}
execRequest := kubeClient.CoreV1().RESTClient().Post().
Timeout(timeout).
Resource("pods").
Name(req.Pod).
Namespace(req.Namespace).
SubResource("exec").
Param("stdin", "true").
Param("stdout", "true").
Param("stderr", "true").
Param("tty", "false")
if req.Container != "" {
execRequest.Param("container", req.Container)
}
for _, cmd := range req.Command {
execRequest.Param("command", cmd)
}
exec, err := remotecommand.NewSPDYExecutor(config, "POST", execRequest.URL())
if err != nil {
return 1, "", "", err
}
stdIn := newStringReader(req.Arg)
stdOut := new(streamCapture)
stdErr := new(streamCapture)
err = exec.StreamWithContext(ctx, remotecommand.StreamOptions{
Stdin: stdIn,
Stdout: stdOut,
Stderr: stdErr,
Tty: false,
})
outStr := strings.Join(stdOut.Str, "")
errStr := strings.Join(stdErr.Str, "")
var exitCode int
if err == nil {
exitCode = 0
} else {
if exitErr, ok := err.(utilexec.ExitError); ok && exitErr.Exited() {
exitCode = exitErr.ExitStatus()
} else {
return 1, outStr, errStr, errors.New("failed to find exit code")
}
}
return exitCode, outStr, errStr, nil
}
type streamCapture struct {
Str []string
}
func (w *streamCapture) Write(p []byte) (n int, err error) {
str := string(p)
if len(str) > 0 {
w.Str = append(w.Str, str)
}
return len(str), nil
}
func newStringReader(ss []string) io.Reader {
formattedString := strings.Join(ss, "\n")
reader := strings.NewReader(formattedString)
return reader
}