@@ -10,13 +10,13 @@ import (
1010 "net/http"
1111 "net/url"
1212 "os"
13+ "os/exec"
1314 "os/signal"
1415 "strconv"
1516 "strings"
1617 "sync"
1718 "time"
1819
19- "github.com/segmentio/kubectl-curl/curl"
2020 "github.com/spf13/pflag"
2121 corev1 "k8s.io/api/core/v1"
2222 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -27,6 +27,8 @@ import (
2727 "k8s.io/client-go/rest"
2828 "k8s.io/client-go/tools/portforward"
2929 "k8s.io/client-go/transport/spdy"
30+
31+ "github.com/segmentio/kubectl-curl/curl"
3032)
3133
3234var (
3638 debug bool
3739 options string
3840 flags * pflag.FlagSet
41+ cflags * pflag.FlagSet
3942 config * genericclioptions.ConfigFlags
4043)
4144
@@ -48,8 +51,9 @@ func init() {
4851
4952 flags = pflag .NewFlagSet ("kubectl curl" , pflag .ExitOnError )
5053 flags .BoolVarP (& help , "help" , "h" , false , "Prints the kubectl plugin help." )
51- flags .BoolVarP (& debug , "debug" , "" , false , "Enable debug mode to print more details about the kubectl command execution." )
52-
54+ flags .BoolVarP (& debug , "debug" , "" , false ,
55+ "Enable debug mode to print more details about the kubectl command execution." )
56+ cflags = pflag .NewFlagSet ("curl" , pflag .ExitOnError ) // curl-only FlagSet
5357 for _ , opt := range curlOptions {
5458 name := strings .TrimPrefix (opt .Name , "--" )
5559 short := strings .TrimPrefix (opt .Short , "-" )
@@ -69,13 +73,15 @@ func init() {
6973 }
7074
7175 flag := flags .VarPF (opt .Value , name , short , opt .Help )
76+ cflag := cflags .VarPF (opt .Value , name , short , opt .Help )
7277 if curl .IsBoolFlag (opt .Value ) {
7378 flag .NoOptDefVal = "true"
79+ cflag .NoOptDefVal = "true"
7480 }
7581 }
7682
7783 config = genericclioptions .NewConfigFlags (false )
78- config .AddFlags (flags )
84+ config .AddFlags (flags ) // adds k8s config flags to flags
7985 options = flags .FlagUsages ()
8086}
8187
@@ -90,7 +96,25 @@ func main() {
9096}
9197
9298func run (ctx context.Context ) error {
93- flags .Parse (os .Args [1 :])
99+ cArgs := make ([]string , 0 )
100+ flags .ParseAll (os .Args [1 :], func (flag * pflag.Flag , value string ) error {
101+ if flag .Name == "silent" {
102+ return nil // --silent is added later to all curl arguments so don't add here
103+ }
104+
105+ // if it's a curl flag, save the full name & value to pass as arguments later
106+ found := cflags .Lookup (flag .Name )
107+ if found != nil {
108+ if flag .Value .Type () == "bool" {
109+ cArgs = append (cArgs , "--" + flag .Name )
110+ } else {
111+ cArgs = append (cArgs , "--" + flag .Name )
112+ cArgs = append (cArgs , value )
113+ }
114+ }
115+
116+ return flags .Set (flag .Name , value )
117+ })
94118
95119 if help {
96120 fmt .Print (usageAndOptions ("Run curl against kubernetes pods" ))
@@ -223,21 +247,36 @@ func run(ctx context.Context) error {
223247 }
224248
225249 requestURL .Host = net .JoinHostPort ("localhost" , strconv .Itoa (int (localPort )))
226- options : = append (curlOptions ,
227- // The -s option is taken by -s,--server from the default kubectl
228- // configuration. Force --silent because we don't really need to
229- // print the dynamic progress view for the scenarios in which this
230- // plugin is useful for.
231- curl . Silent ( true ),
232- )
233- cmd := curl . Command (ctx , requestURL . String (), options ... )
250+ cArgs = append (cArgs , requestURL . String ())
251+ // The -s option is taken by -s,--server from the default kubectl
252+ // configuration. Force --silent because we don't really need to
253+ // print the dynamic progress view for the scenarios in which this
254+ // plugin is useful for.
255+ cArgs = append ( cArgs , "--silent" )
256+
257+ cmd := exec . CommandContext (ctx , "curl" , cArgs ... )
234258 cmd .Stdin = os .Stdin
235259 cmd .Stdout = os .Stdout
236260 cmd .Stderr = os .Stderr
237- log .Printf ("curl %s" , strings . Join (cmd .Args [1 :], " \n \t " ))
261+ log .Printf ("curl %s" , prettyArgs (cmd .Args [1 :]))
238262 return cmd .Run ()
239263}
240264
265+ func prettyArgs (slice []string ) string {
266+ out := ""
267+ for i , s := range slice {
268+ if strings .Contains (s , " " ) {
269+ out += fmt .Sprintf ("%q" , s ) // add quotes when known
270+ } else {
271+ out += s
272+ }
273+ if i != len (slice )- 1 {
274+ out += " " // separate elements with space
275+ }
276+ }
277+ return out
278+ }
279+
241280func selectContainerPort (pod * corev1.Pod , containerName , portName string ) (selectedContainerName string , selectedContainerPort corev1.ContainerPort , err error ) {
242281 for _ , container := range pod .Spec .Containers {
243282 if containerName != "" && container .Name != containerName {
@@ -248,7 +287,8 @@ func selectContainerPort(pod *corev1.Pod, containerName, portName string) (selec
248287 continue
249288 }
250289 if selectedContainerPort .Name != "" {
251- err = fmt .Errorf ("pod %[1]s has multiple containers with a %[2]s port, use kubectl %[1]s [container] to specify which one to profile" , pod .Name , portName )
290+ err = fmt .Errorf ("pod %[1]s has multiple containers with a %[2]s port, use kubectl %[1]s [container] to specify which one to profile" ,
291+ pod .Name , portName )
252292 return
253293 }
254294 selectedContainerName = container .Name
0 commit comments