1
0
Fork 0
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:
allencloud 2016-07-02 10:12:16 +08:00
parent f49fdb9d0b
commit 4b21b411ec
5 changed files with 124 additions and 16 deletions

View file

@ -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)
} }

View file

@ -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

View 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
}

View file

@ -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.

View file

@ -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")
}