github.com/fabiokung/docker@v0.11.2-0.20170222101415-4534dcd49497/cli/command/stack/list.go (about) 1 package stack 2 3 import ( 4 "fmt" 5 "io" 6 "sort" 7 "strconv" 8 "text/tabwriter" 9 10 "github.com/docker/docker/api/types" 11 "github.com/docker/docker/cli" 12 "github.com/docker/docker/cli/command" 13 "github.com/docker/docker/cli/compose/convert" 14 "github.com/docker/docker/client" 15 "github.com/spf13/cobra" 16 "golang.org/x/net/context" 17 ) 18 19 const ( 20 listItemFmt = "%s\t%s\n" 21 ) 22 23 type listOptions struct { 24 } 25 26 func newListCommand(dockerCli *command.DockerCli) *cobra.Command { 27 opts := listOptions{} 28 29 cmd := &cobra.Command{ 30 Use: "ls", 31 Aliases: []string{"list"}, 32 Short: "List stacks", 33 Args: cli.NoArgs, 34 RunE: func(cmd *cobra.Command, args []string) error { 35 return runList(dockerCli, opts) 36 }, 37 } 38 39 return cmd 40 } 41 42 func runList(dockerCli *command.DockerCli, opts listOptions) error { 43 client := dockerCli.Client() 44 ctx := context.Background() 45 46 stacks, err := getStacks(ctx, client) 47 if err != nil { 48 return err 49 } 50 51 out := dockerCli.Out() 52 printTable(out, stacks) 53 return nil 54 } 55 56 type byName []*stack 57 58 func (n byName) Len() int { return len(n) } 59 func (n byName) Swap(i, j int) { n[i], n[j] = n[j], n[i] } 60 func (n byName) Less(i, j int) bool { return n[i].Name < n[j].Name } 61 62 func printTable(out io.Writer, stacks []*stack) { 63 writer := tabwriter.NewWriter(out, 0, 4, 2, ' ', 0) 64 65 // Ignore flushing errors 66 defer writer.Flush() 67 68 sort.Sort(byName(stacks)) 69 70 fmt.Fprintf(writer, listItemFmt, "NAME", "SERVICES") 71 for _, stack := range stacks { 72 fmt.Fprintf( 73 writer, 74 listItemFmt, 75 stack.Name, 76 strconv.Itoa(stack.Services), 77 ) 78 } 79 } 80 81 type stack struct { 82 // Name is the name of the stack 83 Name string 84 // Services is the number of the services 85 Services int 86 } 87 88 func getStacks( 89 ctx context.Context, 90 apiclient client.APIClient, 91 ) ([]*stack, error) { 92 services, err := apiclient.ServiceList( 93 ctx, 94 types.ServiceListOptions{Filters: getAllStacksFilter()}) 95 if err != nil { 96 return nil, err 97 } 98 m := make(map[string]*stack, 0) 99 for _, service := range services { 100 labels := service.Spec.Labels 101 name, ok := labels[convert.LabelNamespace] 102 if !ok { 103 return nil, fmt.Errorf("cannot get label %s for service %s", 104 convert.LabelNamespace, service.ID) 105 } 106 ztack, ok := m[name] 107 if !ok { 108 m[name] = &stack{ 109 Name: name, 110 Services: 1, 111 } 112 } else { 113 ztack.Services++ 114 } 115 } 116 var stacks []*stack 117 for _, stack := range m { 118 stacks = append(stacks, stack) 119 } 120 return stacks, nil 121 }