@@ -10,22 +10,41 @@ import (
1010)
1111
1212var (
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
2224func 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
168203func 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
178210func 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
187216func 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
197223func 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
206229func 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