Support multiple namespaces for docker stack ls

Signed-off-by: Mathieu Champlon <mathieu.champlon@docker.com>
This commit is contained in:
Mathieu Champlon 2018-04-26 11:13:14 +02:00
parent 4d947de292
commit 84241cc393
9 changed files with 64 additions and 15 deletions

View File

@ -31,9 +31,6 @@ func NewStackCommand(dockerCli command.Cli) *cobra.Command {
newServicesCommand(dockerCli), newServicesCommand(dockerCli),
) )
flags := cmd.PersistentFlags() flags := cmd.PersistentFlags()
flags.String("namespace", "", "Kubernetes namespace to use")
flags.SetAnnotation("namespace", "kubernetes", nil)
flags.SetAnnotation("namespace", "experimentalCLI", nil)
flags.String("kubeconfig", "", "Kubernetes config file") flags.String("kubeconfig", "", "Kubernetes config file")
flags.SetAnnotation("kubeconfig", "kubernetes", nil) flags.SetAnnotation("kubeconfig", "kubernetes", nil)
flags.SetAnnotation("kubeconfig", "experimentalCLI", nil) flags.SetAnnotation("kubeconfig", "experimentalCLI", nil)

View File

@ -49,5 +49,6 @@ func newDeployCommand(dockerCli command.Cli) *cobra.Command {
`Query the registry to resolve image digest and supported platforms ("`+swarm.ResolveImageAlways+`"|"`+swarm.ResolveImageChanged+`"|"`+swarm.ResolveImageNever+`")`) `Query the registry to resolve image digest and supported platforms ("`+swarm.ResolveImageAlways+`"|"`+swarm.ResolveImageChanged+`"|"`+swarm.ResolveImageNever+`")`)
flags.SetAnnotation("resolve-image", "version", []string{"1.30"}) flags.SetAnnotation("resolve-image", "version", []string{"1.30"})
flags.SetAnnotation("resolve-image", "swarm", nil) flags.SetAnnotation("resolve-image", "swarm", nil)
kubernetes.AddNamespaceFlag(flags)
return cmd return cmd
} }

View File

@ -34,9 +34,15 @@ func NewOptions(flags *flag.FlagSet) Options {
return opts return opts
} }
// AddNamespaceFlag adds the namespace flag to the given flag set
func AddNamespaceFlag(flags *flag.FlagSet) {
flags.String("namespace", "", "Kubernetes namespace to use")
flags.SetAnnotation("namespace", "kubernetes", nil)
flags.SetAnnotation("namespace", "experimentalCLI", nil)
}
// WrapCli wraps command.Cli with kubernetes specifics // WrapCli wraps command.Cli with kubernetes specifics
func WrapCli(dockerCli command.Cli, opts Options) (*KubeCli, error) { func WrapCli(dockerCli command.Cli, opts Options) (*KubeCli, error) {
var err error
cli := &KubeCli{ cli := &KubeCli{
Cli: dockerCli, Cli: dockerCli,
} }

View File

@ -1,13 +1,25 @@
package kubernetes package kubernetes
import ( import (
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/formatter" "github.com/docker/cli/cli/command/formatter"
"github.com/docker/cli/cli/command/stack/options" "github.com/docker/cli/cli/command/stack/options"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
) )
// GetStacks lists the kubernetes stacks. // GetStacks lists the kubernetes stacks
func GetStacks(kubeCli *KubeCli, opts options.List) ([]*formatter.Stack, error) { func GetStacks(dockerCli command.Cli, opts options.List, kopts Options) ([]*formatter.Stack, error) {
kubeCli, err := WrapCli(dockerCli, kopts)
if err != nil {
return nil, err
}
if opts.AllNamespaces || len(opts.Namespaces) == 0 {
return getStacks(kubeCli, opts)
}
return getStacksWithNamespaces(kubeCli, opts)
}
func getStacks(kubeCli *KubeCli, opts options.List) ([]*formatter.Stack, error) {
composeClient, err := kubeCli.composeClient() composeClient, err := kubeCli.composeClient()
if err != nil { if err != nil {
return nil, err return nil, err
@ -31,3 +43,28 @@ func GetStacks(kubeCli *KubeCli, opts options.List) ([]*formatter.Stack, error)
} }
return formattedStacks, nil return formattedStacks, nil
} }
func getStacksWithNamespaces(kubeCli *KubeCli, opts options.List) ([]*formatter.Stack, error) {
stacks := []*formatter.Stack{}
for _, namespace := range removeDuplicates(opts.Namespaces) {
kubeCli.kubeNamespace = namespace
ss, err := getStacks(kubeCli, opts)
if err != nil {
return nil, err
}
stacks = append(stacks, ss...)
}
return stacks, nil
}
func removeDuplicates(namespaces []string) []string {
found := make(map[string]bool)
results := namespaces[:0]
for _, n := range namespaces {
if !found[n] {
results = append(results, n)
found[n] = true
}
}
return results
}

View File

@ -28,7 +28,10 @@ func newListCommand(dockerCli command.Cli) *cobra.Command {
flags := cmd.Flags() flags := cmd.Flags()
flags.StringVar(&opts.Format, "format", "", "Pretty-print stacks using a Go template") flags.StringVar(&opts.Format, "format", "", "Pretty-print stacks using a Go template")
flags.BoolVarP(&opts.AllNamespaces, "all-namespaces", "", false, "List stacks among all Kubernetes namespaces") flags.StringSliceVar(&opts.Namespaces, "namespace", []string{}, "Kubernetes namespaces to use")
flags.SetAnnotation("namespace", "kubernetes", nil)
flags.SetAnnotation("namespace", "experimentalCLI", nil)
flags.BoolVarP(&opts.AllNamespaces, "all-namespaces", "", false, "List stacks from all Kubernetes namespaces")
flags.SetAnnotation("all-namespaces", "kubernetes", nil) flags.SetAnnotation("all-namespaces", "kubernetes", nil)
flags.SetAnnotation("all-namespaces", "experimentalCLI", nil) flags.SetAnnotation("all-namespaces", "experimentalCLI", nil)
return cmd return cmd
@ -44,16 +47,16 @@ func runList(cmd *cobra.Command, dockerCli command.Cli, opts options.List) error
stacks = append(stacks, ss...) stacks = append(stacks, ss...)
} }
if dockerCli.ClientInfo().HasKubernetes() { if dockerCli.ClientInfo().HasKubernetes() {
kli, err := kubernetes.WrapCli(dockerCli, kubernetes.NewOptions(cmd.Flags())) ss, err := kubernetes.GetStacks(dockerCli, opts, kubernetes.NewOptions(cmd.Flags()))
if err != nil {
return err
}
ss, err := kubernetes.GetStacks(kli, opts)
if err != nil { if err != nil {
return err return err
} }
stacks = append(stacks, ss...) stacks = append(stacks, ss...)
} }
return format(dockerCli, opts, stacks)
}
func format(dockerCli command.Cli, opts options.List, stacks []*formatter.Stack) error {
format := opts.Format format := opts.Format
if format == "" || format == formatter.TableFormatKey { if format == "" || format == formatter.TableFormatKey {
format = formatter.SwarmStackTableFormat format = formatter.SwarmStackTableFormat
@ -66,7 +69,9 @@ func runList(cmd *cobra.Command, dockerCli command.Cli, opts options.List) error
Format: formatter.Format(format), Format: formatter.Format(format),
} }
sort.Slice(stacks, func(i, j int) bool { sort.Slice(stacks, func(i, j int) bool {
return sortorder.NaturalLess(stacks[i].Name, stacks[j].Name) return sortorder.NaturalLess(stacks[i].Name, stacks[j].Name) ||
!sortorder.NaturalLess(stacks[j].Name, stacks[i].Name) &&
sortorder.NaturalLess(stacks[j].Namespace, stacks[i].Namespace)
}) })
return formatter.StackWrite(stackCtx, stacks) return formatter.StackWrite(stackCtx, stacks)
} }

View File

@ -16,6 +16,7 @@ type Deploy struct {
type List struct { type List struct {
Format string Format string
AllNamespaces bool AllNamespaces bool
Namespaces []string
} }
// PS holds docker stack ps options // PS holds docker stack ps options

View File

@ -40,6 +40,6 @@ func newPsCommand(dockerCli command.Cli) *cobra.Command {
flags.SetAnnotation("filter", "swarm", nil) flags.SetAnnotation("filter", "swarm", nil)
flags.BoolVarP(&opts.Quiet, "quiet", "q", false, "Only display task IDs") flags.BoolVarP(&opts.Quiet, "quiet", "q", false, "Only display task IDs")
flags.StringVar(&opts.Format, "format", "", "Pretty-print tasks using a Go template") flags.StringVar(&opts.Format, "format", "", "Pretty-print tasks using a Go template")
kubernetes.AddNamespaceFlag(flags)
return cmd return cmd
} }

View File

@ -33,5 +33,7 @@ func newRemoveCommand(dockerCli command.Cli) *cobra.Command {
} }
}, },
} }
flags := cmd.Flags()
kubernetes.AddNamespaceFlag(flags)
return cmd return cmd
} }

View File

@ -38,6 +38,6 @@ func newServicesCommand(dockerCli command.Cli) *cobra.Command {
flags.StringVar(&opts.Format, "format", "", "Pretty-print services using a Go template") flags.StringVar(&opts.Format, "format", "", "Pretty-print services using a Go template")
flags.VarP(&opts.Filter, "filter", "f", "Filter output based on conditions provided") flags.VarP(&opts.Filter, "filter", "f", "Filter output based on conditions provided")
flags.SetAnnotation("filter", "swarm", nil) flags.SetAnnotation("filter", "swarm", nil)
kubernetes.AddNamespaceFlag(flags)
return cmd return cmd
} }