Signed-off-by: Zhang Wei <zhangwei555@huawei.com>
| 24 | 23 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,76 @@ |
| 0 |
+package container |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "fmt" |
|
| 4 |
+ "strings" |
|
| 5 |
+ |
|
| 6 |
+ "golang.org/x/net/context" |
|
| 7 |
+ |
|
| 8 |
+ "github.com/docker/docker/api/client" |
|
| 9 |
+ "github.com/docker/docker/cli" |
|
| 10 |
+ "github.com/docker/engine-api/types" |
|
| 11 |
+ "github.com/spf13/cobra" |
|
| 12 |
+) |
|
| 13 |
+ |
|
| 14 |
+type rmOptions struct {
|
|
| 15 |
+ rmVolumes bool |
|
| 16 |
+ rmLink bool |
|
| 17 |
+ force bool |
|
| 18 |
+ |
|
| 19 |
+ containers []string |
|
| 20 |
+} |
|
| 21 |
+ |
|
| 22 |
+// NewRmCommand creats a new cobra.Command for `docker rm` |
|
| 23 |
+func NewRmCommand(dockerCli *client.DockerCli) *cobra.Command {
|
|
| 24 |
+ var opts rmOptions |
|
| 25 |
+ |
|
| 26 |
+ cmd := &cobra.Command{
|
|
| 27 |
+ Use: "rm [OPTIONS] CONTAINER [CONTAINER...]", |
|
| 28 |
+ Short: "Remove one or more containers", |
|
| 29 |
+ Args: cli.RequiresMinArgs(1), |
|
| 30 |
+ RunE: func(cmd *cobra.Command, args []string) error {
|
|
| 31 |
+ opts.containers = args |
|
| 32 |
+ return runRm(dockerCli, &opts) |
|
| 33 |
+ }, |
|
| 34 |
+ } |
|
| 35 |
+ |
|
| 36 |
+ flags := cmd.Flags() |
|
| 37 |
+ flags.BoolVarP(&opts.rmVolumes, "volumes", "v", false, "Remove the volumes associated with the container") |
|
| 38 |
+ flags.BoolVarP(&opts.rmLink, "link", "l", false, "Remove the specified link") |
|
| 39 |
+ flags.BoolVarP(&opts.force, "force", "f", false, "Force the removal of a running container (uses SIGKILL)") |
|
| 40 |
+ return cmd |
|
| 41 |
+} |
|
| 42 |
+ |
|
| 43 |
+func runRm(dockerCli *client.DockerCli, opts *rmOptions) error {
|
|
| 44 |
+ ctx := context.Background() |
|
| 45 |
+ |
|
| 46 |
+ var errs []string |
|
| 47 |
+ for _, name := range opts.containers {
|
|
| 48 |
+ if name == "" {
|
|
| 49 |
+ return fmt.Errorf("Container name cannot be empty")
|
|
| 50 |
+ } |
|
| 51 |
+ name = strings.Trim(name, "/") |
|
| 52 |
+ |
|
| 53 |
+ if err := removeContainer(dockerCli, ctx, name, opts.rmVolumes, opts.rmLink, opts.force); err != nil {
|
|
| 54 |
+ errs = append(errs, err.Error()) |
|
| 55 |
+ } else {
|
|
| 56 |
+ fmt.Fprintf(dockerCli.Out(), "%s\n", name) |
|
| 57 |
+ } |
|
| 58 |
+ } |
|
| 59 |
+ if len(errs) > 0 {
|
|
| 60 |
+ return fmt.Errorf("%s", strings.Join(errs, "\n"))
|
|
| 61 |
+ } |
|
| 62 |
+ return nil |
|
| 63 |
+} |
|
| 64 |
+ |
|
| 65 |
+func removeContainer(dockerCli *client.DockerCli, ctx context.Context, container string, removeVolumes, removeLinks, force bool) error {
|
|
| 66 |
+ options := types.ContainerRemoveOptions{
|
|
| 67 |
+ RemoveVolumes: removeVolumes, |
|
| 68 |
+ RemoveLinks: removeLinks, |
|
| 69 |
+ Force: force, |
|
| 70 |
+ } |
|
| 71 |
+ if err := dockerCli.Client().ContainerRemove(ctx, container, options); err != nil {
|
|
| 72 |
+ return err |
|
| 73 |
+ } |
|
| 74 |
+ return nil |
|
| 75 |
+} |
| ... | ... |
@@ -234,7 +234,7 @@ func runRun(dockerCli *client.DockerCli, flags *pflag.FlagSet, opts *runOptions, |
| 234 | 234 |
defer func() {
|
| 235 | 235 |
// Explicitly not sharing the context as it could be "Done" (by calling cancelFun) |
| 236 | 236 |
// and thus the container would not be removed. |
| 237 |
- if err := dockerCli.RemoveContainer(context.Background(), createResponse.ID, true, false, true); err != nil {
|
|
| 237 |
+ if err := removeContainer(dockerCli, context.Background(), createResponse.ID, true, false, true); err != nil {
|
|
| 238 | 238 |
fmt.Fprintf(stderr, "%v\n", err) |
| 239 | 239 |
} |
| 240 | 240 |
}() |
| 241 | 241 |
deleted file mode 100644 |
| ... | ... |
@@ -1,60 +0,0 @@ |
| 1 |
-package client |
|
| 2 |
- |
|
| 3 |
-import ( |
|
| 4 |
- "fmt" |
|
| 5 |
- "strings" |
|
| 6 |
- |
|
| 7 |
- "golang.org/x/net/context" |
|
| 8 |
- |
|
| 9 |
- Cli "github.com/docker/docker/cli" |
|
| 10 |
- flag "github.com/docker/docker/pkg/mflag" |
|
| 11 |
- "github.com/docker/engine-api/types" |
|
| 12 |
-) |
|
| 13 |
- |
|
| 14 |
-// CmdRm removes one or more containers. |
|
| 15 |
-// |
|
| 16 |
-// Usage: docker rm [OPTIONS] CONTAINER [CONTAINER...] |
|
| 17 |
-func (cli *DockerCli) CmdRm(args ...string) error {
|
|
| 18 |
- cmd := Cli.Subcmd("rm", []string{"CONTAINER [CONTAINER...]"}, Cli.DockerCommands["rm"].Description, true)
|
|
| 19 |
- v := cmd.Bool([]string{"v", "-volumes"}, false, "Remove the volumes associated with the container")
|
|
| 20 |
- link := cmd.Bool([]string{"l", "-link"}, false, "Remove the specified link")
|
|
| 21 |
- force := cmd.Bool([]string{"f", "-force"}, false, "Force the removal of a running container (uses SIGKILL)")
|
|
| 22 |
- cmd.Require(flag.Min, 1) |
|
| 23 |
- |
|
| 24 |
- cmd.ParseFlags(args, true) |
|
| 25 |
- |
|
| 26 |
- ctx := context.Background() |
|
| 27 |
- |
|
| 28 |
- var errs []string |
|
| 29 |
- for _, name := range cmd.Args() {
|
|
| 30 |
- if name == "" {
|
|
| 31 |
- return fmt.Errorf("Container name cannot be empty")
|
|
| 32 |
- } |
|
| 33 |
- name = strings.Trim(name, "/") |
|
| 34 |
- |
|
| 35 |
- if err := cli.RemoveContainer(ctx, name, *v, *link, *force); err != nil {
|
|
| 36 |
- errs = append(errs, err.Error()) |
|
| 37 |
- } else {
|
|
| 38 |
- fmt.Fprintf(cli.out, "%s\n", name) |
|
| 39 |
- } |
|
| 40 |
- } |
|
| 41 |
- if len(errs) > 0 {
|
|
| 42 |
- return fmt.Errorf("%s", strings.Join(errs, "\n"))
|
|
| 43 |
- } |
|
| 44 |
- return nil |
|
| 45 |
-} |
|
| 46 |
- |
|
| 47 |
-// RemoveContainer removes a container |
|
| 48 |
-// TODO: this can be unexported again once all container commands are under |
|
| 49 |
-// api/client/container |
|
| 50 |
-func (cli *DockerCli) RemoveContainer(ctx context.Context, container string, removeVolumes, removeLinks, force bool) error {
|
|
| 51 |
- options := types.ContainerRemoveOptions{
|
|
| 52 |
- RemoveVolumes: removeVolumes, |
|
| 53 |
- RemoveLinks: removeLinks, |
|
| 54 |
- Force: force, |
|
| 55 |
- } |
|
| 56 |
- if err := cli.client.ContainerRemove(ctx, container, options); err != nil {
|
|
| 57 |
- return err |
|
| 58 |
- } |
|
| 59 |
- return nil |
|
| 60 |
-} |
| ... | ... |
@@ -44,6 +44,7 @@ func NewCobraAdaptor(clientFlags *cliflags.ClientFlags) CobraAdaptor {
|
| 44 | 44 |
container.NewPortCommand(dockerCli), |
| 45 | 45 |
container.NewRenameCommand(dockerCli), |
| 46 | 46 |
container.NewRestartCommand(dockerCli), |
| 47 |
+ container.NewRmCommand(dockerCli), |
|
| 47 | 48 |
container.NewRunCommand(dockerCli), |
| 48 | 49 |
container.NewStartCommand(dockerCli), |
| 49 | 50 |
container.NewStopCommand(dockerCli), |
| ... | ... |
@@ -22,7 +22,6 @@ var DockerCommandUsage = []Command{
|
| 22 | 22 |
{"ps", "List containers"},
|
| 23 | 23 |
{"pull", "Pull an image or a repository from a registry"},
|
| 24 | 24 |
{"push", "Push an image or a repository to a registry"},
|
| 25 |
- {"rm", "Remove one or more containers"},
|
|
| 26 | 25 |
{"save", "Save one or more images to a tar archive"},
|
| 27 | 26 |
{"stats", "Display a live stream of container(s) resource usage statistics"},
|
| 28 | 27 |
{"tag", "Tag an image into a repository"},
|
| ... | ... |
@@ -184,7 +184,7 @@ func (s *DockerSuite) TestHelpExitCodesHelpOutput(c *check.C) {
|
| 184 | 184 |
c.Assert(stdout, checker.Equals, "") |
| 185 | 185 |
// Should not contain full help text but should contain info about |
| 186 | 186 |
// # of args and Usage line |
| 187 |
- c.Assert(stderr, checker.Contains, "requires a minimum", check.Commentf("Missing # of args text from 'docker rm'\n"))
|
|
| 187 |
+ c.Assert(stderr, checker.Contains, "requires at least 1 argument", check.Commentf("Missing # of args text from 'docker rm'\n"))
|
|
| 188 | 188 |
|
| 189 | 189 |
// docker rm NoSuchContainer: stdout=empty, stderr=all, rc=0 |
| 190 | 190 |
// testing to make sure no blank line on error |