Преглед изворни кода

Migrate start command to cobra

Signed-off-by: Zhang Wei <zhangwei555@huawei.com>
Zhang Wei пре 9 година
родитељ
комит
4f3625a288
6 измењених фајлова са 184 додато и 167 уклоњено
  1. 0 1
      api/client/commands.go
  2. 152 0
      api/client/container/start.go
  3. 0 165
      api/client/start.go
  4. 31 0
      api/client/utils.go
  5. 1 0
      cli/cobraadaptor/adaptor.go
  6. 0 1
      cli/usage.go

+ 0 - 1
api/client/commands.go

@@ -36,7 +36,6 @@ func (cli *DockerCli) Command(name string) func(...string) error {
 		"restart":            cli.CmdRestart,
 		"rm":                 cli.CmdRm,
 		"save":               cli.CmdSave,
-		"start":              cli.CmdStart,
 		"stats":              cli.CmdStats,
 		"tag":                cli.CmdTag,
 		"top":                cli.CmdTop,

+ 152 - 0
api/client/container/start.go

@@ -0,0 +1,152 @@
+package container
+
+import (
+	"fmt"
+	"io"
+	"net/http/httputil"
+	"strings"
+
+	"golang.org/x/net/context"
+
+	"github.com/docker/docker/api/client"
+	"github.com/docker/docker/cli"
+	"github.com/docker/docker/pkg/promise"
+	"github.com/docker/docker/pkg/signal"
+	"github.com/docker/engine-api/types"
+	"github.com/spf13/cobra"
+)
+
+type startOptions struct {
+	attach     bool
+	openStdin  bool
+	detachKeys string
+
+	containers []string
+}
+
+// NewStartCommand creats a new cobra.Command for `docker start`
+func NewStartCommand(dockerCli *client.DockerCli) *cobra.Command {
+	var opts startOptions
+
+	cmd := &cobra.Command{
+		Use:   "start [OPTIONS] CONTAINER [CONTAINER...]",
+		Short: "Start one or more stopped containers",
+		Args:  cli.RequiresMinArgs(1),
+		RunE: func(cmd *cobra.Command, args []string) error {
+			opts.containers = args
+			return runStart(dockerCli, &opts)
+		},
+	}
+	cmd.SetFlagErrorFunc(flagErrorFunc)
+
+	flags := cmd.Flags()
+	flags.BoolVarP(&opts.attach, "attach", "a", false, "Attach STDOUT/STDERR and forward signals")
+	flags.BoolVarP(&opts.openStdin, "interactive", "i", false, "Attach container's STDIN")
+	flags.StringVar(&opts.detachKeys, "detach-keys", "", "Override the key sequence for detaching a container")
+	return cmd
+}
+
+func runStart(dockerCli *client.DockerCli, opts *startOptions) error {
+	ctx, cancelFun := context.WithCancel(context.Background())
+
+	if opts.attach || opts.openStdin {
+		// We're going to attach to a container.
+		// 1. Ensure we only have one container.
+		if len(opts.containers) > 1 {
+			return fmt.Errorf("You cannot start and attach multiple containers at once.")
+		}
+
+		// 2. Attach to the container.
+		container := opts.containers[0]
+		c, err := dockerCli.Client().ContainerInspect(ctx, container)
+		if err != nil {
+			return err
+		}
+
+		if !c.Config.Tty {
+			sigc := dockerCli.ForwardAllSignals(ctx, container)
+			defer signal.StopCatch(sigc)
+		}
+
+		if opts.detachKeys != "" {
+			dockerCli.ConfigFile().DetachKeys = opts.detachKeys
+		}
+
+		options := types.ContainerAttachOptions{
+			Stream:     true,
+			Stdin:      opts.openStdin && c.Config.OpenStdin,
+			Stdout:     true,
+			Stderr:     true,
+			DetachKeys: dockerCli.ConfigFile().DetachKeys,
+		}
+
+		var in io.ReadCloser
+
+		if options.Stdin {
+			in = dockerCli.In()
+		}
+
+		resp, errAttach := dockerCli.Client().ContainerAttach(ctx, container, options)
+		if errAttach != nil && errAttach != httputil.ErrPersistEOF {
+			// ContainerAttach return an ErrPersistEOF (connection closed)
+			// means server met an error and put it in Hijacked connection
+			// keep the error and read detailed error message from hijacked connection
+			return errAttach
+		}
+		defer resp.Close()
+		cErr := promise.Go(func() error {
+			errHijack := dockerCli.HoldHijackedConnection(ctx, c.Config.Tty, in, dockerCli.Out(), dockerCli.Err(), resp)
+			if errHijack == nil {
+				return errAttach
+			}
+			return errHijack
+		})
+
+		// 3. Start the container.
+		if err := dockerCli.Client().ContainerStart(ctx, container, types.ContainerStartOptions{}); err != nil {
+			cancelFun()
+			<-cErr
+			return err
+		}
+
+		// 4. Wait for attachment to break.
+		if c.Config.Tty && dockerCli.IsTerminalOut() {
+			if err := dockerCli.MonitorTtySize(ctx, container, false); err != nil {
+				fmt.Fprintf(dockerCli.Err(), "Error monitoring TTY size: %s\n", err)
+			}
+		}
+		if attchErr := <-cErr; attchErr != nil {
+			return attchErr
+		}
+		_, status, err := dockerCli.GetExitCode(ctx, container)
+		if err != nil {
+			return err
+		}
+		if status != 0 {
+			return cli.StatusError{StatusCode: status}
+		}
+	} else {
+		// We're not going to attach to anything.
+		// Start as many containers as we want.
+		return startContainersWithoutAttachments(dockerCli, ctx, opts.containers)
+	}
+
+	return nil
+}
+
+func startContainersWithoutAttachments(dockerCli *client.DockerCli, ctx context.Context, containers []string) error {
+	var failedContainers []string
+	for _, container := range containers {
+		if err := dockerCli.Client().ContainerStart(ctx, container, types.ContainerStartOptions{}); err != nil {
+			fmt.Fprintf(dockerCli.Err(), "%s\n", err)
+			failedContainers = append(failedContainers, container)
+		} else {
+			fmt.Fprintf(dockerCli.Out(), "%s\n", container)
+		}
+	}
+
+	if len(failedContainers) > 0 {
+		return fmt.Errorf("Error: failed to start containers: %v", strings.Join(failedContainers, ", "))
+	}
+	return nil
+}

+ 0 - 165
api/client/start.go

@@ -1,165 +0,0 @@
-package client
-
-import (
-	"fmt"
-	"io"
-	"net/http/httputil"
-	"os"
-	"strings"
-
-	"golang.org/x/net/context"
-
-	"github.com/Sirupsen/logrus"
-	Cli "github.com/docker/docker/cli"
-	flag "github.com/docker/docker/pkg/mflag"
-	"github.com/docker/docker/pkg/promise"
-	"github.com/docker/docker/pkg/signal"
-	"github.com/docker/engine-api/types"
-)
-
-// ForwardAllSignals forwards signals to the contianer
-// TODO: this can be unexported again once all container commands are under
-// api/client/container
-func (cli *DockerCli) ForwardAllSignals(ctx context.Context, cid string) chan os.Signal {
-	sigc := make(chan os.Signal, 128)
-	signal.CatchAll(sigc)
-	go func() {
-		for s := range sigc {
-			if s == signal.SIGCHLD || s == signal.SIGPIPE {
-				continue
-			}
-			var sig string
-			for sigStr, sigN := range signal.SignalMap {
-				if sigN == s {
-					sig = sigStr
-					break
-				}
-			}
-			if sig == "" {
-				fmt.Fprintf(cli.err, "Unsupported signal: %v. Discarding.\n", s)
-				continue
-			}
-
-			if err := cli.client.ContainerKill(ctx, cid, sig); err != nil {
-				logrus.Debugf("Error sending signal: %s", err)
-			}
-		}
-	}()
-	return sigc
-}
-
-// CmdStart starts one or more containers.
-//
-// Usage: docker start [OPTIONS] CONTAINER [CONTAINER...]
-func (cli *DockerCli) CmdStart(args ...string) error {
-	cmd := Cli.Subcmd("start", []string{"CONTAINER [CONTAINER...]"}, Cli.DockerCommands["start"].Description, true)
-	attach := cmd.Bool([]string{"a", "-attach"}, false, "Attach STDOUT/STDERR and forward signals")
-	openStdin := cmd.Bool([]string{"i", "-interactive"}, false, "Attach container's STDIN")
-	detachKeys := cmd.String([]string{"-detach-keys"}, "", "Override the key sequence for detaching a container")
-	cmd.Require(flag.Min, 1)
-
-	cmd.ParseFlags(args, true)
-
-	ctx, cancelFun := context.WithCancel(context.Background())
-
-	if *attach || *openStdin {
-		// We're going to attach to a container.
-		// 1. Ensure we only have one container.
-		if cmd.NArg() > 1 {
-			return fmt.Errorf("You cannot start and attach multiple containers at once.")
-		}
-
-		// 2. Attach to the container.
-		container := cmd.Arg(0)
-		c, err := cli.client.ContainerInspect(ctx, container)
-		if err != nil {
-			return err
-		}
-
-		if !c.Config.Tty {
-			sigc := cli.ForwardAllSignals(ctx, container)
-			defer signal.StopCatch(sigc)
-		}
-
-		if *detachKeys != "" {
-			cli.configFile.DetachKeys = *detachKeys
-		}
-
-		options := types.ContainerAttachOptions{
-			Stream:     true,
-			Stdin:      *openStdin && c.Config.OpenStdin,
-			Stdout:     true,
-			Stderr:     true,
-			DetachKeys: cli.configFile.DetachKeys,
-		}
-
-		var in io.ReadCloser
-
-		if options.Stdin {
-			in = cli.in
-		}
-
-		resp, errAttach := cli.client.ContainerAttach(ctx, container, options)
-		if errAttach != nil && errAttach != httputil.ErrPersistEOF {
-			// ContainerAttach return an ErrPersistEOF (connection closed)
-			// means server met an error and put it in Hijacked connection
-			// keep the error and read detailed error message from hijacked connection
-			return errAttach
-		}
-		defer resp.Close()
-		cErr := promise.Go(func() error {
-			errHijack := cli.HoldHijackedConnection(ctx, c.Config.Tty, in, cli.out, cli.err, resp)
-			if errHijack == nil {
-				return errAttach
-			}
-			return errHijack
-		})
-
-		// 3. Start the container.
-		if err := cli.client.ContainerStart(ctx, container, types.ContainerStartOptions{}); err != nil {
-			cancelFun()
-			<-cErr
-			return err
-		}
-
-		// 4. Wait for attachment to break.
-		if c.Config.Tty && cli.isTerminalOut {
-			if err := cli.MonitorTtySize(ctx, container, false); err != nil {
-				fmt.Fprintf(cli.err, "Error monitoring TTY size: %s\n", err)
-			}
-		}
-		if attchErr := <-cErr; attchErr != nil {
-			return attchErr
-		}
-		_, status, err := cli.GetExitCode(ctx, container)
-		if err != nil {
-			return err
-		}
-		if status != 0 {
-			return Cli.StatusError{StatusCode: status}
-		}
-	} else {
-		// We're not going to attach to anything.
-		// Start as many containers as we want.
-		return cli.startContainersWithoutAttachments(ctx, cmd.Args())
-	}
-
-	return nil
-}
-
-func (cli *DockerCli) startContainersWithoutAttachments(ctx context.Context, containers []string) error {
-	var failedContainers []string
-	for _, container := range containers {
-		if err := cli.client.ContainerStart(ctx, container, types.ContainerStartOptions{}); err != nil {
-			fmt.Fprintf(cli.err, "%s\n", err)
-			failedContainers = append(failedContainers, container)
-		} else {
-			fmt.Fprintf(cli.out, "%s\n", container)
-		}
-	}
-
-	if len(failedContainers) > 0 {
-		return fmt.Errorf("Error: failed to start containers: %v", strings.Join(failedContainers, ", "))
-	}
-	return nil
-}

+ 31 - 0
api/client/utils.go

@@ -204,3 +204,34 @@ func (cli *DockerCli) retrieveAuthConfigs() map[string]types.AuthConfig {
 	acs, _ := getAllCredentials(cli.configFile)
 	return acs
 }
+
+// ForwardAllSignals forwards signals to the contianer
+// TODO: this can be unexported again once all container commands are under
+// api/client/container
+func (cli *DockerCli) ForwardAllSignals(ctx context.Context, cid string) chan os.Signal {
+	sigc := make(chan os.Signal, 128)
+	signal.CatchAll(sigc)
+	go func() {
+		for s := range sigc {
+			if s == signal.SIGCHLD || s == signal.SIGPIPE {
+				continue
+			}
+			var sig string
+			for sigStr, sigN := range signal.SignalMap {
+				if sigN == s {
+					sig = sigStr
+					break
+				}
+			}
+			if sig == "" {
+				fmt.Fprintf(cli.err, "Unsupported signal: %v. Discarding.\n", s)
+				continue
+			}
+
+			if err := cli.client.ContainerKill(ctx, cid, sig); err != nil {
+				logrus.Debugf("Error sending signal: %s", err)
+			}
+		}
+	}()
+	return sigc
+}

+ 1 - 0
cli/cobraadaptor/adaptor.go

@@ -36,6 +36,7 @@ func NewCobraAdaptor(clientFlags *cliflags.ClientFlags) CobraAdaptor {
 		container.NewCreateCommand(dockerCli),
 		container.NewExportCommand(dockerCli),
 		container.NewRunCommand(dockerCli),
+		container.NewStartCommand(dockerCli),
 		container.NewStopCommand(dockerCli),
 		image.NewRemoveCommand(dockerCli),
 		image.NewSearchCommand(dockerCli),

+ 0 - 1
cli/usage.go

@@ -35,7 +35,6 @@ var DockerCommandUsage = []Command{
 	{"restart", "Restart a container"},
 	{"rm", "Remove one or more containers"},
 	{"save", "Save one or more images to a tar archive"},
-	{"start", "Start one or more stopped containers"},
 	{"stats", "Display a live stream of container(s) resource usage statistics"},
 	{"tag", "Tag an image into a repository"},
 	{"top", "Display the running processes of a container"},