list.go 2.2 KB

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