From b096bf9ad92d1fd772e74f5be39b7694923b8f3b Mon Sep 17 00:00:00 2001 From: aca Date: Sat, 15 Feb 2020 13:19:05 +0900 Subject: [PATCH] Add label selector for plugin --- cmd/plugin/commands/backends/backends.go | 10 +++--- cmd/plugin/commands/certs/certs.go | 9 ++--- cmd/plugin/commands/conf/conf.go | 9 ++--- cmd/plugin/commands/exec/exec.go | 9 ++--- cmd/plugin/commands/general/general.go | 9 ++--- cmd/plugin/commands/logs/logs.go | 13 +++---- cmd/plugin/commands/ssh/ssh.go | 9 ++--- cmd/plugin/request/request.go | 44 +++++++++++++++++++++++- cmd/plugin/util/util.go | 7 ++++ 9 files changed, 86 insertions(+), 33 deletions(-) diff --git a/cmd/plugin/commands/backends/backends.go b/cmd/plugin/commands/backends/backends.go index 778249a13..341c62a9c 100644 --- a/cmd/plugin/commands/backends/backends.go +++ b/cmd/plugin/commands/backends/backends.go @@ -30,7 +30,7 @@ import ( // CreateCommand creates and returns this cobra subcommand func CreateCommand(flags *genericclioptions.ConfigFlags) *cobra.Command { - var pod, deployment *string + var pod, deployment, selector *string cmd := &cobra.Command{ Use: "backends", Short: "Inspect the dynamic backend information of an ingress-nginx instance", @@ -47,20 +47,22 @@ func CreateCommand(flags *genericclioptions.ConfigFlags) *cobra.Command { return fmt.Errorf("--list and --backend cannot both be specified") } - util.PrintError(backends(flags, *pod, *deployment, backend, onlyList)) + util.PrintError(backends(flags, *pod, *deployment, *selector, backend, onlyList)) return nil }, } pod = util.AddPodFlag(cmd) deployment = util.AddDeploymentFlag(cmd) + selector = util.AddSelectorFlag(cmd) + cmd.Flags().String("backend", "", "Output only the information for the given backend") cmd.Flags().Bool("list", false, "Output a newline-separated list of backend names") return cmd } -func backends(flags *genericclioptions.ConfigFlags, podName string, deployment string, backend string, onlyList bool) error { +func backends(flags *genericclioptions.ConfigFlags, podName string, deployment string, selector string, backend string, onlyList bool) error { var command []string if onlyList { command = []string{"/dbg", "backends", "list"} @@ -70,7 +72,7 @@ func backends(flags *genericclioptions.ConfigFlags, podName string, deployment s command = []string{"/dbg", "backends", "all"} } - pod, err := request.ChoosePod(flags, podName, deployment) + pod, err := request.ChoosePod(flags, podName, deployment, selector) if err != nil { return err } diff --git a/cmd/plugin/commands/certs/certs.go b/cmd/plugin/commands/certs/certs.go index b16dd8f11..07fd08ad3 100644 --- a/cmd/plugin/commands/certs/certs.go +++ b/cmd/plugin/commands/certs/certs.go @@ -30,7 +30,7 @@ import ( // CreateCommand creates and returns this cobra subcommand func CreateCommand(flags *genericclioptions.ConfigFlags) *cobra.Command { - var pod, deployment *string + var pod, deployment, selector *string cmd := &cobra.Command{ Use: "certs", Short: "Output the certificate data stored in an ingress-nginx pod", @@ -40,7 +40,7 @@ func CreateCommand(flags *genericclioptions.ConfigFlags) *cobra.Command { return err } - util.PrintError(certs(flags, *pod, *deployment, host)) + util.PrintError(certs(flags, *pod, *deployment, *selector, host)) return nil }, } @@ -49,14 +49,15 @@ func CreateCommand(flags *genericclioptions.ConfigFlags) *cobra.Command { cobra.MarkFlagRequired(cmd.Flags(), "host") pod = util.AddPodFlag(cmd) deployment = util.AddDeploymentFlag(cmd) + selector = util.AddSelectorFlag(cmd) return cmd } -func certs(flags *genericclioptions.ConfigFlags, podName string, deployment string, host string) error { +func certs(flags *genericclioptions.ConfigFlags, podName string, deployment string, selector string, host string) error { command := []string{"/dbg", "certs", "get", host} - pod, err := request.ChoosePod(flags, podName, deployment) + pod, err := request.ChoosePod(flags, podName, deployment, selector) if err != nil { return err } diff --git a/cmd/plugin/commands/conf/conf.go b/cmd/plugin/commands/conf/conf.go index 51c308493..5caa2a649 100644 --- a/cmd/plugin/commands/conf/conf.go +++ b/cmd/plugin/commands/conf/conf.go @@ -32,7 +32,7 @@ import ( // CreateCommand creates and returns this cobra subcommand func CreateCommand(flags *genericclioptions.ConfigFlags) *cobra.Command { - var pod, deployment *string + var pod, deployment, selector *string cmd := &cobra.Command{ Use: "conf", Short: "Inspect the generated nginx.conf", @@ -42,19 +42,20 @@ func CreateCommand(flags *genericclioptions.ConfigFlags) *cobra.Command { return err } - util.PrintError(conf(flags, host, *pod, *deployment)) + util.PrintError(conf(flags, host, *pod, *deployment, *selector)) return nil }, } cmd.Flags().String("host", "", "Print just the server block with this hostname") pod = util.AddPodFlag(cmd) deployment = util.AddDeploymentFlag(cmd) + selector = util.AddSelectorFlag(cmd) return cmd } -func conf(flags *genericclioptions.ConfigFlags, host string, podName string, deployment string) error { - pod, err := request.ChoosePod(flags, podName, deployment) +func conf(flags *genericclioptions.ConfigFlags, host string, podName string, deployment string, selector string) error { + pod, err := request.ChoosePod(flags, podName, deployment, selector) if err != nil { return err } diff --git a/cmd/plugin/commands/exec/exec.go b/cmd/plugin/commands/exec/exec.go index 05f056d2e..5f1a31913 100644 --- a/cmd/plugin/commands/exec/exec.go +++ b/cmd/plugin/commands/exec/exec.go @@ -29,18 +29,19 @@ import ( // CreateCommand creates and returns this cobra subcommand func CreateCommand(flags *genericclioptions.ConfigFlags) *cobra.Command { opts := execFlags{} - var pod, deployment *string + var pod, deployment, selector *string cmd := &cobra.Command{ Use: "exec", Short: "Execute a command inside an ingress-nginx pod", RunE: func(cmd *cobra.Command, args []string) error { - util.PrintError(exec(flags, *pod, *deployment, args, opts)) + util.PrintError(exec(flags, *pod, *deployment, *selector, args, opts)) return nil }, } pod = util.AddPodFlag(cmd) deployment = util.AddDeploymentFlag(cmd) + selector = util.AddSelectorFlag(cmd) cmd.Flags().BoolVarP(&opts.TTY, "tty", "t", false, "Stdin is a TTY") cmd.Flags().BoolVarP(&opts.Stdin, "stdin", "i", false, "Pass stdin to the container") @@ -52,8 +53,8 @@ type execFlags struct { Stdin bool } -func exec(flags *genericclioptions.ConfigFlags, podName string, deployment string, cmd []string, opts execFlags) error { - pod, err := request.ChoosePod(flags, podName, deployment) +func exec(flags *genericclioptions.ConfigFlags, podName string, deployment string, selector string, cmd []string, opts execFlags) error { + pod, err := request.ChoosePod(flags, podName, deployment, selector) if err != nil { return err } diff --git a/cmd/plugin/commands/general/general.go b/cmd/plugin/commands/general/general.go index 182681001..44e02ca88 100644 --- a/cmd/plugin/commands/general/general.go +++ b/cmd/plugin/commands/general/general.go @@ -30,23 +30,24 @@ import ( // CreateCommand creates and returns this cobra subcommand func CreateCommand(flags *genericclioptions.ConfigFlags) *cobra.Command { - var pod, deployment *string + var pod, deployment, selector *string cmd := &cobra.Command{ Use: "general", Short: "Inspect the other dynamic ingress-nginx information", RunE: func(cmd *cobra.Command, args []string) error { - util.PrintError(general(flags, *pod, *deployment)) + util.PrintError(general(flags, *pod, *deployment, *selector)) return nil }, } pod = util.AddPodFlag(cmd) deployment = util.AddDeploymentFlag(cmd) + selector = util.AddSelectorFlag(cmd) return cmd } -func general(flags *genericclioptions.ConfigFlags, podName string, deployment string) error { - pod, err := request.ChoosePod(flags, podName, deployment) +func general(flags *genericclioptions.ConfigFlags, podName string, deployment string, selector string) error { + pod, err := request.ChoosePod(flags, podName, deployment, selector) if err != nil { return err } diff --git a/cmd/plugin/commands/logs/logs.go b/cmd/plugin/commands/logs/logs.go index 81e18e7d8..55cd008dc 100644 --- a/cmd/plugin/commands/logs/logs.go +++ b/cmd/plugin/commands/logs/logs.go @@ -31,18 +31,19 @@ import ( // CreateCommand creates and returns this cobra subcommand func CreateCommand(flags *genericclioptions.ConfigFlags) *cobra.Command { o := logsFlags{} - var pod, deployment *string + var pod, deployment, selector *string cmd := &cobra.Command{ Use: "logs", Short: "Get the kubernetes logs for an ingress-nginx pod", RunE: func(cmd *cobra.Command, args []string) error { - util.PrintError(logs(flags, *pod, *deployment, o)) + util.PrintError(logs(flags, *pod, *deployment, *selector, o)) return nil }, } pod = util.AddPodFlag(cmd) deployment = util.AddDeploymentFlag(cmd) + selector = util.AddSelectorFlag(cmd) cmd.Flags().BoolVarP(&o.Follow, "follow", "f", o.Follow, "Specify if the logs should be streamed.") cmd.Flags().BoolVar(&o.Timestamps, "timestamps", o.Timestamps, "Include timestamps on each line in the log output") @@ -51,7 +52,6 @@ func CreateCommand(flags *genericclioptions.ConfigFlags) *cobra.Command { cmd.Flags().Int64Var(&o.Tail, "tail", o.Tail, "Lines of recent log file to display. Defaults to -1 with no selector, showing all log lines otherwise 10, if a selector is provided.") cmd.Flags().StringVar(&o.SinceTime, "since-time", o.SinceTime, "Only return logs after a specific date (RFC3339). Defaults to all logs. Only one of since-time / since may be used.") cmd.Flags().StringVar(&o.SinceSeconds, "since", o.SinceSeconds, "Only return logs newer than a relative duration like 5s, 2m, or 3h. Defaults to all logs. Only one of since-time / since may be used.") - cmd.Flags().StringVarP(&o.Selector, "selector", "l", o.Selector, "Selector (label query) to filter on.") return cmd } @@ -90,15 +90,12 @@ func (o *logsFlags) toStrings() []string { if o.Tail != 0 { r = append(r, "--tail", fmt.Sprintf("%v", o.Tail)) } - if o.Selector != "" { - r = append(r, "--selector", o.Selector) - } return r } -func logs(flags *genericclioptions.ConfigFlags, podName string, deployment string, opts logsFlags) error { - pod, err := request.ChoosePod(flags, podName, deployment) +func logs(flags *genericclioptions.ConfigFlags, podName string, deployment string, selector string, opts logsFlags) error { + pod, err := request.ChoosePod(flags, podName, deployment, selector) if err != nil { return err } diff --git a/cmd/plugin/commands/ssh/ssh.go b/cmd/plugin/commands/ssh/ssh.go index 77fcd9940..5e8b49fac 100644 --- a/cmd/plugin/commands/ssh/ssh.go +++ b/cmd/plugin/commands/ssh/ssh.go @@ -28,23 +28,24 @@ import ( // CreateCommand creates and returns this cobra subcommand func CreateCommand(flags *genericclioptions.ConfigFlags) *cobra.Command { - var pod, deployment *string + var pod, deployment, selector *string cmd := &cobra.Command{ Use: "ssh", Short: "ssh into a running ingress-nginx pod", RunE: func(cmd *cobra.Command, args []string) error { - util.PrintError(ssh(flags, *pod, *deployment)) + util.PrintError(ssh(flags, *pod, *deployment, *selector)) return nil }, } pod = util.AddPodFlag(cmd) deployment = util.AddDeploymentFlag(cmd) + selector = util.AddSelectorFlag(cmd) return cmd } -func ssh(flags *genericclioptions.ConfigFlags, podName string, deployment string) error { - pod, err := request.ChoosePod(flags, podName, deployment) +func ssh(flags *genericclioptions.ConfigFlags, podName string, deployment string, selector string) error { + pod, err := request.ChoosePod(flags, podName, deployment, selector) if err != nil { return err } diff --git a/cmd/plugin/request/request.go b/cmd/plugin/request/request.go index e1223a8a2..391611ce0 100644 --- a/cmd/plugin/request/request.go +++ b/cmd/plugin/request/request.go @@ -32,11 +32,15 @@ import ( ) // ChoosePod finds a pod either by deployment or by name -func ChoosePod(flags *genericclioptions.ConfigFlags, podName string, deployment string) (apiv1.Pod, error) { +func ChoosePod(flags *genericclioptions.ConfigFlags, podName string, deployment string, selector string) (apiv1.Pod, error) { if podName != "" { return GetNamedPod(flags, podName) } + if selector != "" { + return GetLabeledPod(flags, selector) + } + return GetDeploymentPod(flags, deployment) } @@ -70,6 +74,20 @@ func GetDeploymentPod(flags *genericclioptions.ConfigFlags, deployment string) ( return ings[0], nil } +// GetDeploymentPod finds a pod from a given deployment +func GetLabeledPod(flags *genericclioptions.ConfigFlags, label string) (apiv1.Pod, error) { + ings, err := getLabeledPods(flags, label) + if err != nil { + return apiv1.Pod{}, err + } + + if len(ings) == 0 { + return apiv1.Pod{}, fmt.Errorf("no pods for label selector %v found in namespace %v", label, util.GetNamespace(flags)) + } + + return ings[0], nil +} + // GetDeployments returns an array of Deployments func GetDeployments(flags *genericclioptions.ConfigFlags, namespace string) ([]appsv1.Deployment, error) { rawConfig, err := flags.ToRESTConfig() @@ -246,6 +264,30 @@ func getPods(flags *genericclioptions.ConfigFlags) ([]apiv1.Pod, error) { return pods.Items, nil } +func getLabeledPods(flags *genericclioptions.ConfigFlags, label string) ([]apiv1.Pod, error) { + namespace := util.GetNamespace(flags) + + rawConfig, err := flags.ToRESTConfig() + if err != nil { + return make([]apiv1.Pod, 0), err + } + + api, err := corev1.NewForConfig(rawConfig) + if err != nil { + return make([]apiv1.Pod, 0), err + } + + pods, err := api.Pods(namespace).List(metav1.ListOptions{ + LabelSelector: label, + }) + + if err != nil { + return make([]apiv1.Pod, 0), err + } + + return pods.Items, nil +} + func getDeploymentPods(flags *genericclioptions.ConfigFlags, deployment string) ([]apiv1.Pod, error) { pods, err := getPods(flags) if err != nil { diff --git a/cmd/plugin/util/util.go b/cmd/plugin/util/util.go index dca97a1d4..33918deb7 100644 --- a/cmd/plugin/util/util.go +++ b/cmd/plugin/util/util.go @@ -120,6 +120,13 @@ func AddDeploymentFlag(cmd *cobra.Command) *string { return &v } +// AddSelectorFlag adds a --selector flag to a cobra command +func AddSelectorFlag(cmd *cobra.Command) *string { + v := "" + cmd.Flags().StringVarP(&v, "selector", "l", "", "Selector (label query) of the ingress-nginx pod") + return &v +} + // GetNamespace takes a set of kubectl flag values and returns the namespace we should be operating in func GetNamespace(flags *genericclioptions.ConfigFlags) string { namespace, _, err := flags.ToRawKubeConfigLoader().Namespace()