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  }