فهرست منبع

Add -name for docker run

Remove docker link
Do not add container id as default name
Create an auto generated container name if not
specified at runtime.
Michael Crosby 11 سال پیش
والد
کامیت
0d2924408b

+ 9 - 71
api.go

@@ -6,7 +6,6 @@ import (
 	"encoding/json"
 	"encoding/json"
 	"fmt"
 	"fmt"
 	"github.com/dotcloud/docker/auth"
 	"github.com/dotcloud/docker/auth"
-	"github.com/dotcloud/docker/gograph"
 	"github.com/dotcloud/docker/utils"
 	"github.com/dotcloud/docker/utils"
 	"github.com/gorilla/mux"
 	"github.com/gorilla/mux"
 	"io"
 	"io"
@@ -522,8 +521,12 @@ func postImagesPush(srv *Server, version float64, w http.ResponseWriter, r *http
 }
 }
 
 
 func postContainersCreate(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 func postContainersCreate(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	if err := parseForm(r); err != nil {
+		return nil
+	}
 	config := &Config{}
 	config := &Config{}
 	out := &APIRun{}
 	out := &APIRun{}
+	name := r.Form.Get("name")
 
 
 	if err := json.NewDecoder(r.Body).Decode(config); err != nil {
 	if err := json.NewDecoder(r.Body).Decode(config); err != nil {
 		return err
 		return err
@@ -539,7 +542,7 @@ func postContainersCreate(srv *Server, version float64, w http.ResponseWriter, r
 		config.Dns = defaultDns
 		config.Dns = defaultDns
 	}
 	}
 
 
-	id, warnings, err := srv.ContainerCreate(config)
+	id, warnings, err := srv.ContainerCreate(config, name)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
@@ -649,6 +652,10 @@ func postContainersStart(srv *Server, version float64, w http.ResponseWriter, r
 		return fmt.Errorf("Missing parameter")
 		return fmt.Errorf("Missing parameter")
 	}
 	}
 	name := vars["name"]
 	name := vars["name"]
+	// Register any links from the host config before starting the container
+	if err := srv.RegisterLinks(name, hostConfig); err != nil {
+		return err
+	}
 	if err := srv.ContainerStart(name, hostConfig); err != nil {
 	if err := srv.ContainerStart(name, hostConfig); err != nil {
 		return err
 		return err
 	}
 	}
@@ -1019,73 +1026,6 @@ func makeHttpHandler(srv *Server, logging bool, localMethod string, localRoute s
 	}
 	}
 }
 }
 
 
-func getContainersLinks(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	if err := parseForm(r); err != nil {
-		return err
-	}
-
-	runtime := srv.runtime
-	all, err := getBoolParam(r.Form.Get("all"))
-	if err != nil {
-		return err
-	}
-
-	out := []APILink{}
-	err = runtime.containerGraph.Walk("/", func(p string, e *gograph.Entity) error {
-		if container := runtime.Get(e.ID()); container != nil {
-			if !all && strings.Contains(p, container.ID) {
-				return nil
-			}
-			out = append(out, APILink{
-				Path:        p,
-				ContainerID: container.ID,
-				Image:       runtime.repositories.ImageName(container.Image),
-			})
-		}
-		return nil
-	}, -1)
-
-	if err != nil {
-		return err
-	}
-	return writeJSON(w, http.StatusOK, out)
-}
-
-func postContainerLink(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	if vars == nil {
-		return fmt.Errorf("Missing parameter")
-	}
-	values := make(map[string]string)
-	if matchesContentType(r.Header.Get("Content-Type"), "application/json") && r.Body != nil {
-		defer r.Body.Close()
-
-		dec := json.NewDecoder(r.Body)
-		if err := dec.Decode(&values); err != nil {
-			return err
-		}
-	} else {
-		return fmt.Errorf("Invalid json body")
-	}
-	currentName := values["currentName"]
-	newName := values["newName"]
-
-	if currentName == "" {
-		return fmt.Errorf("currentName cannot be empty")
-	}
-	if newName == "" {
-		return fmt.Errorf("newName cannot be empty")
-	}
-
-	if err := srv.runtime.RenameLink(currentName, newName); err != nil {
-		if strings.HasSuffix(err.Error(), "name are not unique") {
-			return fmt.Errorf("Conflict, %s already exists", newName)
-		}
-		return err
-	}
-
-	return nil
-}
-
 func createRouter(srv *Server, logging bool) (*mux.Router, error) {
 func createRouter(srv *Server, logging bool) (*mux.Router, error) {
 	r := mux.NewRouter()
 	r := mux.NewRouter()
 
 
@@ -1106,7 +1046,6 @@ func createRouter(srv *Server, logging bool) (*mux.Router, error) {
 			"/containers/{name:.*}/json":      getContainersByName,
 			"/containers/{name:.*}/json":      getContainersByName,
 			"/containers/{name:.*}/top":       getContainersTop,
 			"/containers/{name:.*}/top":       getContainersTop,
 			"/containers/{name:.*}/attach/ws": wsContainersAttach,
 			"/containers/{name:.*}/attach/ws": wsContainersAttach,
-			"/containers/links":               getContainersLinks,
 		},
 		},
 		"POST": {
 		"POST": {
 			"/auth":                         postAuth,
 			"/auth":                         postAuth,
@@ -1125,7 +1064,6 @@ func createRouter(srv *Server, logging bool) (*mux.Router, error) {
 			"/containers/{name:.*}/resize":  postContainersResize,
 			"/containers/{name:.*}/resize":  postContainersResize,
 			"/containers/{name:.*}/attach":  postContainersAttach,
 			"/containers/{name:.*}/attach":  postContainersAttach,
 			"/containers/{name:.*}/copy":    postContainersCopy,
 			"/containers/{name:.*}/copy":    postContainersCopy,
-			"/containers/link":              postContainerLink,
 		},
 		},
 		"DELETE": {
 		"DELETE": {
 			"/containers/{name:.*}": deleteContainers,
 			"/containers/{name:.*}": deleteContainers,

+ 0 - 6
api_params.go

@@ -121,9 +121,3 @@ type APICopy struct {
 	Resource string
 	Resource string
 	HostPath string
 	HostPath string
 }
 }
-
-type APILink struct {
-	Path        string
-	ContainerID string
-	Image       string
-}

+ 15 - 2
api_test.go

@@ -352,7 +352,7 @@ func TestGetContainersJSON(t *testing.T) {
 	container, _, err := runtime.Create(&Config{
 	container, _, err := runtime.Create(&Config{
 		Image: GetTestImage(runtime).ID,
 		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"echo", "test"},
 		Cmd:   []string{"echo", "test"},
-	})
+	}, "")
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -391,6 +391,7 @@ func TestGetContainersExport(t *testing.T) {
 			Image: GetTestImage(runtime).ID,
 			Image: GetTestImage(runtime).ID,
 			Cmd:   []string{"touch", "/test"},
 			Cmd:   []string{"touch", "/test"},
 		},
 		},
+		"",
 	)
 	)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
@@ -441,6 +442,7 @@ func TestGetContainersChanges(t *testing.T) {
 			Image: GetTestImage(runtime).ID,
 			Image: GetTestImage(runtime).ID,
 			Cmd:   []string{"/bin/rm", "/etc/passwd"},
 			Cmd:   []string{"/bin/rm", "/etc/passwd"},
 		},
 		},
+		"",
 	)
 	)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
@@ -485,6 +487,7 @@ func TestGetContainersTop(t *testing.T) {
 			Cmd:       []string{"/bin/sh", "-c", "cat"},
 			Cmd:       []string{"/bin/sh", "-c", "cat"},
 			OpenStdin: true,
 			OpenStdin: true,
 		},
 		},
+		"",
 	)
 	)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
@@ -566,6 +569,7 @@ func TestGetContainersByName(t *testing.T) {
 			Image: GetTestImage(runtime).ID,
 			Image: GetTestImage(runtime).ID,
 			Cmd:   []string{"echo", "test"},
 			Cmd:   []string{"echo", "test"},
 		},
 		},
+		"",
 	)
 	)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
@@ -597,6 +601,7 @@ func TestPostCommit(t *testing.T) {
 			Image: GetTestImage(runtime).ID,
 			Image: GetTestImage(runtime).ID,
 			Cmd:   []string{"touch", "/test"},
 			Cmd:   []string{"touch", "/test"},
 		},
 		},
+		"",
 	)
 	)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
@@ -692,6 +697,7 @@ func TestPostContainersKill(t *testing.T) {
 			Cmd:       []string{"/bin/cat"},
 			Cmd:       []string{"/bin/cat"},
 			OpenStdin: true,
 			OpenStdin: true,
 		},
 		},
+		"",
 	)
 	)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
@@ -734,6 +740,7 @@ func TestPostContainersRestart(t *testing.T) {
 			Cmd:       []string{"/bin/top"},
 			Cmd:       []string{"/bin/top"},
 			OpenStdin: true,
 			OpenStdin: true,
 		},
 		},
+		"",
 	)
 	)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
@@ -788,6 +795,7 @@ func TestPostContainersStart(t *testing.T) {
 			Cmd:       []string{"/bin/cat"},
 			Cmd:       []string{"/bin/cat"},
 			OpenStdin: true,
 			OpenStdin: true,
 		},
 		},
+		"",
 	)
 	)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
@@ -840,6 +848,7 @@ func TestPostContainersStop(t *testing.T) {
 			Cmd:       []string{"/bin/top"},
 			Cmd:       []string{"/bin/top"},
 			OpenStdin: true,
 			OpenStdin: true,
 		},
 		},
+		"",
 	)
 	)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
@@ -887,6 +896,7 @@ func TestPostContainersWait(t *testing.T) {
 			Cmd:       []string{"/bin/sleep", "1"},
 			Cmd:       []string{"/bin/sleep", "1"},
 			OpenStdin: true,
 			OpenStdin: true,
 		},
 		},
+		"",
 	)
 	)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
@@ -929,6 +939,7 @@ func TestPostContainersAttach(t *testing.T) {
 			Cmd:       []string{"/bin/cat"},
 			Cmd:       []string{"/bin/cat"},
 			OpenStdin: true,
 			OpenStdin: true,
 		},
 		},
+		"",
 	)
 	)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
@@ -1018,6 +1029,7 @@ func TestPostContainersAttachStderr(t *testing.T) {
 			Cmd:       []string{"/bin/sh", "-c", "/bin/cat >&2"},
 			Cmd:       []string{"/bin/sh", "-c", "/bin/cat >&2"},
 			OpenStdin: true,
 			OpenStdin: true,
 		},
 		},
+		"",
 	)
 	)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
@@ -1107,7 +1119,7 @@ func TestDeleteContainers(t *testing.T) {
 	container, _, err := runtime.Create(&Config{
 	container, _, err := runtime.Create(&Config{
 		Image: GetTestImage(runtime).ID,
 		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"touch", "/test"},
 		Cmd:   []string{"touch", "/test"},
-	})
+	}, "")
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -1299,6 +1311,7 @@ func TestPostContainersCopy(t *testing.T) {
 			Image: GetTestImage(runtime).ID,
 			Image: GetTestImage(runtime).ID,
 			Cmd:   []string{"touch", "/test.txt"},
 			Cmd:   []string{"touch", "/test.txt"},
 		},
 		},
+		"",
 	)
 	)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)

+ 3 - 3
buildfile.go

@@ -335,7 +335,7 @@ func (b *buildFile) CmdAdd(args string) error {
 
 
 	b.config.Image = b.image
 	b.config.Image = b.image
 	// Create the container and start it
 	// Create the container and start it
-	container, _, err := b.runtime.Create(b.config)
+	container, _, err := b.runtime.Create(b.config, "")
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
@@ -370,7 +370,7 @@ func (b *buildFile) run() (string, error) {
 	b.config.Image = b.image
 	b.config.Image = b.image
 
 
 	// Create the container and start it
 	// Create the container and start it
-	c, _, err := b.runtime.Create(b.config)
+	c, _, err := b.runtime.Create(b.config, "")
 	if err != nil {
 	if err != nil {
 		return "", err
 		return "", err
 	}
 	}
@@ -433,7 +433,7 @@ func (b *buildFile) commit(id string, autoCmd []string, comment string) error {
 			}
 			}
 		}
 		}
 
 
-		container, _, err := b.runtime.Create(b.config)
+		container, _, err := b.runtime.Create(b.config, "")
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}

+ 14 - 27
commands.go

@@ -91,7 +91,6 @@ func (cli *DockerCli) CmdHelp(args ...string) error {
 		{"insert", "Insert a file in an image"},
 		{"insert", "Insert a file in an image"},
 		{"inspect", "Return low-level information on a container"},
 		{"inspect", "Return low-level information on a container"},
 		{"kill", "Kill a running container"},
 		{"kill", "Kill a running container"},
-		{"link", "Link the container with a new name"},
 		{"login", "Register or Login to the docker registry server"},
 		{"login", "Register or Login to the docker registry server"},
 		{"logs", "Fetch the logs of a container"},
 		{"logs", "Fetch the logs of a container"},
 		{"port", "Lookup the public-facing port which is NAT-ed to PRIVATE_PORT"},
 		{"port", "Lookup the public-facing port which is NAT-ed to PRIVATE_PORT"},
@@ -1163,12 +1162,15 @@ func (cli *DockerCli) CmdPs(args ...string) error {
 		if !*noTrunc {
 		if !*noTrunc {
 			out.ID = utils.TruncateID(out.ID)
 			out.ID = utils.TruncateID(out.ID)
 		}
 		}
+
+		// Remove the leading / from the names
+		for i := 0; i < len(out.Names); i++ {
+			out.Names[i] = out.Names[i][1:]
+		}
+
 		if !*quiet {
 		if !*quiet {
 			if !*noTrunc {
 			if !*noTrunc {
 				out.Command = utils.Trunc(out.Command, 20)
 				out.Command = utils.Trunc(out.Command, 20)
-				for i := 0; i < len(out.Names); i++ {
-					out.Names[i] = utils.Trunc(out.Names[i], 10)
-				}
 			}
 			}
 			fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\t%s\t%s\t", out.ID, out.Image, out.Command, utils.HumanDuration(time.Now().Sub(time.Unix(out.Created, 0))), out.Status, displayablePorts(out.Ports), strings.Join(out.Names, ","))
 			fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\t%s\t%s\t", out.ID, out.Image, out.Command, utils.HumanDuration(time.Now().Sub(time.Unix(out.Created, 0))), out.Status, displayablePorts(out.Ports), strings.Join(out.Names, ","))
 			if *size {
 			if *size {
@@ -1191,27 +1193,6 @@ func (cli *DockerCli) CmdPs(args ...string) error {
 	return nil
 	return nil
 }
 }
 
 
-func (cli *DockerCli) CmdLink(args ...string) error {
-	cmd := Subcmd("link", "CURRENT_NAME NEW_NAME", "Link the container with a new name")
-	if err := cmd.Parse(args); err != nil {
-		return nil
-	}
-	if cmd.NArg() != 2 {
-		cmd.Usage()
-		return nil
-	}
-	body := map[string]string{
-		"currentName": cmd.Arg(0),
-		"newName":     cmd.Arg(1),
-	}
-
-	_, _, err := cli.call("POST", "/containers/link", body)
-	if err != nil {
-		return err
-	}
-	return nil
-}
-
 func (cli *DockerCli) CmdCommit(args ...string) error {
 func (cli *DockerCli) CmdCommit(args ...string) error {
 	cmd := Subcmd("commit", "[OPTIONS] CONTAINER [REPOSITORY [TAG]]", "Create a new image from a container's changes")
 	cmd := Subcmd("commit", "[OPTIONS] CONTAINER [REPOSITORY [TAG]]", "Create a new image from a container's changes")
 	flComment := cmd.String("m", "", "Commit message")
 	flComment := cmd.String("m", "", "Commit message")
@@ -1535,6 +1516,7 @@ func (cli *DockerCli) CmdRun(args ...string) error {
 
 
 	flSigProxy := cmd.Lookup("sig-proxy")
 	flSigProxy := cmd.Lookup("sig-proxy")
 	sigProxy, _ := strconv.ParseBool(flSigProxy.Value.String())
 	sigProxy, _ := strconv.ParseBool(flSigProxy.Value.String())
+	flName := cmd.Lookup("name")
 
 
 	var containerIDFile *os.File
 	var containerIDFile *os.File
 	if len(hostConfig.ContainerIDFile) > 0 {
 	if len(hostConfig.ContainerIDFile) > 0 {
@@ -1547,9 +1529,14 @@ func (cli *DockerCli) CmdRun(args ...string) error {
 		}
 		}
 		defer containerIDFile.Close()
 		defer containerIDFile.Close()
 	}
 	}
+	containerValues := url.Values{}
+	name := flName.Value.String()
+	if name != "" {
+		containerValues.Set("name", name)
+	}
 
 
 	//create the container
 	//create the container
-	body, statusCode, err := cli.call("POST", "/containers/create", config)
+	body, statusCode, err := cli.call("POST", "/containers/create?"+containerValues.Encode(), config)
 	//if image not found try to pull it
 	//if image not found try to pull it
 	if statusCode == 404 {
 	if statusCode == 404 {
 		_, tag := utils.ParseRepositoryTag(config.Image)
 		_, tag := utils.ParseRepositoryTag(config.Image)
@@ -1590,7 +1577,7 @@ func (cli *DockerCli) CmdRun(args ...string) error {
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}
-		body, _, err = cli.call("POST", "/containers/create", config)
+		body, _, err = cli.call("POST", "/containers/create?"+containerValues.Encode(), config)
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}

+ 4 - 2
container.go

@@ -44,6 +44,7 @@ type Container struct {
 	ResolvConfPath string
 	ResolvConfPath string
 	HostnamePath   string
 	HostnamePath   string
 	HostsPath      string
 	HostsPath      string
+	Name           string
 
 
 	cmd       *exec.Cmd
 	cmd       *exec.Cmd
 	stdout    *utils.WriteBroadcaster
 	stdout    *utils.WriteBroadcaster
@@ -167,6 +168,7 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *HostConfig,
 	flPrivileged := cmd.Bool("privileged", false, "Give extended privileges to this container")
 	flPrivileged := cmd.Bool("privileged", false, "Give extended privileges to this container")
 	flAutoRemove := cmd.Bool("rm", false, "Automatically remove the container when it exits (incompatible with -d)")
 	flAutoRemove := cmd.Bool("rm", false, "Automatically remove the container when it exits (incompatible with -d)")
 	flSigProxy := cmd.Bool("sig-proxy", false, "Proxify all received signal to the process (even in non-tty mode)")
 	flSigProxy := cmd.Bool("sig-proxy", false, "Proxify all received signal to the process (even in non-tty mode)")
+	cmd.String("name", "", "Assign a name to the container")
 
 
 	if capabilities != nil && *flMemory > 0 && !capabilities.MemoryLimit {
 	if capabilities != nil && *flMemory > 0 && !capabilities.MemoryLimit {
 		//fmt.Fprintf(stdout, "WARNING: Your kernel does not support memory limit capabilities. Limitation discarded.\n")
 		//fmt.Fprintf(stdout, "WARNING: Your kernel does not support memory limit capabilities. Limitation discarded.\n")
@@ -199,7 +201,7 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *HostConfig,
 	cmd.Var(&flLxcOpts, "lxc-conf", "Add custom lxc options -lxc-conf=\"lxc.cgroup.cpuset.cpus = 0,1\"")
 	cmd.Var(&flLxcOpts, "lxc-conf", "Add custom lxc options -lxc-conf=\"lxc.cgroup.cpuset.cpus = 0,1\"")
 
 
 	var flLinks utils.ListOpts
 	var flLinks utils.ListOpts
-	cmd.Var(&flLinks, "link", "Add link to another container (containerid:alias)")
+	cmd.Var(&flLinks, "link", "Add link to another container (name:alias)")
 
 
 	if err := cmd.Parse(args); err != nil {
 	if err := cmd.Parse(args); err != nil {
 		return nil, nil, cmd, err
 		return nil, nil, cmd, err
@@ -858,7 +860,7 @@ func (container *Container) Start(hostConfig *HostConfig) (err error) {
 	// Init any links between the parent and children
 	// Init any links between the parent and children
 	runtime := container.runtime
 	runtime := container.runtime
 
 
-	children, err := runtime.Children(fmt.Sprintf("/%s", container.ID))
+	children, err := runtime.Children(container.Name)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}

+ 36 - 5
container_test.go

@@ -23,6 +23,7 @@ func TestIDFormat(t *testing.T) {
 			Image: GetTestImage(runtime).ID,
 			Image: GetTestImage(runtime).ID,
 			Cmd:   []string{"/bin/sh", "-c", "echo hello world"},
 			Cmd:   []string{"/bin/sh", "-c", "echo hello world"},
 		},
 		},
+		"",
 	)
 	)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
@@ -393,6 +394,7 @@ func TestOutput(t *testing.T) {
 			Image: GetTestImage(runtime).ID,
 			Image: GetTestImage(runtime).ID,
 			Cmd:   []string{"echo", "-n", "foobar"},
 			Cmd:   []string{"echo", "-n", "foobar"},
 		},
 		},
+		"",
 	)
 	)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
@@ -415,6 +417,7 @@ func TestContainerNetwork(t *testing.T) {
 			Image: GetTestImage(runtime).ID,
 			Image: GetTestImage(runtime).ID,
 			Cmd:   []string{"ping", "-c", "1", "127.0.0.1"},
 			Cmd:   []string{"ping", "-c", "1", "127.0.0.1"},
 		},
 		},
+		"",
 	)
 	)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
@@ -438,6 +441,7 @@ func TestKillDifferentUser(t *testing.T) {
 		OpenStdin: true,
 		OpenStdin: true,
 		User:      "daemon",
 		User:      "daemon",
 	},
 	},
+		"",
 	)
 	)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
@@ -492,7 +496,7 @@ func TestCreateVolume(t *testing.T) {
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
-	c, _, err := runtime.Create(config)
+	c, _, err := runtime.Create(config, "")
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -511,6 +515,7 @@ func TestKill(t *testing.T) {
 		Image: GetTestImage(runtime).ID,
 		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"sleep", "2"},
 		Cmd:   []string{"sleep", "2"},
 	},
 	},
+		"",
 	)
 	)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
@@ -554,7 +559,7 @@ func TestExitCode(t *testing.T) {
 	trueContainer, _, err := runtime.Create(&Config{
 	trueContainer, _, err := runtime.Create(&Config{
 		Image: GetTestImage(runtime).ID,
 		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"/bin/true", ""},
 		Cmd:   []string{"/bin/true", ""},
-	})
+	}, "")
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -569,7 +574,7 @@ func TestExitCode(t *testing.T) {
 	falseContainer, _, err := runtime.Create(&Config{
 	falseContainer, _, err := runtime.Create(&Config{
 		Image: GetTestImage(runtime).ID,
 		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"/bin/false", ""},
 		Cmd:   []string{"/bin/false", ""},
-	})
+	}, "")
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -589,6 +594,7 @@ func TestRestart(t *testing.T) {
 		Image: GetTestImage(runtime).ID,
 		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"echo", "-n", "foobar"},
 		Cmd:   []string{"echo", "-n", "foobar"},
 	},
 	},
+		"",
 	)
 	)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
@@ -621,6 +627,7 @@ func TestRestartStdin(t *testing.T) {
 
 
 		OpenStdin: true,
 		OpenStdin: true,
 	},
 	},
+		"",
 	)
 	)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
@@ -697,6 +704,7 @@ func TestUser(t *testing.T) {
 		Image: GetTestImage(runtime).ID,
 		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"id"},
 		Cmd:   []string{"id"},
 	},
 	},
+		"",
 	)
 	)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
@@ -717,6 +725,7 @@ func TestUser(t *testing.T) {
 
 
 		User: "root",
 		User: "root",
 	},
 	},
+		"",
 	)
 	)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
@@ -737,6 +746,7 @@ func TestUser(t *testing.T) {
 
 
 		User: "0",
 		User: "0",
 	},
 	},
+		"",
 	)
 	)
 	if err != nil || container.State.ExitCode != 0 {
 	if err != nil || container.State.ExitCode != 0 {
 		t.Fatal(err)
 		t.Fatal(err)
@@ -757,6 +767,7 @@ func TestUser(t *testing.T) {
 
 
 		User: "1",
 		User: "1",
 	},
 	},
+		"",
 	)
 	)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
@@ -779,6 +790,7 @@ func TestUser(t *testing.T) {
 
 
 		User: "daemon",
 		User: "daemon",
 	},
 	},
+		"",
 	)
 	)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
@@ -799,6 +811,7 @@ func TestUser(t *testing.T) {
 
 
 		User: "unknownuser",
 		User: "unknownuser",
 	},
 	},
+		"",
 	)
 	)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
@@ -818,6 +831,7 @@ func TestMultipleContainers(t *testing.T) {
 		Image: GetTestImage(runtime).ID,
 		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"sleep", "2"},
 		Cmd:   []string{"sleep", "2"},
 	},
 	},
+		"",
 	)
 	)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
@@ -828,6 +842,7 @@ func TestMultipleContainers(t *testing.T) {
 		Image: GetTestImage(runtime).ID,
 		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"sleep", "2"},
 		Cmd:   []string{"sleep", "2"},
 	},
 	},
+		"",
 	)
 	)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
@@ -874,6 +889,7 @@ func TestStdin(t *testing.T) {
 
 
 		OpenStdin: true,
 		OpenStdin: true,
 	},
 	},
+		"",
 	)
 	)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
@@ -919,6 +935,7 @@ func TestTty(t *testing.T) {
 
 
 		OpenStdin: true,
 		OpenStdin: true,
 	},
 	},
+		"",
 	)
 	)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
@@ -962,6 +979,7 @@ func TestEnv(t *testing.T) {
 		Image: GetTestImage(runtime).ID,
 		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"env"},
 		Cmd:   []string{"env"},
 	},
 	},
+		"",
 	)
 	)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
@@ -1013,6 +1031,7 @@ func TestEntrypoint(t *testing.T) {
 			Entrypoint: []string{"/bin/echo"},
 			Entrypoint: []string{"/bin/echo"},
 			Cmd:        []string{"-n", "foobar"},
 			Cmd:        []string{"-n", "foobar"},
 		},
 		},
+		"",
 	)
 	)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
@@ -1035,6 +1054,7 @@ func TestEntrypointNoCmd(t *testing.T) {
 			Image:      GetTestImage(runtime).ID,
 			Image:      GetTestImage(runtime).ID,
 			Entrypoint: []string{"/bin/echo", "foobar"},
 			Entrypoint: []string{"/bin/echo", "foobar"},
 		},
 		},
+		"",
 	)
 	)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
@@ -1089,6 +1109,7 @@ func TestLXCConfig(t *testing.T) {
 		Memory:    int64(mem),
 		Memory:    int64(mem),
 		CpuShares: int64(cpu),
 		CpuShares: int64(cpu),
 	},
 	},
+		"",
 	)
 	)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
@@ -1111,6 +1132,7 @@ func TestCustomLxcConfig(t *testing.T) {
 
 
 		Hostname: "foobar",
 		Hostname: "foobar",
 	},
 	},
+		"",
 	)
 	)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
@@ -1140,6 +1162,7 @@ func BenchmarkRunSequencial(b *testing.B) {
 			Image: GetTestImage(runtime).ID,
 			Image: GetTestImage(runtime).ID,
 			Cmd:   []string{"echo", "-n", "foo"},
 			Cmd:   []string{"echo", "-n", "foo"},
 		},
 		},
+			"",
 		)
 		)
 		if err != nil {
 		if err != nil {
 			b.Fatal(err)
 			b.Fatal(err)
@@ -1172,6 +1195,7 @@ func BenchmarkRunParallel(b *testing.B) {
 				Image: GetTestImage(runtime).ID,
 				Image: GetTestImage(runtime).ID,
 				Cmd:   []string{"echo", "-n", "foo"},
 				Cmd:   []string{"echo", "-n", "foo"},
 			},
 			},
+				"",
 			)
 			)
 			if err != nil {
 			if err != nil {
 				complete <- err
 				complete <- err
@@ -1324,6 +1348,7 @@ func TestVolumesFromReadonlyMount(t *testing.T) {
 			Cmd:     []string{"/bin/echo", "-n", "foobar"},
 			Cmd:     []string{"/bin/echo", "-n", "foobar"},
 			Volumes: map[string]struct{}{"/test": {}},
 			Volumes: map[string]struct{}{"/test": {}},
 		},
 		},
+		"",
 	)
 	)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
@@ -1343,6 +1368,7 @@ func TestVolumesFromReadonlyMount(t *testing.T) {
 			Cmd:         []string{"/bin/echo", "-n", "foobar"},
 			Cmd:         []string{"/bin/echo", "-n", "foobar"},
 			VolumesFrom: container.ID,
 			VolumesFrom: container.ID,
 		},
 		},
+		"",
 	)
 	)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
@@ -1378,6 +1404,7 @@ func TestRestartWithVolumes(t *testing.T) {
 		Cmd:     []string{"echo", "-n", "foobar"},
 		Cmd:     []string{"echo", "-n", "foobar"},
 		Volumes: map[string]struct{}{"/test": {}},
 		Volumes: map[string]struct{}{"/test": {}},
 	},
 	},
+		"",
 	)
 	)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
@@ -1421,6 +1448,7 @@ func TestVolumesFromWithVolumes(t *testing.T) {
 		Cmd:     []string{"sh", "-c", "echo -n bar > /test/foo"},
 		Cmd:     []string{"sh", "-c", "echo -n bar > /test/foo"},
 		Volumes: map[string]struct{}{"/test": {}},
 		Volumes: map[string]struct{}{"/test": {}},
 	},
 	},
+		"",
 	)
 	)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
@@ -1450,6 +1478,7 @@ func TestVolumesFromWithVolumes(t *testing.T) {
 			VolumesFrom: container.ID,
 			VolumesFrom: container.ID,
 			Volumes:     map[string]struct{}{"/test": {}},
 			Volumes:     map[string]struct{}{"/test": {}},
 		},
 		},
+		"",
 	)
 	)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
@@ -1484,7 +1513,7 @@ func TestOnlyLoopbackExistsWhenUsingDisableNetworkOption(t *testing.T) {
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
-	c, _, err := runtime.Create(config)
+	c, _, err := runtime.Create(config, "")
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -1555,6 +1584,7 @@ func TestMultipleVolumesFrom(t *testing.T) {
 		Cmd:     []string{"sh", "-c", "echo -n bar > /test/foo"},
 		Cmd:     []string{"sh", "-c", "echo -n bar > /test/foo"},
 		Volumes: map[string]struct{}{"/test": {}},
 		Volumes: map[string]struct{}{"/test": {}},
 	},
 	},
+		"",
 	)
 	)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
@@ -1583,6 +1613,7 @@ func TestMultipleVolumesFrom(t *testing.T) {
 			Cmd:     []string{"sh", "-c", "echo -n bar > /other/foo"},
 			Cmd:     []string{"sh", "-c", "echo -n bar > /other/foo"},
 			Volumes: map[string]struct{}{"/other": {}},
 			Volumes: map[string]struct{}{"/other": {}},
 		},
 		},
+		"",
 	)
 	)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
@@ -1603,7 +1634,7 @@ func TestMultipleVolumesFrom(t *testing.T) {
 			Image:       GetTestImage(runtime).ID,
 			Image:       GetTestImage(runtime).ID,
 			Cmd:         []string{"/bin/echo", "-n", "foobar"},
 			Cmd:         []string{"/bin/echo", "-n", "foobar"},
 			VolumesFrom: strings.Join([]string{container.ID, container2.ID}, ","),
 			VolumesFrom: strings.Join([]string{container.ID, container2.ID}, ","),
-		})
+		}, "")
 
 
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)

+ 1 - 0
docs/sources/api/docker_remote_api_v1.6.rst

@@ -151,6 +151,7 @@ Create a container
 	   }
 	   }
 	
 	
 	:jsonparam config: the container's configuration
 	:jsonparam config: the container's configuration
+ 	:query name: container name to use
 	:statuscode 201: no error
 	:statuscode 201: no error
 	:statuscode 404: no such container
 	:statuscode 404: no such container
 	:statuscode 406: impossible to attach (container not running)
 	:statuscode 406: impossible to attach (container not running)

+ 12 - 30
docs/sources/commandline/cli.rst

@@ -403,33 +403,6 @@ Insert file from github
 
 
     Kill a running container
     Kill a running container
 
 
-.. _cli_link:
-
-``link``
---------
-
-::
-
-    Usage: docker link CURRENT_NAME NEW_NAME
-
-    Link a container to a new name.
-
-
-Examples:
-~~~~~~~~~
-
-.. code-block:: bash
-
-    $ docker link /59669e088202c2ebe150b4346cb3301562d073b51261176a354a74e8f618bfbc /redis
-    $ docker ls
-    NAME                                                                      ID                                                                 IMAGE
-    /redis                                                                    59669e088202c2ebe150b4346cb3301562d073b51261176a354a74e8f618bfbc   crosbymichael/redis:latest
-    /59669e088202c2ebe150b4346cb3301562d073b51261176a354a74e8f618bfbc         59669e088202c2ebe150b4346cb3301562d073b51261176a354a74e8f618bfbc   crosbymichael/redis:latest
-
-
-This will create a new link for the existing name ``/59669e088202c2ebe150b4346cb3301562d073b51261176a354a74e8f618bfbc`` 
-with the new name ``/redis`` so that we can new reference the same container under the new name ``/redis``.
-
 .. _cli_login:
 .. _cli_login:
 
 
 ``login``
 ``login``
@@ -604,7 +577,8 @@ network communication.
       -lxc-conf=[]: Add custom lxc options -lxc-conf="lxc.cgroup.cpuset.cpus = 0,1"
       -lxc-conf=[]: Add custom lxc options -lxc-conf="lxc.cgroup.cpuset.cpus = 0,1"
       -sig-proxy=false: Proxify all received signal to the process (even in non-tty mode)
       -sig-proxy=false: Proxify all received signal to the process (even in non-tty mode)
       -expose=[]: Expose a port from the container without publishing it to your host
       -expose=[]: Expose a port from the container without publishing it to your host
-      -link="": Add link to another container (containerid:alias)
+      -link="": Add link to another container (name:alias)
+      -name="": Assign the specified name to the container. If no name is specific docker will generate a random name
 
 
 Examples
 Examples
 --------
 --------
@@ -680,12 +654,20 @@ without publishing the port to the host system's interfaces.
 
 
 .. code-block:: bash
 .. code-block:: bash
 
 
-    docker run -link /redis:redis ubuntu bash
+    docker run -name console -t -i ubuntu bash
+
+This will create and run a new container with the container name 
+being ``console``.
+
+.. code-block:: bash
+
+    docker run -link /redis:redis -name console ubuntu bash
 
 
 The ``-link`` flag will link the container named ``/redis`` into the 
 The ``-link`` flag will link the container named ``/redis`` into the 
 newly created container with the alias ``redis``.  The new container
 newly created container with the alias ``redis``.  The new container
 can access the network and environment of the redis container via
 can access the network and environment of the redis container via
-environment variables.
+environment variables.  The ``-name`` flag will assign the name ``console`` 
+to the newly created container.
 
 
 .. _cli_search:
 .. _cli_search:
 
 

+ 11 - 23
docs/sources/examples/linking_into_redis.rst

@@ -54,26 +54,14 @@ Run the redis container
 
 
 .. code-block:: bash
 .. code-block:: bash
     
     
-    docker run -d -e PASSWORD=docker crosbymichael/redis --requirepass docker
+    docker run -d -e PASSWORD=docker -name redis crosbymichael/redis --requirepass=docker
  
  
-This will run our redis container using the default port of 6379 and using
-as password to secure our service. Next we will link the redis container to 
-a new name using ``docker link``.
-
-
-Linking an existing container
------------------------------
-
-Docker will automatically create an initial link with the container's id but
-because the is long and not very user friendly we can link the container with
-a new name.
-
-.. code-block:: bash
-
-    docker link /39588b6a45100ef5b328b2c302ea085624f29e6cbab70f88be04793af02cec89 /redis
-
-Now we can reference our running redis service using the friendly name ``/redis``.  
-We can issue all the commands that you would expect; start, stop, attach, using the new name.
+This will run our redis container using the default port of 6379 and using docker 
+as password to secure our service.  By specifying the ``-name`` flag on run 
+we will assign the name ``redis`` to this container. 
+We can issue all the commands that you would expect; start, stop, attach, using the name.
+The name also allows us to link other containers into this one.  If you do not specify a 
+name on docker run, docker will automatically generate a name for your container. 
 
 
 Linking redis as a child
 Linking redis as a child
 ------------------------
 ------------------------
@@ -90,12 +78,12 @@ Now lets start our web application with a link into redis.
 
 
 .. code-block:: bash
 .. code-block:: bash
    
    
-    docker run -t -i -link /redis:db ubuntu bash
+    docker run -t -i -link /redis:db -name webapp ubuntu bash
 
 
     root@4c01db0b339c:/# env
     root@4c01db0b339c:/# env
 
 
     HOSTNAME=4c01db0b339c
     HOSTNAME=4c01db0b339c
-    DB_NAME=/4c01db0b339cf19958731255a796ee072040a652f51652a4ade190ab8c27006f/db
+    DB_NAME=/webapp/db
     TERM=xterm
     TERM=xterm
     DB_PORT=tcp://172.17.0.8:6379
     DB_PORT=tcp://172.17.0.8:6379
     DB_PORT_6379_TCP=tcp://172.17.0.8:6379
     DB_PORT_6379_TCP=tcp://172.17.0.8:6379
@@ -118,7 +106,7 @@ network and environment information from the child.
 .. code-block:: bash
 .. code-block:: bash
 
 
     # The name of the child container
     # The name of the child container
-    DB_NAME=/4c01db0b339cf19958731255a796ee072040a652f51652a4ade190ab8c27006f/db
+    DB_NAME=/webapp/db
     # The default protocol, ip, and port of the service running in the container
     # The default protocol, ip, and port of the service running in the container
     DB_PORT=tcp://172.17.0.8:6379
     DB_PORT=tcp://172.17.0.8:6379
     # A specific protocol, ip, and port of various services
     # A specific protocol, ip, and port of various services
@@ -129,4 +117,4 @@ network and environment information from the child.
 
 
 Accessing the network information along with the environment of the child container allows
 Accessing the network information along with the environment of the child container allows
 us to easily connect to the redis service on the specific ip and port and use the password
 us to easily connect to the redis service on the specific ip and port and use the password
-specified in the environment.  
+specified in the environment.

+ 18 - 6
gograph/gograph.go

@@ -132,6 +132,11 @@ func (db *Database) Set(fullPath, id string) (*Entity, error) {
 	return e, nil
 	return e, nil
 }
 }
 
 
+// Return true if a name already exists in the database
+func (db *Database) Exists(name string) bool {
+	return db.Get(name) != nil
+}
+
 func (db *Database) setEdge(parentPath, name string, e *Entity) error {
 func (db *Database) setEdge(parentPath, name string, e *Entity) error {
 	parent, err := db.get(parentPath)
 	parent, err := db.get(parentPath)
 	if err != nil {
 	if err != nil {
@@ -189,14 +194,22 @@ func (db *Database) get(name string) (*Entity, error) {
 // The key will be the full path of the entity
 // The key will be the full path of the entity
 func (db *Database) List(name string, depth int) Entities {
 func (db *Database) List(name string, depth int) Entities {
 	out := Entities{}
 	out := Entities{}
-	for c := range db.children(name, depth) {
+	e, err := db.get(name)
+	if err != nil {
+		return out
+	}
+	for c := range db.children(e, name, depth) {
 		out[c.FullPath] = c.Entity
 		out[c.FullPath] = c.Entity
 	}
 	}
 	return out
 	return out
 }
 }
 
 
 func (db *Database) Walk(name string, walkFunc WalkFunc, depth int) error {
 func (db *Database) Walk(name string, walkFunc WalkFunc, depth int) error {
-	for c := range db.children(name, depth) {
+	e, err := db.get(name)
+	if err != nil {
+		return err
+	}
+	for c := range db.children(e, name, depth) {
 		if err := walkFunc(c.FullPath, c.Entity); err != nil {
 		if err := walkFunc(c.FullPath, c.Entity); err != nil {
 			return err
 			return err
 		}
 		}
@@ -327,10 +340,9 @@ type WalkMeta struct {
 	Edge     *Edge
 	Edge     *Edge
 }
 }
 
 
-func (db *Database) children(name string, depth int) <-chan WalkMeta {
+func (db *Database) children(e *Entity, name string, depth int) <-chan WalkMeta {
 	out := make(chan WalkMeta)
 	out := make(chan WalkMeta)
-	e, err := db.get(name)
-	if err != nil {
+	if e == nil {
 		close(out)
 		close(out)
 		return out
 		return out
 	}
 	}
@@ -370,7 +382,7 @@ func (db *Database) children(name string, depth int) <-chan WalkMeta {
 			if depth != -1 {
 			if depth != -1 {
 				nDepth -= 1
 				nDepth -= 1
 			}
 			}
-			sc := db.children(meta.FullPath, nDepth)
+			sc := db.children(child, meta.FullPath, nDepth)
 			for c := range sc {
 			for c := range sc {
 				out <- c
 				out <- c
 			}
 			}

+ 24 - 0
gograph/gograph_test.go

@@ -28,6 +28,7 @@ func TestNewDatabase(t *testing.T) {
 	if db == nil {
 	if db == nil {
 		t.Fatal("Database should not be nil")
 		t.Fatal("Database should not be nil")
 	}
 	}
+	db.Close()
 	defer destroyTestDb(dbpath)
 	defer destroyTestDb(dbpath)
 }
 }
 
 
@@ -465,3 +466,26 @@ func TestRefPaths(t *testing.T) {
 		t.Fatalf("Expected reference count to be 2, got %d", len(refs))
 		t.Fatalf("Expected reference count to be 2, got %d", len(refs))
 	}
 	}
 }
 }
+
+func TestExistsTrue(t *testing.T) {
+	db, dbpath := newTestDb(t)
+	defer destroyTestDb(dbpath)
+
+	db.Set("/testing", "1")
+
+	if !db.Exists("/testing") {
+		t.Fatalf("/tesing should exist")
+	}
+}
+
+func TestExistsFalse(t *testing.T) {
+	db, dbpath := newTestDb(t)
+	defer destroyTestDb(dbpath)
+
+	db.Set("toerhe", "1")
+
+	if db.Exists("/testing") {
+		t.Fatalf("/tesing should not exist")
+	}
+
+}

+ 1 - 1
links.go

@@ -54,7 +54,7 @@ func (l *Link) ToEnv() []string {
 	alias := strings.ToUpper(l.Alias())
 	alias := strings.ToUpper(l.Alias())
 
 
 	if p := l.getDefaultPort(); p != nil {
 	if p := l.getDefaultPort(); p != nil {
-		env = append(env, fmt.Sprintf("%s_PORT=%s:%s", alias, l.ChildIP, p.Port()))
+		env = append(env, fmt.Sprintf("%s_PORT=%s://%s:%s", alias, p.Proto(), l.ChildIP, p.Port()))
 	}
 	}
 
 
 	// Load exposed ports into the environment
 	// Load exposed ports into the environment

+ 1 - 1
links_test.go

@@ -89,7 +89,7 @@ func TestLinkEnv(t *testing.T) {
 		}
 		}
 		env[parts[0]] = parts[1]
 		env[parts[0]] = parts[1]
 	}
 	}
-	if env["DOCKER_PORT"] != "172.0.17.2:6379" {
+	if env["DOCKER_PORT"] != "tcp://172.0.17.2:6379" {
 		t.Fatalf("Expected 172.0.17.2:6379, got %s", env["DOCKER_PORT"])
 		t.Fatalf("Expected 172.0.17.2:6379, got %s", env["DOCKER_PORT"])
 	}
 	}
 	if env["DOCKER_PORT_6379_TCP"] != "tcp://172.0.17.2:6379" {
 	if env["DOCKER_PORT_6379_TCP"] != "tcp://172.0.17.2:6379" {

+ 0 - 0
names-generator/names-generator.go → namesgenerator/names-generator.go


+ 0 - 0
names-generator/names-generator_test.go → namesgenerator/names-generator_test.go


+ 23 - 53
runtime.go

@@ -265,7 +265,10 @@ func (runtime *Runtime) restore() error {
 	// Any containers that are left over do not exist in the graph
 	// Any containers that are left over do not exist in the graph
 	for _, container := range containers {
 	for _, container := range containers {
 		// Try to set the default name for a container if it exists prior to links
 		// Try to set the default name for a container if it exists prior to links
-		if _, err := runtime.containerGraph.Set(fmt.Sprintf("/%s", container.ID), container.ID); err != nil {
+		name := generateRandomName(runtime)
+		container.Name = name
+
+		if _, err := runtime.containerGraph.Set(name, container.ID); err != nil {
 			utils.Debugf("Setting default id - %s", err)
 			utils.Debugf("Setting default id - %s", err)
 		}
 		}
 		register(container)
 		register(container)
@@ -306,8 +309,8 @@ func (runtime *Runtime) UpdateCapabilities(quiet bool) {
 	}
 	}
 }
 }
 
 
-// Create creates a new container from the given configuration.
-func (runtime *Runtime) Create(config *Config) (*Container, []string, error) {
+// Create creates a new container from the given configuration with a given name.
+func (runtime *Runtime) Create(config *Config, name string) (*Container, []string, error) {
 	// Lookup image
 	// Lookup image
 	img, err := runtime.repositories.LookupImage(config.Image)
 	img, err := runtime.repositories.LookupImage(config.Image)
 	if err != nil {
 	if err != nil {
@@ -345,8 +348,15 @@ func (runtime *Runtime) Create(config *Config) (*Container, []string, error) {
 	// Generate id
 	// Generate id
 	id := GenerateID()
 	id := GenerateID()
 
 
-	// Set the default enitity in the graph
-	if _, err := runtime.containerGraph.Set(fmt.Sprintf("/%s", id), id); err != nil {
+	if name == "" {
+		name = generateRandomName(runtime)
+	}
+	if name[0] != '/' {
+		name = "/" + name
+	}
+
+	// Set the enitity in the graph using the default name specified
+	if _, err := runtime.containerGraph.Set(name, id); err != nil {
 		return nil, nil, err
 		return nil, nil, err
 	}
 	}
 
 
@@ -378,6 +388,7 @@ func (runtime *Runtime) Create(config *Config) (*Container, []string, error) {
 		NetworkSettings: &NetworkSettings{},
 		NetworkSettings: &NetworkSettings{},
 		// FIXME: do we need to store this in the container?
 		// FIXME: do we need to store this in the container?
 		SysInitPath: sysInitPath,
 		SysInitPath: sysInitPath,
+		Name:        name,
 	}
 	}
 	container.root = runtime.containerRoot(container.ID)
 	container.root = runtime.containerRoot(container.ID)
 	// Step 1: create the container directory.
 	// Step 1: create the container directory.
@@ -483,16 +494,7 @@ func (runtime *Runtime) Commit(container *Container, repository, tag, comment, a
 	return img, nil
 	return img, nil
 }
 }
 
 
-// Strip the leading slash from the name to look up if it
-// is a truncated id
-// Prepend the slash back after finding the name
 func (runtime *Runtime) getFullName(name string) string {
 func (runtime *Runtime) getFullName(name string) string {
-	if name[0] == '/' {
-		name = name[1:]
-	}
-	if id, err := runtime.idIndex.Get(name); err == nil {
-		name = id
-	}
 	if name[0] != '/' {
 	if name[0] != '/' {
 		name = "/" + name
 		name = "/" + name
 	}
 	}
@@ -500,9 +502,7 @@ func (runtime *Runtime) getFullName(name string) string {
 }
 }
 
 
 func (runtime *Runtime) GetByName(name string) (*Container, error) {
 func (runtime *Runtime) GetByName(name string) (*Container, error) {
-	name = runtime.getFullName(name)
-
-	entity := runtime.containerGraph.Get(name)
+	entity := runtime.containerGraph.Get(runtime.getFullName(name))
 	if entity == nil {
 	if entity == nil {
 		return nil, fmt.Errorf("Could not find entity for %s", name)
 		return nil, fmt.Errorf("Could not find entity for %s", name)
 	}
 	}
@@ -514,6 +514,7 @@ func (runtime *Runtime) GetByName(name string) (*Container, error) {
 }
 }
 
 
 func (runtime *Runtime) Children(name string) (map[string]*Container, error) {
 func (runtime *Runtime) Children(name string) (map[string]*Container, error) {
+	name = runtime.getFullName(name)
 	children := make(map[string]*Container)
 	children := make(map[string]*Container)
 
 
 	err := runtime.containerGraph.Walk(name, func(p string, e *gograph.Entity) error {
 	err := runtime.containerGraph.Walk(name, func(p string, e *gograph.Entity) error {
@@ -531,44 +532,13 @@ func (runtime *Runtime) Children(name string) (map[string]*Container, error) {
 	return children, nil
 	return children, nil
 }
 }
 
 
-func (runtime *Runtime) RenameLink(oldName, newName string) error {
-	oldName = runtime.getFullName(oldName)
-
-	entity := runtime.containerGraph.Get(oldName)
-	if entity == nil {
-		return fmt.Errorf("Could not find entity for %s", oldName)
-	}
-
-	if newName[0] != '/' {
-		newName = "/" + newName
-	}
-
-	// This is not rename but adding a new link for the default name
-	// Strip the leading '/'
-	if entity.ID() == oldName[1:] {
-		_, err := runtime.containerGraph.Set(newName, entity.ID())
+func (runtime *Runtime) RegisterLink(parent, child *Container, alias string) error {
+	fullName := path.Join(parent.Name, alias)
+	if !runtime.containerGraph.Exists(fullName) {
+		_, err := runtime.containerGraph.Set(fullName, child.ID)
 		return err
 		return err
 	}
 	}
-	return runtime.containerGraph.Rename(oldName, newName)
-}
-
-func (runtime *Runtime) Link(parentName, childName, alias string) error {
-	if id, err := runtime.idIndex.Get(parentName); err == nil {
-		parentName = id
-	}
-	parent := runtime.containerGraph.Get(parentName)
-	if parent == nil {
-		return fmt.Errorf("Could not get container for %s", parentName)
-	}
-	if id, err := runtime.idIndex.Get(childName); err == nil {
-		childName = id
-	}
-	child := runtime.containerGraph.Get(childName)
-	if child == nil {
-		return fmt.Errorf("Could not get container for %s", childName)
-	}
-	_, err := runtime.containerGraph.Set(path.Join(parentName, alias), child.ID())
-	return err
+	return nil
 }
 }
 
 
 // FIXME: harmonize with NewGraph()
 // FIXME: harmonize with NewGraph()

+ 39 - 38
runtime_test.go

@@ -197,6 +197,7 @@ func TestRuntimeCreate(t *testing.T) {
 		Image: GetTestImage(runtime).ID,
 		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"ls", "-al"},
 		Cmd:   []string{"ls", "-al"},
 	},
 	},
+		"",
 	)
 	)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
@@ -234,7 +235,7 @@ func TestRuntimeCreate(t *testing.T) {
 	}
 	}
 
 
 	// Make sure create with bad parameters returns an error
 	// Make sure create with bad parameters returns an error
-	if _, _, err = runtime.Create(&Config{Image: GetTestImage(runtime).ID}); err == nil {
+	if _, _, err = runtime.Create(&Config{Image: GetTestImage(runtime).ID}, ""); err == nil {
 		t.Fatal("Builder.Create should throw an error when Cmd is missing")
 		t.Fatal("Builder.Create should throw an error when Cmd is missing")
 	}
 	}
 
 
@@ -243,6 +244,7 @@ func TestRuntimeCreate(t *testing.T) {
 			Image: GetTestImage(runtime).ID,
 			Image: GetTestImage(runtime).ID,
 			Cmd:   []string{},
 			Cmd:   []string{},
 		},
 		},
+		"",
 	); err == nil {
 	); err == nil {
 		t.Fatal("Builder.Create should throw an error when Cmd is empty")
 		t.Fatal("Builder.Create should throw an error when Cmd is empty")
 	}
 	}
@@ -252,7 +254,7 @@ func TestRuntimeCreate(t *testing.T) {
 		Cmd:       []string{"/bin/ls"},
 		Cmd:       []string{"/bin/ls"},
 		PortSpecs: []string{"80"},
 		PortSpecs: []string{"80"},
 	}
 	}
-	container, _, err = runtime.Create(config)
+	container, _, err = runtime.Create(config, "")
 
 
 	_, err = runtime.Commit(container, "testrepo", "testtag", "", "", config)
 	_, err = runtime.Commit(container, "testrepo", "testtag", "", "", config)
 	if err != nil {
 	if err != nil {
@@ -267,7 +269,7 @@ func TestDestroy(t *testing.T) {
 	container, _, err := runtime.Create(&Config{
 	container, _, err := runtime.Create(&Config{
 		Image: GetTestImage(runtime).ID,
 		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"ls", "-al"},
 		Cmd:   []string{"ls", "-al"},
-	})
+	}, "")
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -361,7 +363,7 @@ func startEchoServerContainer(t *testing.T, proto string) (*Runtime, *Container,
 			Cmd:          []string{"sh", "-c", cmd},
 			Cmd:          []string{"sh", "-c", cmd},
 			PortSpecs:    []string{fmt.Sprintf("%s/%s", strPort, proto)},
 			PortSpecs:    []string{fmt.Sprintf("%s/%s", strPort, proto)},
 			ExposedPorts: ep,
 			ExposedPorts: ep,
-		})
+		}, "")
 		if err != nil {
 		if err != nil {
 			nuke(runtime)
 			nuke(runtime)
 			t.Fatal(err)
 			t.Fatal(err)
@@ -573,6 +575,9 @@ func TestReloadContainerLinks(t *testing.T) {
 	h1 := &HostConfig{}
 	h1 := &HostConfig{}
 	// Add a link to container 2
 	// Add a link to container 2
 	h1.Links = []string{"/" + container2.ID + ":first"}
 	h1.Links = []string{"/" + container2.ID + ":first"}
+	if err := runtime1.RegisterLink(container1, container2, "first"); err != nil {
+		t.Fatal(err)
+	}
 	if err := container1.Start(h1); err != nil {
 	if err := container1.Start(h1); err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -620,7 +625,7 @@ func TestReloadContainerLinks(t *testing.T) {
 
 
 	t.Logf("Number of links: %d", runtime2.containerGraph.Refs("0"))
 	t.Logf("Number of links: %d", runtime2.containerGraph.Refs("0"))
 	// Verify that the link is still registered in the runtime
 	// Verify that the link is still registered in the runtime
-	entity := runtime2.containerGraph.Get(fmt.Sprintf("/%s", container1.ID))
+	entity := runtime2.containerGraph.Get(container1.Name)
 	if entity == nil {
 	if entity == nil {
 		t.Fatal("Entity should not be nil")
 		t.Fatal("Entity should not be nil")
 	}
 	}
@@ -636,13 +641,17 @@ func TestDefaultContainerName(t *testing.T) {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 
 
-	shortId, _, err := srv.ContainerCreate(config)
+	shortId, _, err := srv.ContainerCreate(config, "some_name")
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 	container := runtime.Get(shortId)
 	container := runtime.Get(shortId)
 	containerID := container.ID
 	containerID := container.ID
 
 
+	if container.Name != "/some_name" {
+		t.Fatalf("Expect /some_name got %s", container.Name)
+	}
+
 	paths := runtime.containerGraph.RefPaths(containerID)
 	paths := runtime.containerGraph.RefPaths(containerID)
 	if paths == nil || len(paths) == 0 {
 	if paths == nil || len(paths) == 0 {
 		t.Fatalf("Could not find edges for %s", containerID)
 		t.Fatalf("Could not find edges for %s", containerID)
@@ -654,12 +663,12 @@ func TestDefaultContainerName(t *testing.T) {
 	if edge.EntityID != containerID {
 	if edge.EntityID != containerID {
 		t.Fatalf("Expected %s got %s", containerID, edge.EntityID)
 		t.Fatalf("Expected %s got %s", containerID, edge.EntityID)
 	}
 	}
-	if edge.Name != containerID {
-		t.Fatalf("Expected %s got %s", containerID, edge.Name)
+	if edge.Name != "some_name" {
+		t.Fatalf("Expected some_name got %s", edge.Name)
 	}
 	}
 }
 }
 
 
-func TestDefaultContainerRename(t *testing.T) {
+func TestRandomContainerName(t *testing.T) {
 	runtime := mkRuntime(t)
 	runtime := mkRuntime(t)
 	defer nuke(runtime)
 	defer nuke(runtime)
 	srv := &Server{runtime: runtime}
 	srv := &Server{runtime: runtime}
@@ -669,24 +678,30 @@ func TestDefaultContainerRename(t *testing.T) {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 
 
-	shortId, _, err := srv.ContainerCreate(config)
+	shortId, _, err := srv.ContainerCreate(config, "")
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 	container := runtime.Get(shortId)
 	container := runtime.Get(shortId)
 	containerID := container.ID
 	containerID := container.ID
 
 
-	if err := runtime.RenameLink(fmt.Sprintf("/%s", containerID), "/webapp"); err != nil {
-		t.Fatal(err)
+	if container.Name == "" {
+		t.Fatalf("Expected not empty container name")
 	}
 	}
 
 
-	webapp, err := runtime.GetByName("/webapp")
-	if err != nil {
-		t.Fatal(err)
+	paths := runtime.containerGraph.RefPaths(containerID)
+	if paths == nil || len(paths) == 0 {
+		t.Fatalf("Could not find edges for %s", containerID)
 	}
 	}
-
-	if webapp.ID != container.ID {
-		t.Fatalf("Expect webapp id to match container id: %s != %s", webapp.ID, container.ID)
+	edge := paths[0]
+	if edge.ParentID != "0" {
+		t.Fatalf("Expected engine got %s", edge.ParentID)
+	}
+	if edge.EntityID != containerID {
+		t.Fatalf("Expected %s got %s", containerID, edge.EntityID)
+	}
+	if edge.Name == "" {
+		t.Fatalf("Expected not empty container name")
 	}
 	}
 }
 }
 
 
@@ -700,16 +715,12 @@ func TestLinkChildContainer(t *testing.T) {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 
 
-	shortId, _, err := srv.ContainerCreate(config)
+	shortId, _, err := srv.ContainerCreate(config, "/webapp")
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 	container := runtime.Get(shortId)
 	container := runtime.Get(shortId)
 
 
-	if err := runtime.RenameLink(fmt.Sprintf("/%s", container.ID), "/webapp"); err != nil {
-		t.Fatal(err)
-	}
-
 	webapp, err := runtime.GetByName("/webapp")
 	webapp, err := runtime.GetByName("/webapp")
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
@@ -724,17 +735,14 @@ func TestLinkChildContainer(t *testing.T) {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 
 
-	shortId, _, err = srv.ContainerCreate(config)
+	shortId, _, err = srv.ContainerCreate(config, "")
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 
 
 	childContainer := runtime.Get(shortId)
 	childContainer := runtime.Get(shortId)
-	if err := runtime.RenameLink(fmt.Sprintf("/%s", childContainer.ID), "/db"); err != nil {
-		t.Fatal(err)
-	}
 
 
-	if err := runtime.Link("/webapp", "/db", "db"); err != nil {
+	if err := runtime.RegisterLink(webapp, childContainer, "db"); err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 
 
@@ -758,16 +766,12 @@ func TestGetAllChildren(t *testing.T) {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 
 
-	shortId, _, err := srv.ContainerCreate(config)
+	shortId, _, err := srv.ContainerCreate(config, "/webapp")
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 	container := runtime.Get(shortId)
 	container := runtime.Get(shortId)
 
 
-	if err := runtime.RenameLink(fmt.Sprintf("/%s", container.ID), "/webapp"); err != nil {
-		t.Fatal(err)
-	}
-
 	webapp, err := runtime.GetByName("/webapp")
 	webapp, err := runtime.GetByName("/webapp")
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
@@ -782,17 +786,14 @@ func TestGetAllChildren(t *testing.T) {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 
 
-	shortId, _, err = srv.ContainerCreate(config)
+	shortId, _, err = srv.ContainerCreate(config, "")
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 
 
 	childContainer := runtime.Get(shortId)
 	childContainer := runtime.Get(shortId)
-	if err := runtime.RenameLink(fmt.Sprintf("/%s", childContainer.ID), "/db"); err != nil {
-		t.Fatal(err)
-	}
 
 
-	if err := runtime.Link("/webapp", "/db", "db"); err != nil {
+	if err := runtime.RegisterLink(webapp, childContainer, "db"); err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 
 

+ 21 - 10
server.go

@@ -156,7 +156,7 @@ func (srv *Server) ImageInsert(name, url, path string, out io.Writer, sf *utils.
 		return "", err
 		return "", err
 	}
 	}
 
 
-	c, _, err := srv.runtime.Create(config)
+	c, _, err := srv.runtime.Create(config, "")
 	if err != nil {
 	if err != nil {
 		return "", err
 		return "", err
 	}
 	}
@@ -937,7 +937,7 @@ func (srv *Server) ImageImport(src, repo, tag string, in io.Reader, out io.Write
 	return nil
 	return nil
 }
 }
 
 
-func (srv *Server) ContainerCreate(config *Config) (string, []string, error) {
+func (srv *Server) ContainerCreate(config *Config, name string) (string, []string, error) {
 	if config.Memory != 0 && config.Memory < 524288 {
 	if config.Memory != 0 && config.Memory < 524288 {
 		return "", nil, fmt.Errorf("Memory limit must be given in bytes (minimum 524288 bytes)")
 		return "", nil, fmt.Errorf("Memory limit must be given in bytes (minimum 524288 bytes)")
 	}
 	}
@@ -949,7 +949,7 @@ func (srv *Server) ContainerCreate(config *Config) (string, []string, error) {
 	if config.Memory > 0 && !srv.runtime.capabilities.SwapLimit {
 	if config.Memory > 0 && !srv.runtime.capabilities.SwapLimit {
 		config.MemorySwap = -1
 		config.MemorySwap = -1
 	}
 	}
-	container, buildWarnings, err := srv.runtime.Create(config)
+	container, buildWarnings, err := srv.runtime.Create(config, name)
 	if err != nil {
 	if err != nil {
 		if srv.runtime.graph.IsNotExist(err) {
 		if srv.runtime.graph.IsNotExist(err) {
 
 
@@ -1209,13 +1209,12 @@ func (srv *Server) ImageGetCached(imgID string, config *Config) (*Image, error)
 	return nil, nil
 	return nil, nil
 }
 }
 
 
-func (srv *Server) ContainerStart(name string, hostConfig *HostConfig) error {
+func (srv *Server) RegisterLinks(name string, hostConfig *HostConfig) error {
 	runtime := srv.runtime
 	runtime := srv.runtime
 	container := runtime.Get(name)
 	container := runtime.Get(name)
 	if container == nil {
 	if container == nil {
 		return fmt.Errorf("No such container: %s", name)
 		return fmt.Errorf("No such container: %s", name)
 	}
 	}
-
 	// Register links
 	// Register links
 	if hostConfig != nil && hostConfig.Links != nil {
 	if hostConfig != nil && hostConfig.Links != nil {
 		for _, l := range hostConfig.Links {
 		for _, l := range hostConfig.Links {
@@ -1223,16 +1222,28 @@ func (srv *Server) ContainerStart(name string, hostConfig *HostConfig) error {
 			if err != nil {
 			if err != nil {
 				return err
 				return err
 			}
 			}
-
-			childName := parts["name"]
-			if childName[0] != '/' {
-				childName = "/" + childName
+			child, err := srv.runtime.GetByName(parts["name"])
+			if err != nil {
+				return err
+			}
+			if child == nil {
+				return fmt.Errorf("Could not get container for %s", parts["name"])
 			}
 			}
-			if err := runtime.Link(fmt.Sprintf("/%s", container.ID), childName, parts["alias"]); err != nil {
+
+			if err := runtime.RegisterLink(container, child, parts["alias"]); err != nil {
 				return err
 				return err
 			}
 			}
 		}
 		}
 	}
 	}
+	return nil
+}
+
+func (srv *Server) ContainerStart(name string, hostConfig *HostConfig) error {
+	runtime := srv.runtime
+	container := runtime.Get(name)
+	if container == nil {
+		return fmt.Errorf("No such container: %s", name)
+	}
 
 
 	if err := container.Start(hostConfig); err != nil {
 	if err := container.Start(hostConfig); err != nil {
 		return fmt.Errorf("Error starting container %s: %s", name, err)
 		return fmt.Errorf("Error starting container %s: %s", name, err)

+ 7 - 6
server_test.go

@@ -89,7 +89,7 @@ func TestCreateRm(t *testing.T) {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 
 
-	id, _, err := srv.ContainerCreate(config)
+	id, _, err := srv.ContainerCreate(config, "")
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -119,7 +119,7 @@ func TestCreateRmVolumes(t *testing.T) {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 
 
-	id, _, err := srv.ContainerCreate(config)
+	id, _, err := srv.ContainerCreate(config, "")
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -158,7 +158,7 @@ func TestCommit(t *testing.T) {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 
 
-	id, _, err := srv.ContainerCreate(config)
+	id, _, err := srv.ContainerCreate(config, "")
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -179,7 +179,7 @@ func TestCreateStartRestartStopStartKillRm(t *testing.T) {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 
 
-	id, _, err := srv.ContainerCreate(config)
+	id, _, err := srv.ContainerCreate(config, "")
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -231,6 +231,7 @@ func TestRunWithTooLowMemoryLimit(t *testing.T) {
 			CpuShares: 1000,
 			CpuShares: 1000,
 			Cmd:       []string{"/bin/cat"},
 			Cmd:       []string{"/bin/cat"},
 		},
 		},
+		"",
 	); err == nil {
 	); err == nil {
 		t.Errorf("Memory limit is smaller than the allowed limit. Container creation should've failed!")
 		t.Errorf("Memory limit is smaller than the allowed limit. Container creation should've failed!")
 	}
 	}
@@ -397,7 +398,7 @@ func TestRmi(t *testing.T) {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 
 
-	containerID, _, err := srv.ContainerCreate(config)
+	containerID, _, err := srv.ContainerCreate(config, "")
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -418,7 +419,7 @@ func TestRmi(t *testing.T) {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 
 
-	containerID, _, err = srv.ContainerCreate(config)
+	containerID, _, err = srv.ContainerCreate(config, "")
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}

+ 0 - 22
sorter.go

@@ -81,25 +81,3 @@ func sortContainers(containers []*Container, predicate func(i, j *Container) boo
 	s := &containerSorter{containers, predicate}
 	s := &containerSorter{containers, predicate}
 	sort.Sort(s)
 	sort.Sort(s)
 }
 }
-
-type apiLinkSorter struct {
-	links []APILink
-	by    func(i, j APILink) bool
-}
-
-func (s *apiLinkSorter) Len() int {
-	return len(s.links)
-}
-
-func (s *apiLinkSorter) Swap(i, j int) {
-	s.links[i], s.links[j] = s.links[j], s.links[i]
-}
-
-func (s *apiLinkSorter) Less(i, j int) bool {
-	return s.by(s.links[i], s.links[j])
-}
-
-func sortLinks(links []APILink, predicate func(i, j APILink) bool) {
-	s := &apiLinkSorter{links, predicate}
-	sort.Sort(s)
-}

+ 18 - 0
utils.go

@@ -2,6 +2,7 @@ package docker
 
 
 import (
 import (
 	"fmt"
 	"fmt"
+	"github.com/dotcloud/docker/namesgenerator"
 	"github.com/dotcloud/docker/utils"
 	"github.com/dotcloud/docker/utils"
 	"strconv"
 	"strconv"
 	"strings"
 	"strings"
@@ -289,3 +290,20 @@ func migratePortMappings(config *Config) error {
 func parseLink(rawLink string) (map[string]string, error) {
 func parseLink(rawLink string) (map[string]string, error) {
 	return utils.PartParser("name:alias", rawLink)
 	return utils.PartParser("name:alias", rawLink)
 }
 }
+
+type checker struct {
+	runtime *Runtime
+}
+
+func (c *checker) Exists(name string) bool {
+	return c.runtime.containerGraph.Exists("/" + name)
+}
+
+// Generate a random and unique name
+func generateRandomName(runtime *Runtime) string {
+	n, err := namesgenerator.GenerateRandomName(&checker{runtime})
+	if err != nil {
+		panic(err)
+	}
+	return n
+}

+ 1 - 1
utils_test.go

@@ -129,7 +129,7 @@ func mkContainer(r *Runtime, args []string, t *testing.T) (*Container, *HostConf
 	if config.Image == "_" {
 	if config.Image == "_" {
 		config.Image = GetTestImage(r).ID
 		config.Image = GetTestImage(r).ID
 	}
 	}
-	c, _, err := r.Create(config)
+	c, _, err := r.Create(config, "")
 	if err != nil {
 	if err != nil {
 		return nil, nil, err
 		return nil, nil, err
 	}
 	}