Browse code

rename a existing container Closes #3036

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

Srini Brahmaroutu authored on 2014/10/05 11:47:54
Showing 10 changed files
... ...
@@ -818,6 +818,26 @@ func (cli *DockerCli) CmdPause(args ...string) error {
818 818
 	return encounteredError
819 819
 }
820 820
 
821
+func (cli *DockerCli) CmdRename(args ...string) error {
822
+	cmd := cli.Subcmd("rename", "OLD_NAME NEW_NAME", "Rename a container", true)
823
+	if err := cmd.Parse(args); err != nil {
824
+		return nil
825
+	}
826
+
827
+	if cmd.NArg() != 2 {
828
+		cmd.Usage()
829
+		return nil
830
+	}
831
+	old_name := cmd.Arg(0)
832
+	new_name := cmd.Arg(1)
833
+
834
+	if _, _, err := readBody(cli.call("POST", fmt.Sprintf("/containers/%s/rename?name=%s", old_name, new_name), nil, false)); err != nil {
835
+		fmt.Fprintf(cli.err, "%s\n", err)
836
+		return fmt.Errorf("Error: failed to rename container named %s", old_name)
837
+	}
838
+	return nil
839
+}
840
+
821 841
 func (cli *DockerCli) CmdInspect(args ...string) error {
822 842
 	cmd := cli.Subcmd("inspect", "CONTAINER|IMAGE [CONTAINER|IMAGE...]", "Return low-level information on a container or image", true)
823 843
 	tmplStr := cmd.String([]string{"f", "#format", "-format"}, "", "Format the output using the given go template.")
... ...
@@ -739,6 +739,24 @@ func postContainersRestart(eng *engine.Engine, version version.Version, w http.R
739 739
 	return nil
740 740
 }
741 741
 
742
+func postContainerRename(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
743
+	if err := parseForm(r); err != nil {
744
+		return err
745
+	}
746
+	if vars == nil {
747
+		return fmt.Errorf("Missing parameter")
748
+	}
749
+
750
+	newName := r.URL.Query().Get("name")
751
+	job := eng.Job("container_rename", vars["name"], newName)
752
+	job.Setenv("t", r.Form.Get("t"))
753
+	if err := job.Run(); err != nil {
754
+		return err
755
+	}
756
+	w.WriteHeader(http.StatusNoContent)
757
+	return nil
758
+}
759
+
742 760
 func deleteContainers(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
743 761
 	if err := parseForm(r); err != nil {
744 762
 		return err
... ...
@@ -1311,6 +1329,7 @@ func createRouter(eng *engine.Engine, logging, enableCors bool, dockerVersion st
1311 1311
 			"/containers/{name:.*}/exec":    postContainerExecCreate,
1312 1312
 			"/exec/{name:.*}/start":         postContainerExecStart,
1313 1313
 			"/exec/{name:.*}/resize":        postContainerExecResize,
1314
+			"/containers/{name:.*}/rename":  postContainerRename,
1314 1315
 		},
1315 1316
 		"DELETE": {
1316 1317
 			"/containers/{name:.*}": deleteContainers,
... ...
@@ -113,6 +113,7 @@ func (daemon *Daemon) Install(eng *engine.Engine) error {
113 113
 		"commit":            daemon.ContainerCommit,
114 114
 		"container_changes": daemon.ContainerChanges,
115 115
 		"container_copy":    daemon.ContainerCopy,
116
+		"container_rename":  daemon.ContainerRename,
116 117
 		"container_inspect": daemon.ContainerInspect,
117 118
 		"containers":        daemon.Containers,
118 119
 		"create":            daemon.ContainerCreate,
119 120
new file mode 100644
... ...
@@ -0,0 +1,30 @@
0
+package daemon
1
+
2
+import (
3
+	"github.com/docker/docker/engine"
4
+)
5
+
6
+func (daemon *Daemon) ContainerRename(job *engine.Job) engine.Status {
7
+	if len(job.Args) != 2 {
8
+		return job.Errorf("usage: %s OLD_NAME NEW_NAME", job.Name)
9
+	}
10
+	old_name := job.Args[0]
11
+	new_name := job.Args[1]
12
+
13
+	container := daemon.Get(old_name)
14
+	if container == nil {
15
+		return job.Errorf("No such container: %s", old_name)
16
+	}
17
+
18
+	container.Lock()
19
+	defer container.Unlock()
20
+	if err := daemon.containerGraph.Delete(container.Name); err != nil {
21
+		return job.Errorf("Failed to delete container %q: %v", old_name, err)
22
+	}
23
+	if _, err := daemon.reserveName(container.ID, new_name); err != nil {
24
+		return job.Errorf("Error when allocating new name: %s", err)
25
+	}
26
+	container.Name = new_name
27
+
28
+	return engine.StatusOK
29
+}
... ...
@@ -90,6 +90,7 @@ func init() {
90 90
 			{"ps", "List containers"},
91 91
 			{"pull", "Pull an image or a repository from a Docker registry server"},
92 92
 			{"push", "Push an image or a repository to a Docker registry server"},
93
+			{"rename", "Rename an existing container"},
93 94
 			{"restart", "Restart a running container"},
94 95
 			{"rm", "Remove one or more containers"},
95 96
 			{"rmi", "Remove one or more images"},
96 97
new file mode 100644
... ...
@@ -0,0 +1,13 @@
0
+% DOCKER(1) Docker User Manuals
1
+% Docker Community
2
+% OCTOBER 2014
3
+# NAME
4
+docker-rename - Rename a container
5
+
6
+# SYNOPSIS
7
+**docker rename**
8
+OLD_NAME NEW_NAME
9
+
10
+# OPTIONS
11
+There are no available options.
12
+
... ...
@@ -647,6 +647,27 @@ Status Codes:
647 647
 -   **404** – no such container
648 648
 -   **500** – server error
649 649
 
650
+### Rename a container
651
+
652
+`POST /containers/(id)/rename/(new_name)`
653
+
654
+Rename the container `id` to a `new_name`
655
+
656
+**Example request**:
657
+
658
+        POST /containers/e90e34656806/rename/new_name HTTP/1.1
659
+
660
+**Example response**:
661
+
662
+        HTTP/1.1 204 No Content
663
+
664
+Status Codes:
665
+
666
+-   **204** – no error
667
+-   **404** – no such container
668
+-   **409** - conflict name already assigned
669
+-   **500** – server error
670
+
650 671
 ### Pause a container
651 672
 
652 673
 `POST /containers/(id)/pause`
... ...
@@ -1366,6 +1366,30 @@ just a specific mapping:
1366 1366
     $ sudo docker port test 7890
1367 1367
     0.0.0.0:4321
1368 1368
 
1369
+## pause
1370
+
1371
+    Usage: docker pause CONTAINER
1372
+
1373
+    Pause all processes within a container
1374
+
1375
+The `docker pause` command uses the cgroups freezer to suspend all processes in
1376
+a container.  Traditionally when suspending a process the `SIGSTOP` signal is
1377
+used, which is observable by the process being suspended. With the cgroups freezer
1378
+the process is unaware, and unable to capture, that it is being suspended,
1379
+and subsequently resumed.
1380
+
1381
+See the
1382
+[cgroups freezer documentation](https://www.kernel.org/doc/Documentation/cgroups/freezer-subsystem.txt)
1383
+for further details.
1384
+
1385
+## rename
1386
+
1387
+    Usage: docker rename OLD_NAME NEW_NAME
1388
+
1389
+    rename a existing container to a NEW_NAME
1390
+
1391
+The `docker rename` command allows the container to be renamed to a different name.  
1392
+
1369 1393
 ## ps
1370 1394
 
1371 1395
     Usage: docker ps [OPTIONS]
... ...
@@ -1,6 +1,7 @@
1 1
 package main
2 2
 
3 3
 import (
4
+	"github.com/docker/docker/pkg/iptables"
4 5
 	"io/ioutil"
5 6
 	"os"
6 7
 	"os/exec"
... ...
@@ -8,8 +9,6 @@ import (
8 8
 	"strings"
9 9
 	"testing"
10 10
 	"time"
11
-
12
-	"github.com/docker/docker/pkg/iptables"
13 11
 )
14 12
 
15 13
 func TestLinksEtcHostsRegularFile(t *testing.T) {
... ...
@@ -76,6 +75,52 @@ func TestLinksPingLinkedContainers(t *testing.T) {
76 76
 	logDone("links - ping linked container")
77 77
 }
78 78
 
79
+func TestLinksPingLinkedContainersAfterRename(t *testing.T) {
80
+	out, _, _ := dockerCmd(t, "run", "-d", "--name", "container1", "busybox", "sleep", "10")
81
+	idA := stripTrailingCharacters(out)
82
+	out, _, _ = dockerCmd(t, "run", "-d", "--name", "container2", "busybox", "sleep", "10")
83
+	idB := stripTrailingCharacters(out)
84
+	dockerCmd(t, "rename", "container1", "container_new")
85
+	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")
86
+	dockerCmd(t, "kill", idA)
87
+	dockerCmd(t, "kill", idB)
88
+	deleteAllContainers()
89
+
90
+	logDone("links - ping linked container after rename")
91
+}
92
+
93
+func TestLinksPingLinkedContainersOnRename(t *testing.T) {
94
+	var out string
95
+	out, _, _ = dockerCmd(t, "run", "-d", "--name", "container1", "busybox", "sleep", "10")
96
+	idA := stripTrailingCharacters(out)
97
+	if idA == "" {
98
+		t.Fatal(out, "id should not be nil")
99
+	}
100
+	out, _, _ = dockerCmd(t, "run", "-d", "--link", "container1:alias1", "--name", "container2", "busybox", "sleep", "10")
101
+	idB := stripTrailingCharacters(out)
102
+	if idB == "" {
103
+		t.Fatal(out, "id should not be nil")
104
+	}
105
+
106
+	execCmd := exec.Command(dockerBinary, "exec", "container2", "ping", "-c", "1", "alias1", "-W", "1")
107
+	out, _, err := runCommandWithOutput(execCmd)
108
+	if err != nil {
109
+		t.Fatal(out, err)
110
+	}
111
+
112
+	dockerCmd(t, "rename", "container1", "container_new")
113
+
114
+	execCmd = exec.Command(dockerBinary, "exec", "container2", "ping", "-c", "1", "alias1", "-W", "1")
115
+	out, _, err = runCommandWithOutput(execCmd)
116
+	if err != nil {
117
+		t.Fatal(out, err)
118
+	}
119
+
120
+	deleteAllContainers()
121
+
122
+	logDone("links - ping linked container upon rename")
123
+}
124
+
79 125
 func TestLinksIpTablesRulesWhenLinkAndUnlink(t *testing.T) {
80 126
 	dockerCmd(t, "run", "-d", "--name", "child", "--publish", "8080:80", "busybox", "sleep", "10")
81 127
 	dockerCmd(t, "run", "-d", "--name", "parent", "--link", "child:http", "busybox", "sleep", "10")
82 128
new file mode 100644
... ...
@@ -0,0 +1,99 @@
0
+package main
1
+
2
+import (
3
+	"os/exec"
4
+	"strings"
5
+	"testing"
6
+)
7
+
8
+func TestRenameStoppedContainer(t *testing.T) {
9
+	runCmd := exec.Command(dockerBinary, "run", "--name", "first_name", "-d", "busybox", "sh")
10
+	out, _, err := runCommandWithOutput(runCmd)
11
+	if err != nil {
12
+		t.Fatalf(out, err)
13
+	}
14
+
15
+	cleanedContainerID := stripTrailingCharacters(out)
16
+
17
+	runCmd = exec.Command(dockerBinary, "wait", cleanedContainerID)
18
+	out, _, err = runCommandWithOutput(runCmd)
19
+	if err != nil {
20
+		t.Fatalf(out, err)
21
+	}
22
+
23
+	name, err := inspectField(cleanedContainerID, "Name")
24
+
25
+	runCmd = exec.Command(dockerBinary, "rename", "first_name", "new_name")
26
+	out, _, err = runCommandWithOutput(runCmd)
27
+	if err != nil {
28
+		t.Fatalf(out, err)
29
+	}
30
+
31
+	name, err = inspectField(cleanedContainerID, "Name")
32
+	if err != nil {
33
+		t.Fatal(err)
34
+	}
35
+	if name != "new_name" {
36
+		t.Fatal("Failed to rename container ", name)
37
+	}
38
+	deleteAllContainers()
39
+
40
+	logDone("rename - stopped container")
41
+}
42
+
43
+func TestRenameRunningContainer(t *testing.T) {
44
+	runCmd := exec.Command(dockerBinary, "run", "--name", "first_name", "-d", "busybox", "sh")
45
+	out, _, err := runCommandWithOutput(runCmd)
46
+	if err != nil {
47
+		t.Fatalf(out, err)
48
+	}
49
+
50
+	cleanedContainerID := stripTrailingCharacters(out)
51
+	runCmd = exec.Command(dockerBinary, "rename", "first_name", "new_name")
52
+	out, _, err = runCommandWithOutput(runCmd)
53
+	if err != nil {
54
+		t.Fatalf(out, err)
55
+	}
56
+
57
+	name, err := inspectField(cleanedContainerID, "Name")
58
+	if err != nil {
59
+		t.Fatal(err)
60
+	}
61
+	if name != "new_name" {
62
+		t.Fatal("Failed to rename container ")
63
+	}
64
+	deleteAllContainers()
65
+
66
+	logDone("rename - running container")
67
+}
68
+
69
+func TestRenameCheckNames(t *testing.T) {
70
+	runCmd := exec.Command(dockerBinary, "run", "--name", "first_name", "-d", "busybox", "sh")
71
+	out, _, err := runCommandWithOutput(runCmd)
72
+	if err != nil {
73
+		t.Fatalf(out, err)
74
+	}
75
+
76
+	runCmd = exec.Command(dockerBinary, "rename", "first_name", "new_name")
77
+	out, _, err = runCommandWithOutput(runCmd)
78
+	if err != nil {
79
+		t.Fatalf(out, err)
80
+	}
81
+
82
+	name, err := inspectField("new_name", "Name")
83
+	if err != nil {
84
+		t.Fatal(err)
85
+	}
86
+	if name != "new_name" {
87
+		t.Fatal("Failed to rename container ")
88
+	}
89
+
90
+	name, err = inspectField("first_name", "Name")
91
+	if err == nil && !strings.Contains(err.Error(), "No such image or container: first_name") {
92
+		t.Fatal(err)
93
+	}
94
+
95
+	deleteAllContainers()
96
+
97
+	logDone("rename - running container")
98
+}