Skip to content

Commit 8956fda

Browse files
committed
refactoring and more flags
1 parent a63d468 commit 8956fda

File tree

2 files changed

+134
-74
lines changed

2 files changed

+134
-74
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@ Edit the configuration file to set default image and shell to execute, as well a
1818

1919
| Flag | Description |
2020
| ---- | ----------- |
21+
| `--list` | List running testpods. |
2122
| `--image` | Overrides the default image from your template. |
2223
| `--shell` | Overrides the default shell from your template. |
2324
| `--enter-mine` | Enters an existing testpod managed by you. |
2425
| `--enter-any` | Enters an existing testpod managed by anyone. |
2526
| `--dry-run` | Prints the rendered manifests instead of applying them to Kubernetes. |
27+
| `--no-temp-kubeconfig` | Do not use temporary copy of kubeconfig file. |

main.go

Lines changed: 132 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,41 @@ import (
1010
)
1111

1212
var (
13-
flagImageOverride = flag.String("image", "", "set to override default image from template")
14-
flagShellOverride = flag.String("shell", "", "set to override default shell from template")
15-
flagEnterMine = flag.Bool("enter-mine", false, "open another shell in existing testpod managed by you")
16-
flagEnterAny = flag.Bool("enter-any", false, "open another shell in existing testpod managed by anyone")
17-
flagDryRun = flag.Bool("dry-run", false, "print manifest instead of applying it to kubernetes")
13+
flagImageOverride = flag.String("image", "", "set to override default image from template")
14+
flagShellOverride = flag.String("shell", "", "set to override default shell from template")
15+
flagList = flag.Bool("list", false, "list all running testpods")
16+
flagEnterMine = flag.Bool("enter-mine", false, "open another shell in existing testpod managed by you")
17+
flagEnterAny = flag.Bool("enter-any", false, "open another shell in existing testpod managed by anyone")
18+
flagDryRun = flag.Bool("dry-run", false, "print manifest instead of applying it to kubernetes")
19+
flagNoTempKubeConfig = flag.Bool("no-temp-kubeconfig", false, "do not use temporary copy of kubeconfig file")
1820

1921
tempKubeconfigPath string
2022
)
2123

2224
func main() {
2325
flag.Parse()
2426

27+
if err := execAll(); err != nil {
28+
fmt.Println("ERR:", err)
29+
os.Exit(1)
30+
}
31+
}
32+
33+
func execAll() error {
34+
if *flagList {
35+
if *flagEnterMine || *flagEnterAny {
36+
return fmt.Errorf("cannot set flag --list in conjunction with --enter-mine or --enter-any")
37+
}
38+
39+
if err := kubectlListPods(map[string]string{"app.kubernetes.io/name": "go-testpod"}); err != nil {
40+
return fmt.Errorf("list testpods: %w", err)
41+
}
42+
return nil
43+
}
44+
2545
tpl, err := ReadTemplate()
2646
if err != nil {
27-
fmt.Println("ERR: read template:", err)
28-
os.Exit(1)
47+
return fmt.Errorf("read template: %w", err)
2948
}
3049
if len(*flagImageOverride) > 0 {
3150
tpl.DefaultImage = *flagImageOverride
@@ -34,34 +53,33 @@ func main() {
3453
tpl.DefaultShell = *flagShellOverride
3554
}
3655

37-
if err := execTemplate(tpl); err != nil {
38-
fmt.Println("ERR:", err)
39-
os.Exit(1)
40-
}
56+
return execWithTemplate(tpl)
4157
}
4258

43-
func execTemplate(tpl Template) error {
59+
func execWithTemplate(tpl Template) error {
4460
realKubeconfigPath := os.Getenv("KUBECONFIG")
45-
tmpFile, err := os.CreateTemp(os.TempDir(), "testpod-kubeconfig-*.yaml")
46-
if err != nil {
47-
return fmt.Errorf("create temp kubeconfig: %w", err)
48-
}
49-
tempKubeconfigPath = tmpFile.Name()
50-
fmt.Println("clone kubeconfig", realKubeconfigPath, "to", tempKubeconfigPath)
51-
data, err := os.ReadFile(realKubeconfigPath)
52-
if err != nil {
53-
return fmt.Errorf("read kubeconfig: %w", err)
54-
}
55-
if err := os.WriteFile(tempKubeconfigPath, data, os.ModePerm); err != nil {
56-
return fmt.Errorf("write temp kubeconfig: %w", err)
57-
}
58-
defer func() {
59-
if err := os.Remove(tempKubeconfigPath); err != nil {
60-
fmt.Println("WARN: failed to delete temp kubeconfig file", tempKubeconfigPath)
61-
} else {
62-
fmt.Println("temp kubeconfig file", tempKubeconfigPath, "deleted")
61+
if !*flagNoTempKubeConfig {
62+
tmpFile, err := os.CreateTemp(os.TempDir(), "testpod-kubeconfig-*.yaml")
63+
if err != nil {
64+
return fmt.Errorf("create temp kubeconfig: %w", err)
6365
}
64-
}()
66+
tempKubeconfigPath = tmpFile.Name()
67+
fmt.Println("clone kubeconfig", realKubeconfigPath, "to", tempKubeconfigPath)
68+
data, err := os.ReadFile(realKubeconfigPath)
69+
if err != nil {
70+
return fmt.Errorf("read kubeconfig: %w", err)
71+
}
72+
if err := os.WriteFile(tempKubeconfigPath, data, os.ModePerm); err != nil {
73+
return fmt.Errorf("write temp kubeconfig: %w", err)
74+
}
75+
defer func() {
76+
if err := os.Remove(tempKubeconfigPath); err != nil {
77+
fmt.Println("WARN: failed to delete temp kubeconfig file", tempKubeconfigPath)
78+
} else {
79+
fmt.Println("temp kubeconfig file", tempKubeconfigPath, "deleted")
80+
}
81+
}()
82+
}
6583

6684
hostname, err := os.Hostname()
6785
if err != nil {
@@ -73,15 +91,18 @@ func execTemplate(tpl Template) error {
7391
if *flagEnterMine && *flagEnterAny {
7492
return fmt.Errorf("cannot set flags --enter-mine and --enter-any at the same time")
7593
}
94+
if len(*flagImageOverride) > 0 {
95+
return fmt.Errorf("cannot set flag --image when entering existing pod")
96+
}
7697

77-
matchLabel := "app.kubernetes.io/managed-by"
78-
matchValue := managedBy
79-
if *flagEnterAny {
80-
matchLabel = "app.kubernetes.io/name"
81-
matchValue = "go-testpod"
98+
matchLabels := map[string]string{
99+
"app.kubernetes.io/name": "go-testpod",
100+
}
101+
if *flagEnterMine {
102+
matchLabels["app.kubernetes.io/managed-by"] = managedBy
82103
}
83104

84-
pods, err := kubectlGetPodNames(matchLabel, matchValue)
105+
pods, err := kubectlGetPodNames(matchLabels)
85106
if err != nil {
86107
return fmt.Errorf("list running pods: %w", err)
87108
}
@@ -146,15 +167,29 @@ func execTemplate(tpl Template) error {
146167
return nil
147168
}
148169

149-
func kubectlGetPodNames(label, value string) ([]string, error) {
150-
cmd := exec.Command("kubectl", "get", "pods", "-l", label+"="+value, "--no-headers", "-o", "custom-columns=:metadata.name")
151-
cmd.Env = os.Environ()
152-
cmd.Env = append(cmd.Env, "KUBECONFIG="+tempKubeconfigPath)
153-
out, err := cmd.CombinedOutput()
154-
fmt.Println(strings.TrimSpace(string(out)))
170+
func kubectlListPods(matchLabels map[string]string) error {
171+
args := []string{"get", "pods", "-L", "app.kubernetes.io/managed-by"}
172+
for k, v := range matchLabels {
173+
args = append(args, "-l", k+"="+v)
174+
}
175+
return kubectl(options{
176+
Args: args,
177+
})
178+
}
179+
180+
func kubectlGetPodNames(matchLabels map[string]string) ([]string, error) {
181+
args := []string{"get", "pods", "--no-headers", "-o", "custom-columns=:metadata.name"}
182+
for k, v := range matchLabels {
183+
args = append(args, "-l", k+"="+v)
184+
}
185+
out, err := kubectlGetOutput(options{
186+
Args: args,
187+
Silent: true,
188+
})
155189
if err != nil {
156190
return nil, err
157191
}
192+
158193
podNames := make([]string, 0)
159194
for _, part := range strings.Split(string(out), "\n") {
160195
part = strings.TrimSpace(part)
@@ -166,48 +201,71 @@ func kubectlGetPodNames(label, value string) ([]string, error) {
166201
}
167202

168203
func kubectlApply(manifestData string) error {
169-
cmd := exec.Command("kubectl", "apply", "-f", "-")
170-
cmd.Env = os.Environ()
171-
cmd.Env = append(cmd.Env, "KUBECONFIG="+tempKubeconfigPath)
172-
cmd.Stdin = strings.NewReader(manifestData)
173-
out, err := cmd.CombinedOutput()
174-
fmt.Println(strings.TrimSpace(string(out)))
175-
return err
204+
return kubectl(options{
205+
Args: []string{"apply", "-f", "-"},
206+
StdIn: manifestData,
207+
})
176208
}
177209

178210
func kubectlWaitForPod(podName string) error {
179-
cmd := exec.Command("kubectl", "wait", "--for=condition=ready", "--timeout=30s", "pod/"+podName)
180-
cmd.Env = os.Environ()
181-
cmd.Env = append(cmd.Env, "KUBECONFIG="+tempKubeconfigPath)
182-
out, err := cmd.CombinedOutput()
183-
fmt.Println(strings.TrimSpace(string(out)))
184-
return err
211+
return kubectl(options{
212+
Args: []string{"wait", "--for=condition=ready", "--timeout=30s", "pod/" + podName},
213+
})
185214
}
186215

187216
func kubectlExec(podName string, shell string) error {
188-
cmd := exec.Command("kubectl", "exec", "-it", podName, "--", shell)
189-
cmd.Env = os.Environ()
190-
cmd.Env = append(cmd.Env, "KUBECONFIG="+tempKubeconfigPath)
191-
cmd.Stdin = os.Stdin
192-
cmd.Stdout = os.Stdout
193-
cmd.Stderr = os.Stderr
194-
return cmd.Run()
217+
return kubectl(options{
218+
Args: []string{"exec", "-it", podName, "--", shell},
219+
PipeAll: true,
220+
})
195221
}
196222

197223
func kubectlDeletePod(podName string) error {
198-
cmd := exec.Command("kubectl", "delete", "--wait=false", "pod", podName)
199-
cmd.Env = os.Environ()
200-
cmd.Env = append(cmd.Env, "KUBECONFIG="+tempKubeconfigPath)
201-
out, err := cmd.CombinedOutput()
202-
fmt.Println(strings.TrimSpace(string(out)))
203-
return err
224+
return kubectl(options{
225+
Args: []string{"delete", "--wait=false", "pod", podName},
226+
})
204227
}
205228

206229
func kubectlDeleteNetworkPolicy(name string) error {
207-
cmd := exec.Command("kubectl", "delete", "--wait=false", "netpol", name)
208-
cmd.Env = os.Environ()
209-
cmd.Env = append(cmd.Env, "KUBECONFIG="+tempKubeconfigPath)
210-
out, err := cmd.CombinedOutput()
211-
fmt.Println(strings.TrimSpace(string(out)))
230+
return kubectl(options{
231+
Args: []string{"delete", "--wait=false", "netpol", name},
232+
})
233+
}
234+
235+
type options struct {
236+
Args []string
237+
PipeAll bool
238+
Silent bool
239+
StdIn string
240+
}
241+
242+
func kubectl(options options) error {
243+
_, err := kubectlGetOutput(options)
212244
return err
213245
}
246+
247+
func kubectlGetOutput(options options) (string, error) {
248+
if options.PipeAll && len(options.StdIn) > 0 {
249+
return "", fmt.Errorf("cannot set PipeAll and StdIn at the same time")
250+
}
251+
252+
cmd := exec.Command("kubectl", options.Args...)
253+
if len(tempKubeconfigPath) > 0 {
254+
cmd.Env = os.Environ()
255+
cmd.Env = append(cmd.Env, "KUBECONFIG="+tempKubeconfigPath)
256+
}
257+
if options.PipeAll {
258+
cmd.Stdin = os.Stdin
259+
cmd.Stdout = os.Stdout
260+
cmd.Stderr = os.Stderr
261+
return "", cmd.Run()
262+
}
263+
if len(options.StdIn) > 0 {
264+
cmd.Stdin = strings.NewReader(options.StdIn)
265+
}
266+
out, err := cmd.CombinedOutput()
267+
if !options.Silent {
268+
fmt.Println(strings.TrimSpace(string(out)))
269+
}
270+
return string(out), err
271+
}

0 commit comments

Comments
 (0)