1
16
17 package kubectl
18
19 import (
20 "bytes"
21 "fmt"
22 "io"
23 "net"
24 "net/url"
25 "os"
26 "os/exec"
27 "strings"
28 "syscall"
29 "time"
30
31 "k8s.io/client-go/tools/clientcmd"
32 uexec "k8s.io/utils/exec"
33
34 "k8s.io/kubernetes/test/e2e/framework"
35 )
36
37
38
39 type KubectlBuilder struct {
40 cmd *exec.Cmd
41 timeout <-chan time.Time
42 }
43
44
45 func NewKubectlCommand(namespace string, args ...string) *KubectlBuilder {
46 b := new(KubectlBuilder)
47 tk := NewTestKubeconfig(framework.TestContext.CertDir, framework.TestContext.Host, framework.TestContext.KubeConfig, framework.TestContext.KubeContext, framework.TestContext.KubectlPath, namespace)
48 b.cmd = tk.KubectlCmd(args...)
49 return b
50 }
51
52
53 func (b *KubectlBuilder) AppendEnv(env []string) *KubectlBuilder {
54 if b.cmd.Env == nil {
55 b.cmd.Env = os.Environ()
56 }
57 b.cmd.Env = append(b.cmd.Env, env...)
58 return b
59 }
60
61
62 func (b *KubectlBuilder) WithTimeout(t <-chan time.Time) *KubectlBuilder {
63 b.timeout = t
64 return b
65 }
66
67
68 func (b KubectlBuilder) WithStdinData(data string) *KubectlBuilder {
69 b.cmd.Stdin = strings.NewReader(data)
70 return &b
71 }
72
73
74 func (b KubectlBuilder) WithStdinReader(reader io.Reader) *KubectlBuilder {
75 b.cmd.Stdin = reader
76 return &b
77 }
78
79
80 func (b KubectlBuilder) ExecOrDie(namespace string) string {
81 str, err := b.Exec()
82
83
84 if isTimeout(err) {
85 framework.Logf("Hit i/o timeout error, talking to the server 2s later to see if it's temporary.")
86 time.Sleep(2 * time.Second)
87 retryStr, retryErr := RunKubectl(namespace, "version")
88 framework.Logf("stdout: %q", retryStr)
89 framework.Logf("err: %v", retryErr)
90 }
91 framework.ExpectNoError(err)
92 return str
93 }
94
95 func isTimeout(err error) bool {
96 switch err := err.(type) {
97 case *url.Error:
98 if err, ok := err.Err.(net.Error); ok && err.Timeout() {
99 return true
100 }
101 case net.Error:
102 if err.Timeout() {
103 return true
104 }
105 }
106 return false
107 }
108
109
110 func (b KubectlBuilder) Exec() (string, error) {
111 stdout, _, err := b.ExecWithFullOutput()
112 return stdout, err
113 }
114
115
116 func (b KubectlBuilder) ExecWithFullOutput() (string, string, error) {
117 var stdout, stderr bytes.Buffer
118 cmd := b.cmd
119 cmd.Stdout, cmd.Stderr = &stdout, &stderr
120
121 framework.Logf("Running '%s %s'", cmd.Path, strings.Join(cmd.Args[1:], " "))
122 if err := cmd.Start(); err != nil {
123 return "", "", fmt.Errorf("error starting %v:\nCommand stdout:\n%v\nstderr:\n%v\nerror:\n%v", cmd, cmd.Stdout, cmd.Stderr, err)
124 }
125 errCh := make(chan error, 1)
126 go func() {
127 errCh <- cmd.Wait()
128 }()
129 select {
130 case err := <-errCh:
131 if err != nil {
132 var rc = 127
133 if ee, ok := err.(*exec.ExitError); ok {
134 rc = int(ee.Sys().(syscall.WaitStatus).ExitStatus())
135 framework.Logf("rc: %d", rc)
136 }
137 return stdout.String(), stderr.String(), uexec.CodeExitError{
138 Err: fmt.Errorf("error running %v:\nCommand stdout:\n%v\nstderr:\n%v\nerror:\n%v", cmd, cmd.Stdout, cmd.Stderr, err),
139 Code: rc,
140 }
141 }
142 case <-b.timeout:
143 b.cmd.Process.Kill()
144 return "", "", fmt.Errorf("timed out waiting for command %v:\nCommand stdout:\n%v\nstderr:\n%v", cmd, cmd.Stdout, cmd.Stderr)
145 }
146 framework.Logf("stderr: %q", stderr.String())
147 framework.Logf("stdout: %q", stdout.String())
148 return stdout.String(), stderr.String(), nil
149 }
150
151
152 func RunKubectlOrDie(namespace string, args ...string) string {
153 return NewKubectlCommand(namespace, args...).ExecOrDie(namespace)
154 }
155
156
157 func RunKubectl(namespace string, args ...string) (string, error) {
158 return NewKubectlCommand(namespace, args...).Exec()
159 }
160
161
162
163 func RunKubectlWithFullOutput(namespace string, args ...string) (string, string, error) {
164 return NewKubectlCommand(namespace, args...).ExecWithFullOutput()
165 }
166
167
168 func RunKubectlOrDieInput(namespace string, data string, args ...string) string {
169 return NewKubectlCommand(namespace, args...).WithStdinData(data).ExecOrDie(namespace)
170 }
171
172
173 func RunKubectlInput(namespace string, data string, args ...string) (string, error) {
174 return NewKubectlCommand(namespace, args...).WithStdinData(data).Exec()
175 }
176
177
178 func RunKubemciWithKubeconfig(args ...string) (string, error) {
179 if framework.TestContext.KubeConfig != "" {
180 args = append(args, "--"+clientcmd.RecommendedConfigPathFlag+"="+framework.TestContext.KubeConfig)
181 }
182 return RunKubemciCmd(args...)
183 }
184
185
186
187 func RunKubemciCmd(args ...string) (string, error) {
188
189 kubemci := "kubemci"
190 b := new(KubectlBuilder)
191 args = append(args, "--gcp-project="+framework.TestContext.CloudConfig.ProjectID)
192
193 b.cmd = exec.Command(kubemci, args...)
194 return b.Exec()
195 }
196
View as plain text