소스 검색

rename a existing container
Closes #3036

Signed-off-by: Srini Brahmaroutu <srbrahma@us.ibm.com>

Srini Brahmaroutu 10 년 전
부모
커밋
21a809d9ae

+ 20 - 0
api/client/commands.go

@@ -818,6 +818,26 @@ func (cli *DockerCli) CmdPause(args ...string) error {
 	return encounteredError
 }
 
+func (cli *DockerCli) CmdRename(args ...string) error {
+	cmd := cli.Subcmd("rename", "OLD_NAME NEW_NAME", "Rename a container", true)
+	if err := cmd.Parse(args); err != nil {
+		return nil
+	}
+
+	if cmd.NArg() != 2 {
+		cmd.Usage()
+		return nil
+	}
+	old_name := cmd.Arg(0)
+	new_name := cmd.Arg(1)
+
+	if _, _, err := readBody(cli.call("POST", fmt.Sprintf("/containers/%s/rename?name=%s", old_name, new_name), nil, false)); err != nil {
+		fmt.Fprintf(cli.err, "%s\n", err)
+		return fmt.Errorf("Error: failed to rename container named %s", old_name)
+	}
+	return nil
+}
+
 func (cli *DockerCli) CmdInspect(args ...string) error {
 	cmd := cli.Subcmd("inspect", "CONTAINER|IMAGE [CONTAINER|IMAGE...]", "Return low-level information on a container or image", true)
 	tmplStr := cmd.String([]string{"f", "#format", "-format"}, "", "Format the output using the given go template.")

+ 19 - 0
api/server/server.go

@@ -739,6 +739,24 @@ func postContainersRestart(eng *engine.Engine, version version.Version, w http.R
 	return nil
 }
 
+func postContainerRename(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	if err := parseForm(r); err != nil {
+		return err
+	}
+	if vars == nil {
+		return fmt.Errorf("Missing parameter")
+	}
+
+	newName := r.URL.Query().Get("name")
+	job := eng.Job("container_rename", vars["name"], newName)
+	job.Setenv("t", r.Form.Get("t"))
+	if err := job.Run(); err != nil {
+		return err
+	}
+	w.WriteHeader(http.StatusNoContent)
+	return nil
+}
+
 func deleteContainers(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if err := parseForm(r); err != nil {
 		return err
@@ -1311,6 +1329,7 @@ func createRouter(eng *engine.Engine, logging, enableCors bool, dockerVersion st
 			"/containers/{name:.*}/exec":    postContainerExecCreate,
 			"/exec/{name:.*}/start":         postContainerExecStart,
 			"/exec/{name:.*}/resize":        postContainerExecResize,
+			"/containers/{name:.*}/rename":  postContainerRename,
 		},
 		"DELETE": {
 			"/containers/{name:.*}": deleteContainers,

+ 1 - 0
daemon/daemon.go

@@ -113,6 +113,7 @@ func (daemon *Daemon) Install(eng *engine.Engine) error {
 		"commit":            daemon.ContainerCommit,
 		"container_changes": daemon.ContainerChanges,
 		"container_copy":    daemon.ContainerCopy,
+		"container_rename":  daemon.ContainerRename,
 		"container_inspect": daemon.ContainerInspect,
 		"containers":        daemon.Containers,
 		"create":            daemon.ContainerCreate,

+ 30 - 0
daemon/rename.go

@@ -0,0 +1,30 @@
+package daemon
+
+import (
+	"github.com/docker/docker/engine"
+)
+
+func (daemon *Daemon) ContainerRename(job *engine.Job) engine.Status {
+	if len(job.Args) != 2 {
+		return job.Errorf("usage: %s OLD_NAME NEW_NAME", job.Name)
+	}
+	old_name := job.Args[0]
+	new_name := job.Args[1]
+
+	container := daemon.Get(old_name)
+	if container == nil {
+		return job.Errorf("No such container: %s", old_name)
+	}
+
+	container.Lock()
+	defer container.Unlock()
+	if err := daemon.containerGraph.Delete(container.Name); err != nil {
+		return job.Errorf("Failed to delete container %q: %v", old_name, err)
+	}
+	if _, err := daemon.reserveName(container.ID, new_name); err != nil {
+		return job.Errorf("Error when allocating new name: %s", err)
+	}
+	container.Name = new_name
+
+	return engine.StatusOK
+}

+ 1 - 0
docker/flags.go

@@ -90,6 +90,7 @@ func init() {
 			{"ps", "List containers"},
 			{"pull", "Pull an image or a repository from a Docker registry server"},
 			{"push", "Push an image or a repository to a Docker registry server"},
+			{"rename", "Rename an existing container"},
 			{"restart", "Restart a running container"},
 			{"rm", "Remove one or more containers"},
 			{"rmi", "Remove one or more images"},

+ 13 - 0
docs/man/docker-rename.1.md

@@ -0,0 +1,13 @@
+% DOCKER(1) Docker User Manuals
+% Docker Community
+% OCTOBER 2014
+# NAME
+docker-rename - Rename a container
+
+# SYNOPSIS
+**docker rename**
+OLD_NAME NEW_NAME
+
+# OPTIONS
+There are no available options.
+

+ 21 - 0
docs/sources/reference/api/docker_remote_api_v1.15.md

@@ -647,6 +647,27 @@ Status Codes:
 -   **404** – no such container
 -   **500** – server error
 
+### Rename a container
+
+`POST /containers/(id)/rename/(new_name)`
+
+Rename the container `id` to a `new_name`
+
+**Example request**:
+
+        POST /containers/e90e34656806/rename/new_name HTTP/1.1
+
+**Example response**:
+
+        HTTP/1.1 204 No Content
+
+Status Codes:
+
+-   **204** – no error
+-   **404** – no such container
+-   **409** - conflict name already assigned
+-   **500** – server error
+
 ### Pause a container
 
 `POST /containers/(id)/pause`

+ 24 - 0
docs/sources/reference/commandline/cli.md

@@ -1366,6 +1366,30 @@ just a specific mapping:
     $ sudo docker port test 7890
     0.0.0.0:4321
 
+## pause
+
+    Usage: docker pause CONTAINER
+
+    Pause all processes within a container
+
+The `docker pause` command uses the cgroups freezer to suspend all processes in
+a container.  Traditionally when suspending a process the `SIGSTOP` signal is
+used, which is observable by the process being suspended. With the cgroups freezer
+the process is unaware, and unable to capture, that it is being suspended,
+and subsequently resumed.
+
+See the
+[cgroups freezer documentation](https://www.kernel.org/doc/Documentation/cgroups/freezer-subsystem.txt)
+for further details.
+
+## rename
+
+    Usage: docker rename OLD_NAME NEW_NAME
+
+    rename a existing container to a NEW_NAME
+
+The `docker rename` command allows the container to be renamed to a different name.  
+
 ## ps
 
     Usage: docker ps [OPTIONS]

+ 47 - 2
integration-cli/docker_cli_links_test.go

@@ -1,6 +1,7 @@
 package main
 
 import (
+	"github.com/docker/docker/pkg/iptables"
 	"io/ioutil"
 	"os"
 	"os/exec"
@@ -8,8 +9,6 @@ import (
 	"strings"
 	"testing"
 	"time"
-
-	"github.com/docker/docker/pkg/iptables"
 )
 
 func TestLinksEtcHostsRegularFile(t *testing.T) {
@@ -76,6 +75,52 @@ func TestLinksPingLinkedContainers(t *testing.T) {
 	logDone("links - ping linked container")
 }
 
+func TestLinksPingLinkedContainersAfterRename(t *testing.T) {
+	out, _, _ := dockerCmd(t, "run", "-d", "--name", "container1", "busybox", "sleep", "10")
+	idA := stripTrailingCharacters(out)
+	out, _, _ = dockerCmd(t, "run", "-d", "--name", "container2", "busybox", "sleep", "10")
+	idB := stripTrailingCharacters(out)
+	dockerCmd(t, "rename", "container1", "container_new")
+	dockerCmd(t, "run", "--rm", "--link", "container_new:alias1", "--link", "container2:alias2", "busybox", "sh", "-c", "ping -c 1 alias1 -W 1 && ping -c 1 alias2 -W 1")
+	dockerCmd(t, "kill", idA)
+	dockerCmd(t, "kill", idB)
+	deleteAllContainers()
+
+	logDone("links - ping linked container after rename")
+}
+
+func TestLinksPingLinkedContainersOnRename(t *testing.T) {
+	var out string
+	out, _, _ = dockerCmd(t, "run", "-d", "--name", "container1", "busybox", "sleep", "10")
+	idA := stripTrailingCharacters(out)
+	if idA == "" {
+		t.Fatal(out, "id should not be nil")
+	}
+	out, _, _ = dockerCmd(t, "run", "-d", "--link", "container1:alias1", "--name", "container2", "busybox", "sleep", "10")
+	idB := stripTrailingCharacters(out)
+	if idB == "" {
+		t.Fatal(out, "id should not be nil")
+	}
+
+	execCmd := exec.Command(dockerBinary, "exec", "container2", "ping", "-c", "1", "alias1", "-W", "1")
+	out, _, err := runCommandWithOutput(execCmd)
+	if err != nil {
+		t.Fatal(out, err)
+	}
+
+	dockerCmd(t, "rename", "container1", "container_new")
+
+	execCmd = exec.Command(dockerBinary, "exec", "container2", "ping", "-c", "1", "alias1", "-W", "1")
+	out, _, err = runCommandWithOutput(execCmd)
+	if err != nil {
+		t.Fatal(out, err)
+	}
+
+	deleteAllContainers()
+
+	logDone("links - ping linked container upon rename")
+}
+
 func TestLinksIpTablesRulesWhenLinkAndUnlink(t *testing.T) {
 	dockerCmd(t, "run", "-d", "--name", "child", "--publish", "8080:80", "busybox", "sleep", "10")
 	dockerCmd(t, "run", "-d", "--name", "parent", "--link", "child:http", "busybox", "sleep", "10")

+ 99 - 0
integration-cli/docker_cli_rename_test.go

@@ -0,0 +1,99 @@
+package main
+
+import (
+	"os/exec"
+	"strings"
+	"testing"
+)
+
+func TestRenameStoppedContainer(t *testing.T) {
+	runCmd := exec.Command(dockerBinary, "run", "--name", "first_name", "-d", "busybox", "sh")
+	out, _, err := runCommandWithOutput(runCmd)
+	if err != nil {
+		t.Fatalf(out, err)
+	}
+
+	cleanedContainerID := stripTrailingCharacters(out)
+
+	runCmd = exec.Command(dockerBinary, "wait", cleanedContainerID)
+	out, _, err = runCommandWithOutput(runCmd)
+	if err != nil {
+		t.Fatalf(out, err)
+	}
+
+	name, err := inspectField(cleanedContainerID, "Name")
+
+	runCmd = exec.Command(dockerBinary, "rename", "first_name", "new_name")
+	out, _, err = runCommandWithOutput(runCmd)
+	if err != nil {
+		t.Fatalf(out, err)
+	}
+
+	name, err = inspectField(cleanedContainerID, "Name")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if name != "new_name" {
+		t.Fatal("Failed to rename container ", name)
+	}
+	deleteAllContainers()
+
+	logDone("rename - stopped container")
+}
+
+func TestRenameRunningContainer(t *testing.T) {
+	runCmd := exec.Command(dockerBinary, "run", "--name", "first_name", "-d", "busybox", "sh")
+	out, _, err := runCommandWithOutput(runCmd)
+	if err != nil {
+		t.Fatalf(out, err)
+	}
+
+	cleanedContainerID := stripTrailingCharacters(out)
+	runCmd = exec.Command(dockerBinary, "rename", "first_name", "new_name")
+	out, _, err = runCommandWithOutput(runCmd)
+	if err != nil {
+		t.Fatalf(out, err)
+	}
+
+	name, err := inspectField(cleanedContainerID, "Name")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if name != "new_name" {
+		t.Fatal("Failed to rename container ")
+	}
+	deleteAllContainers()
+
+	logDone("rename - running container")
+}
+
+func TestRenameCheckNames(t *testing.T) {
+	runCmd := exec.Command(dockerBinary, "run", "--name", "first_name", "-d", "busybox", "sh")
+	out, _, err := runCommandWithOutput(runCmd)
+	if err != nil {
+		t.Fatalf(out, err)
+	}
+
+	runCmd = exec.Command(dockerBinary, "rename", "first_name", "new_name")
+	out, _, err = runCommandWithOutput(runCmd)
+	if err != nil {
+		t.Fatalf(out, err)
+	}
+
+	name, err := inspectField("new_name", "Name")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if name != "new_name" {
+		t.Fatal("Failed to rename container ")
+	}
+
+	name, err = inspectField("first_name", "Name")
+	if err == nil && !strings.Contains(err.Error(), "No such image or container: first_name") {
+		t.Fatal(err)
+	}
+
+	deleteAllContainers()
+
+	logDone("rename - running container")
+}