mirror of
				https://github.com/moby/moby.git
				synced 2022-11-09 12:21:53 -05:00 
			
		
		
		
	add command docker stack services STACKNAME
				
					
				
			Signed-off-by: allencloud <allen.sun@daocloud.io>
This commit is contained in:
		
							parent
							
								
									f49fdb9d0b
								
							
						
					
					
						commit
						4b21b411ec
					
				
					 5 changed files with 124 additions and 16 deletions
				
			
		| 
						 | 
					@ -57,7 +57,7 @@ func runList(dockerCli *client.DockerCli, opts listOptions) error {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	out := dockerCli.Out()
 | 
						out := dockerCli.Out()
 | 
				
			||||||
	if opts.quiet {
 | 
						if opts.quiet {
 | 
				
			||||||
		printQuiet(out, services)
 | 
							PrintQuiet(out, services)
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		taskFilter := filters.NewArgs()
 | 
							taskFilter := filters.NewArgs()
 | 
				
			||||||
		for _, service := range services {
 | 
							for _, service := range services {
 | 
				
			||||||
| 
						 | 
					@ -73,25 +73,32 @@ func runList(dockerCli *client.DockerCli, opts listOptions) error {
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		activeNodes := make(map[string]struct{})
 | 
					 | 
				
			||||||
		for _, n := range nodes {
 | 
					 | 
				
			||||||
			if n.Status.State == swarm.NodeStateReady {
 | 
					 | 
				
			||||||
				activeNodes[n.ID] = struct{}{}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		running := map[string]int{}
 | 
							PrintNotQuiet(out, services, nodes, tasks)
 | 
				
			||||||
		for _, task := range tasks {
 | 
					 | 
				
			||||||
			if _, nodeActive := activeNodes[task.NodeID]; nodeActive && task.Status.State == "running" {
 | 
					 | 
				
			||||||
				running[task.ServiceID]++
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		printTable(out, services, running)
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// PrintNotQuiet shows service list in a non-quiet way.
 | 
				
			||||||
 | 
					// Besides this, command `docker stack services xxx` will call this, too.
 | 
				
			||||||
 | 
					func PrintNotQuiet(out io.Writer, services []swarm.Service, nodes []swarm.Node, tasks []swarm.Task) {
 | 
				
			||||||
 | 
						activeNodes := make(map[string]struct{})
 | 
				
			||||||
 | 
						for _, n := range nodes {
 | 
				
			||||||
 | 
							if n.Status.State == swarm.NodeStateReady {
 | 
				
			||||||
 | 
								activeNodes[n.ID] = struct{}{}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						running := map[string]int{}
 | 
				
			||||||
 | 
						for _, task := range tasks {
 | 
				
			||||||
 | 
							if _, nodeActive := activeNodes[task.NodeID]; nodeActive && task.Status.State == "running" {
 | 
				
			||||||
 | 
								running[task.ServiceID]++
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						printTable(out, services, running)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func printTable(out io.Writer, services []swarm.Service, running map[string]int) {
 | 
					func printTable(out io.Writer, services []swarm.Service, running map[string]int) {
 | 
				
			||||||
	writer := tabwriter.NewWriter(out, 0, 4, 2, ' ', 0)
 | 
						writer := tabwriter.NewWriter(out, 0, 4, 2, ' ', 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -117,7 +124,9 @@ func printTable(out io.Writer, services []swarm.Service, running map[string]int)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func printQuiet(out io.Writer, services []swarm.Service) {
 | 
					// PrintQuiet shows service list in a quiet way.
 | 
				
			||||||
 | 
					// Besides this, command `docker stack services xxx` will call this, too.
 | 
				
			||||||
 | 
					func PrintQuiet(out io.Writer, services []swarm.Service) {
 | 
				
			||||||
	for _, service := range services {
 | 
						for _, service := range services {
 | 
				
			||||||
		fmt.Fprintln(out, service.ID)
 | 
							fmt.Fprintln(out, service.ID)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,6 +24,7 @@ func NewStackCommand(dockerCli *client.DockerCli) *cobra.Command {
 | 
				
			||||||
		newConfigCommand(dockerCli),
 | 
							newConfigCommand(dockerCli),
 | 
				
			||||||
		newDeployCommand(dockerCli),
 | 
							newDeployCommand(dockerCli),
 | 
				
			||||||
		newRemoveCommand(dockerCli),
 | 
							newRemoveCommand(dockerCli),
 | 
				
			||||||
 | 
							newServicesCommand(dockerCli),
 | 
				
			||||||
		newTasksCommand(dockerCli),
 | 
							newTasksCommand(dockerCli),
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
	return cmd
 | 
						return cmd
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										87
									
								
								api/client/stack/services.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								api/client/stack/services.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,87 @@
 | 
				
			||||||
 | 
					// +build experimental
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package stack
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"golang.org/x/net/context"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/docker/docker/api/client"
 | 
				
			||||||
 | 
						"github.com/docker/docker/api/client/service"
 | 
				
			||||||
 | 
						"github.com/docker/docker/cli"
 | 
				
			||||||
 | 
						"github.com/docker/docker/opts"
 | 
				
			||||||
 | 
						"github.com/docker/engine-api/types"
 | 
				
			||||||
 | 
						"github.com/docker/engine-api/types/filters"
 | 
				
			||||||
 | 
						"github.com/spf13/cobra"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						listItemFmt = "%s\t%s\t%s\t%s\t%s\n"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type servicesOptions struct {
 | 
				
			||||||
 | 
						quiet     bool
 | 
				
			||||||
 | 
						filter    opts.FilterOpt
 | 
				
			||||||
 | 
						namespace string
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func newServicesCommand(dockerCli *client.DockerCli) *cobra.Command {
 | 
				
			||||||
 | 
						opts := servicesOptions{filter: opts.NewFilterOpt()}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cmd := &cobra.Command{
 | 
				
			||||||
 | 
							Use:   "services [OPTIONS] STACK",
 | 
				
			||||||
 | 
							Short: "List the services in the stack",
 | 
				
			||||||
 | 
							Args:  cli.ExactArgs(1),
 | 
				
			||||||
 | 
							RunE: func(cmd *cobra.Command, args []string) error {
 | 
				
			||||||
 | 
								opts.namespace = args[0]
 | 
				
			||||||
 | 
								return runServices(dockerCli, opts)
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						flags := cmd.Flags()
 | 
				
			||||||
 | 
						flags.BoolVarP(&opts.quiet, "quiet", "q", false, "Only display IDs")
 | 
				
			||||||
 | 
						flags.VarP(&opts.filter, "filter", "f", "Filter output based on conditions provided")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return cmd
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func runServices(dockerCli *client.DockerCli, opts servicesOptions) error {
 | 
				
			||||||
 | 
						ctx := context.Background()
 | 
				
			||||||
 | 
						client := dockerCli.Client()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						filter := opts.filter.Value()
 | 
				
			||||||
 | 
						filter.Add("label", labelNamespace+"="+opts.namespace)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						services, err := client.ServiceList(ctx, types.ServiceListOptions{Filter: filter})
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						out := dockerCli.Out()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// if no services in this stack, print message and exit 0
 | 
				
			||||||
 | 
						if len(services) == 0 {
 | 
				
			||||||
 | 
							fmt.Fprintf(out, "Nothing found in stack: %s\n", opts.namespace)
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if opts.quiet {
 | 
				
			||||||
 | 
							service.PrintQuiet(out, services)
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							taskFilter := filters.NewArgs()
 | 
				
			||||||
 | 
							for _, service := range services {
 | 
				
			||||||
 | 
								taskFilter.Add("service", service.ID)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							tasks, err := client.TaskList(ctx, types.TaskListOptions{Filter: taskFilter})
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							nodes, err := client.NodeList(ctx, types.NodeListOptions{})
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							service.PrintNotQuiet(out, services, nodes, tasks)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -93,6 +93,7 @@ Commands:
 | 
				
			||||||
  config      Print the stack configuration
 | 
					  config      Print the stack configuration
 | 
				
			||||||
  deploy      Create and update a stack
 | 
					  deploy      Create and update a stack
 | 
				
			||||||
  rm          Remove the stack
 | 
					  rm          Remove the stack
 | 
				
			||||||
 | 
					  services    List the services in the stack
 | 
				
			||||||
  tasks       List the tasks in the stack
 | 
					  tasks       List the tasks in the stack
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Run 'docker stack COMMAND --help' for more information on a command.
 | 
					Run 'docker stack COMMAND --help' for more information on a command.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,3 +26,13 @@ func (s *DockerSwarmSuite) TestStackTasks(c *check.C) {
 | 
				
			||||||
	c.Assert(err, checker.IsNil)
 | 
						c.Assert(err, checker.IsNil)
 | 
				
			||||||
	c.Assert(out, check.Equals, "Nothing found in stack: UNKNOWN_STACK\n")
 | 
						c.Assert(out, check.Equals, "Nothing found in stack: UNKNOWN_STACK\n")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (s *DockerSwarmSuite) TestStackServices(c *check.C) {
 | 
				
			||||||
 | 
						d := s.AddDaemon(c, true, true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						stackArgs := append([]string{"services", "UNKNOWN_STACK"})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						out, err := d.Cmd("stack", stackArgs...)
 | 
				
			||||||
 | 
						c.Assert(err, checker.IsNil)
 | 
				
			||||||
 | 
						c.Assert(out, check.Equals, "Nothing found in stack: UNKNOWN_STACK\n")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue