github.com/fabiokung/docker@v0.11.2-0.20170222101415-4534dcd49497/cli/command/service/list.go (about)

     1  package service
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/docker/docker/api/types"
     7  	"github.com/docker/docker/api/types/filters"
     8  	"github.com/docker/docker/api/types/swarm"
     9  	"github.com/docker/docker/cli"
    10  	"github.com/docker/docker/cli/command"
    11  	"github.com/docker/docker/cli/command/formatter"
    12  	"github.com/docker/docker/opts"
    13  	"github.com/spf13/cobra"
    14  	"golang.org/x/net/context"
    15  )
    16  
    17  type listOptions struct {
    18  	quiet  bool
    19  	format string
    20  	filter opts.FilterOpt
    21  }
    22  
    23  func newListCommand(dockerCli *command.DockerCli) *cobra.Command {
    24  	opts := listOptions{filter: opts.NewFilterOpt()}
    25  
    26  	cmd := &cobra.Command{
    27  		Use:     "ls [OPTIONS]",
    28  		Aliases: []string{"list"},
    29  		Short:   "List services",
    30  		Args:    cli.NoArgs,
    31  		RunE: func(cmd *cobra.Command, args []string) error {
    32  			return runList(dockerCli, opts)
    33  		},
    34  	}
    35  
    36  	flags := cmd.Flags()
    37  	flags.BoolVarP(&opts.quiet, "quiet", "q", false, "Only display IDs")
    38  	flags.StringVar(&opts.format, "format", "", "Pretty-print services using a Go template")
    39  	flags.VarP(&opts.filter, "filter", "f", "Filter output based on conditions provided")
    40  
    41  	return cmd
    42  }
    43  
    44  func runList(dockerCli *command.DockerCli, opts listOptions) error {
    45  	ctx := context.Background()
    46  	client := dockerCli.Client()
    47  
    48  	services, err := client.ServiceList(ctx, types.ServiceListOptions{Filters: opts.filter.Value()})
    49  	if err != nil {
    50  		return err
    51  	}
    52  
    53  	info := map[string]formatter.ServiceListInfo{}
    54  	if len(services) > 0 && !opts.quiet {
    55  		// only non-empty services and not quiet, should we call TaskList and NodeList api
    56  		taskFilter := filters.NewArgs()
    57  		for _, service := range services {
    58  			taskFilter.Add("service", service.ID)
    59  		}
    60  
    61  		tasks, err := client.TaskList(ctx, types.TaskListOptions{Filters: taskFilter})
    62  		if err != nil {
    63  			return err
    64  		}
    65  
    66  		nodes, err := client.NodeList(ctx, types.NodeListOptions{})
    67  		if err != nil {
    68  			return err
    69  		}
    70  
    71  		info = GetServicesStatus(services, nodes, tasks)
    72  	}
    73  
    74  	format := opts.format
    75  	if len(format) == 0 {
    76  		if len(dockerCli.ConfigFile().ServicesFormat) > 0 && !opts.quiet {
    77  			format = dockerCli.ConfigFile().ServicesFormat
    78  		} else {
    79  			format = formatter.TableFormatKey
    80  		}
    81  	}
    82  
    83  	servicesCtx := formatter.Context{
    84  		Output: dockerCli.Out(),
    85  		Format: formatter.NewServiceListFormat(format, opts.quiet),
    86  	}
    87  	return formatter.ServiceListWrite(servicesCtx, services, info)
    88  }
    89  
    90  // GetServicesStatus returns a map of mode and replicas
    91  func GetServicesStatus(services []swarm.Service, nodes []swarm.Node, tasks []swarm.Task) map[string]formatter.ServiceListInfo {
    92  	running := map[string]int{}
    93  	tasksNoShutdown := map[string]int{}
    94  
    95  	activeNodes := make(map[string]struct{})
    96  	for _, n := range nodes {
    97  		if n.Status.State != swarm.NodeStateDown {
    98  			activeNodes[n.ID] = struct{}{}
    99  		}
   100  	}
   101  
   102  	for _, task := range tasks {
   103  		if task.DesiredState != swarm.TaskStateShutdown {
   104  			tasksNoShutdown[task.ServiceID]++
   105  		}
   106  
   107  		if _, nodeActive := activeNodes[task.NodeID]; nodeActive && task.Status.State == swarm.TaskStateRunning {
   108  			running[task.ServiceID]++
   109  		}
   110  	}
   111  
   112  	info := map[string]formatter.ServiceListInfo{}
   113  	for _, service := range services {
   114  		info[service.ID] = formatter.ServiceListInfo{}
   115  		if service.Spec.Mode.Replicated != nil && service.Spec.Mode.Replicated.Replicas != nil {
   116  			info[service.ID] = formatter.ServiceListInfo{
   117  				Mode:     "replicated",
   118  				Replicas: fmt.Sprintf("%d/%d", running[service.ID], *service.Spec.Mode.Replicated.Replicas),
   119  			}
   120  		} else if service.Spec.Mode.Global != nil {
   121  			info[service.ID] = formatter.ServiceListInfo{
   122  				Mode:     "global",
   123  				Replicas: fmt.Sprintf("%d/%d", running[service.ID], tasksNoShutdown[service.ID]),
   124  			}
   125  		}
   126  	}
   127  	return info
   128  }