Signed-off-by: Srini Brahmaroutu <srbrahma@us.ibm.com>
| ... | ... |
@@ -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"},
|
| ... | ... |
@@ -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 |
+} |