mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
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.
This commit is contained in:
parent
c0662488c7
commit
0d2924408b
23 changed files with 258 additions and 307 deletions
80
api.go
80
api.go
|
@ -6,7 +6,6 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/dotcloud/docker/auth"
|
||||
"github.com/dotcloud/docker/gograph"
|
||||
"github.com/dotcloud/docker/utils"
|
||||
"github.com/gorilla/mux"
|
||||
"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 {
|
||||
if err := parseForm(r); err != nil {
|
||||
return nil
|
||||
}
|
||||
config := &Config{}
|
||||
out := &APIRun{}
|
||||
name := r.Form.Get("name")
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(config); err != nil {
|
||||
return err
|
||||
|
@ -539,7 +542,7 @@ func postContainersCreate(srv *Server, version float64, w http.ResponseWriter, r
|
|||
config.Dns = defaultDns
|
||||
}
|
||||
|
||||
id, warnings, err := srv.ContainerCreate(config)
|
||||
id, warnings, err := srv.ContainerCreate(config, name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -649,6 +652,10 @@ func postContainersStart(srv *Server, version float64, w http.ResponseWriter, r
|
|||
return fmt.Errorf("Missing parameter")
|
||||
}
|
||||
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 {
|
||||
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) {
|
||||
r := mux.NewRouter()
|
||||
|
||||
|
@ -1106,7 +1046,6 @@ func createRouter(srv *Server, logging bool) (*mux.Router, error) {
|
|||
"/containers/{name:.*}/json": getContainersByName,
|
||||
"/containers/{name:.*}/top": getContainersTop,
|
||||
"/containers/{name:.*}/attach/ws": wsContainersAttach,
|
||||
"/containers/links": getContainersLinks,
|
||||
},
|
||||
"POST": {
|
||||
"/auth": postAuth,
|
||||
|
@ -1125,7 +1064,6 @@ func createRouter(srv *Server, logging bool) (*mux.Router, error) {
|
|||
"/containers/{name:.*}/resize": postContainersResize,
|
||||
"/containers/{name:.*}/attach": postContainersAttach,
|
||||
"/containers/{name:.*}/copy": postContainersCopy,
|
||||
"/containers/link": postContainerLink,
|
||||
},
|
||||
"DELETE": {
|
||||
"/containers/{name:.*}": deleteContainers,
|
||||
|
|
|
@ -121,9 +121,3 @@ type APICopy struct {
|
|||
Resource string
|
||||
HostPath string
|
||||
}
|
||||
|
||||
type APILink struct {
|
||||
Path string
|
||||
ContainerID string
|
||||
Image string
|
||||
}
|
||||
|
|
17
api_test.go
17
api_test.go
|
@ -352,7 +352,7 @@ func TestGetContainersJSON(t *testing.T) {
|
|||
container, _, err := runtime.Create(&Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"echo", "test"},
|
||||
})
|
||||
}, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -391,6 +391,7 @@ func TestGetContainersExport(t *testing.T) {
|
|||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"touch", "/test"},
|
||||
},
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -441,6 +442,7 @@ func TestGetContainersChanges(t *testing.T) {
|
|||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"/bin/rm", "/etc/passwd"},
|
||||
},
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -485,6 +487,7 @@ func TestGetContainersTop(t *testing.T) {
|
|||
Cmd: []string{"/bin/sh", "-c", "cat"},
|
||||
OpenStdin: true,
|
||||
},
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -566,6 +569,7 @@ func TestGetContainersByName(t *testing.T) {
|
|||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"echo", "test"},
|
||||
},
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -597,6 +601,7 @@ func TestPostCommit(t *testing.T) {
|
|||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"touch", "/test"},
|
||||
},
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -692,6 +697,7 @@ func TestPostContainersKill(t *testing.T) {
|
|||
Cmd: []string{"/bin/cat"},
|
||||
OpenStdin: true,
|
||||
},
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -734,6 +740,7 @@ func TestPostContainersRestart(t *testing.T) {
|
|||
Cmd: []string{"/bin/top"},
|
||||
OpenStdin: true,
|
||||
},
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -788,6 +795,7 @@ func TestPostContainersStart(t *testing.T) {
|
|||
Cmd: []string{"/bin/cat"},
|
||||
OpenStdin: true,
|
||||
},
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -840,6 +848,7 @@ func TestPostContainersStop(t *testing.T) {
|
|||
Cmd: []string{"/bin/top"},
|
||||
OpenStdin: true,
|
||||
},
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -887,6 +896,7 @@ func TestPostContainersWait(t *testing.T) {
|
|||
Cmd: []string{"/bin/sleep", "1"},
|
||||
OpenStdin: true,
|
||||
},
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -929,6 +939,7 @@ func TestPostContainersAttach(t *testing.T) {
|
|||
Cmd: []string{"/bin/cat"},
|
||||
OpenStdin: true,
|
||||
},
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -1018,6 +1029,7 @@ func TestPostContainersAttachStderr(t *testing.T) {
|
|||
Cmd: []string{"/bin/sh", "-c", "/bin/cat >&2"},
|
||||
OpenStdin: true,
|
||||
},
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -1107,7 +1119,7 @@ func TestDeleteContainers(t *testing.T) {
|
|||
container, _, err := runtime.Create(&Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"touch", "/test"},
|
||||
})
|
||||
}, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -1299,6 +1311,7 @@ func TestPostContainersCopy(t *testing.T) {
|
|||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"touch", "/test.txt"},
|
||||
},
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
|
|
@ -335,7 +335,7 @@ func (b *buildFile) CmdAdd(args string) error {
|
|||
|
||||
b.config.Image = b.image
|
||||
// Create the container and start it
|
||||
container, _, err := b.runtime.Create(b.config)
|
||||
container, _, err := b.runtime.Create(b.config, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -370,7 +370,7 @@ func (b *buildFile) run() (string, error) {
|
|||
b.config.Image = b.image
|
||||
|
||||
// Create the container and start it
|
||||
c, _, err := b.runtime.Create(b.config)
|
||||
c, _, err := b.runtime.Create(b.config, "")
|
||||
if err != nil {
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
|
|
41
commands.go
41
commands.go
|
@ -91,7 +91,6 @@ func (cli *DockerCli) CmdHelp(args ...string) error {
|
|||
{"insert", "Insert a file in an image"},
|
||||
{"inspect", "Return low-level information on a container"},
|
||||
{"kill", "Kill a running container"},
|
||||
{"link", "Link the container with a new name"},
|
||||
{"login", "Register or Login to the docker registry server"},
|
||||
{"logs", "Fetch the logs of a container"},
|
||||
{"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 {
|
||||
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 !*noTrunc {
|
||||
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, ","))
|
||||
if *size {
|
||||
|
@ -1191,27 +1193,6 @@ func (cli *DockerCli) CmdPs(args ...string) error {
|
|||
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 {
|
||||
cmd := Subcmd("commit", "[OPTIONS] CONTAINER [REPOSITORY [TAG]]", "Create a new image from a container's changes")
|
||||
flComment := cmd.String("m", "", "Commit message")
|
||||
|
@ -1535,6 +1516,7 @@ func (cli *DockerCli) CmdRun(args ...string) error {
|
|||
|
||||
flSigProxy := cmd.Lookup("sig-proxy")
|
||||
sigProxy, _ := strconv.ParseBool(flSigProxy.Value.String())
|
||||
flName := cmd.Lookup("name")
|
||||
|
||||
var containerIDFile *os.File
|
||||
if len(hostConfig.ContainerIDFile) > 0 {
|
||||
|
@ -1547,9 +1529,14 @@ func (cli *DockerCli) CmdRun(args ...string) error {
|
|||
}
|
||||
defer containerIDFile.Close()
|
||||
}
|
||||
containerValues := url.Values{}
|
||||
name := flName.Value.String()
|
||||
if name != "" {
|
||||
containerValues.Set("name", name)
|
||||
}
|
||||
|
||||
//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 statusCode == 404 {
|
||||
_, tag := utils.ParseRepositoryTag(config.Image)
|
||||
|
@ -1590,7 +1577,7 @@ func (cli *DockerCli) CmdRun(args ...string) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
body, _, err = cli.call("POST", "/containers/create", config)
|
||||
body, _, err = cli.call("POST", "/containers/create?"+containerValues.Encode(), config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@ type Container struct {
|
|||
ResolvConfPath string
|
||||
HostnamePath string
|
||||
HostsPath string
|
||||
Name string
|
||||
|
||||
cmd *exec.Cmd
|
||||
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")
|
||||
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)")
|
||||
cmd.String("name", "", "Assign a name to the container")
|
||||
|
||||
if capabilities != nil && *flMemory > 0 && !capabilities.MemoryLimit {
|
||||
//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\"")
|
||||
|
||||
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 {
|
||||
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
|
||||
runtime := container.runtime
|
||||
|
||||
children, err := runtime.Children(fmt.Sprintf("/%s", container.ID))
|
||||
children, err := runtime.Children(container.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ func TestIDFormat(t *testing.T) {
|
|||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"/bin/sh", "-c", "echo hello world"},
|
||||
},
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -393,6 +394,7 @@ func TestOutput(t *testing.T) {
|
|||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"echo", "-n", "foobar"},
|
||||
},
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -415,6 +417,7 @@ func TestContainerNetwork(t *testing.T) {
|
|||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"ping", "-c", "1", "127.0.0.1"},
|
||||
},
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -438,6 +441,7 @@ func TestKillDifferentUser(t *testing.T) {
|
|||
OpenStdin: true,
|
||||
User: "daemon",
|
||||
},
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -492,7 +496,7 @@ func TestCreateVolume(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
c, _, err := runtime.Create(config)
|
||||
c, _, err := runtime.Create(config, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -511,6 +515,7 @@ func TestKill(t *testing.T) {
|
|||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"sleep", "2"},
|
||||
},
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -554,7 +559,7 @@ func TestExitCode(t *testing.T) {
|
|||
trueContainer, _, err := runtime.Create(&Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"/bin/true", ""},
|
||||
})
|
||||
}, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -569,7 +574,7 @@ func TestExitCode(t *testing.T) {
|
|||
falseContainer, _, err := runtime.Create(&Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"/bin/false", ""},
|
||||
})
|
||||
}, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -589,6 +594,7 @@ func TestRestart(t *testing.T) {
|
|||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"echo", "-n", "foobar"},
|
||||
},
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -621,6 +627,7 @@ func TestRestartStdin(t *testing.T) {
|
|||
|
||||
OpenStdin: true,
|
||||
},
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -697,6 +704,7 @@ func TestUser(t *testing.T) {
|
|||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"id"},
|
||||
},
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -717,6 +725,7 @@ func TestUser(t *testing.T) {
|
|||
|
||||
User: "root",
|
||||
},
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -737,6 +746,7 @@ func TestUser(t *testing.T) {
|
|||
|
||||
User: "0",
|
||||
},
|
||||
"",
|
||||
)
|
||||
if err != nil || container.State.ExitCode != 0 {
|
||||
t.Fatal(err)
|
||||
|
@ -757,6 +767,7 @@ func TestUser(t *testing.T) {
|
|||
|
||||
User: "1",
|
||||
},
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -779,6 +790,7 @@ func TestUser(t *testing.T) {
|
|||
|
||||
User: "daemon",
|
||||
},
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -799,6 +811,7 @@ func TestUser(t *testing.T) {
|
|||
|
||||
User: "unknownuser",
|
||||
},
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -818,6 +831,7 @@ func TestMultipleContainers(t *testing.T) {
|
|||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"sleep", "2"},
|
||||
},
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -828,6 +842,7 @@ func TestMultipleContainers(t *testing.T) {
|
|||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"sleep", "2"},
|
||||
},
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -874,6 +889,7 @@ func TestStdin(t *testing.T) {
|
|||
|
||||
OpenStdin: true,
|
||||
},
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -919,6 +935,7 @@ func TestTty(t *testing.T) {
|
|||
|
||||
OpenStdin: true,
|
||||
},
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -962,6 +979,7 @@ func TestEnv(t *testing.T) {
|
|||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"env"},
|
||||
},
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -1013,6 +1031,7 @@ func TestEntrypoint(t *testing.T) {
|
|||
Entrypoint: []string{"/bin/echo"},
|
||||
Cmd: []string{"-n", "foobar"},
|
||||
},
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -1035,6 +1054,7 @@ func TestEntrypointNoCmd(t *testing.T) {
|
|||
Image: GetTestImage(runtime).ID,
|
||||
Entrypoint: []string{"/bin/echo", "foobar"},
|
||||
},
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -1089,6 +1109,7 @@ func TestLXCConfig(t *testing.T) {
|
|||
Memory: int64(mem),
|
||||
CpuShares: int64(cpu),
|
||||
},
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -1111,6 +1132,7 @@ func TestCustomLxcConfig(t *testing.T) {
|
|||
|
||||
Hostname: "foobar",
|
||||
},
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -1140,6 +1162,7 @@ func BenchmarkRunSequencial(b *testing.B) {
|
|||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"echo", "-n", "foo"},
|
||||
},
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
|
@ -1172,6 +1195,7 @@ func BenchmarkRunParallel(b *testing.B) {
|
|||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"echo", "-n", "foo"},
|
||||
},
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
complete <- err
|
||||
|
@ -1324,6 +1348,7 @@ func TestVolumesFromReadonlyMount(t *testing.T) {
|
|||
Cmd: []string{"/bin/echo", "-n", "foobar"},
|
||||
Volumes: map[string]struct{}{"/test": {}},
|
||||
},
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -1343,6 +1368,7 @@ func TestVolumesFromReadonlyMount(t *testing.T) {
|
|||
Cmd: []string{"/bin/echo", "-n", "foobar"},
|
||||
VolumesFrom: container.ID,
|
||||
},
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -1378,6 +1404,7 @@ func TestRestartWithVolumes(t *testing.T) {
|
|||
Cmd: []string{"echo", "-n", "foobar"},
|
||||
Volumes: map[string]struct{}{"/test": {}},
|
||||
},
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -1421,6 +1448,7 @@ func TestVolumesFromWithVolumes(t *testing.T) {
|
|||
Cmd: []string{"sh", "-c", "echo -n bar > /test/foo"},
|
||||
Volumes: map[string]struct{}{"/test": {}},
|
||||
},
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -1450,6 +1478,7 @@ func TestVolumesFromWithVolumes(t *testing.T) {
|
|||
VolumesFrom: container.ID,
|
||||
Volumes: map[string]struct{}{"/test": {}},
|
||||
},
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -1484,7 +1513,7 @@ func TestOnlyLoopbackExistsWhenUsingDisableNetworkOption(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
c, _, err := runtime.Create(config)
|
||||
c, _, err := runtime.Create(config, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -1555,6 +1584,7 @@ func TestMultipleVolumesFrom(t *testing.T) {
|
|||
Cmd: []string{"sh", "-c", "echo -n bar > /test/foo"},
|
||||
Volumes: map[string]struct{}{"/test": {}},
|
||||
},
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -1583,6 +1613,7 @@ func TestMultipleVolumesFrom(t *testing.T) {
|
|||
Cmd: []string{"sh", "-c", "echo -n bar > /other/foo"},
|
||||
Volumes: map[string]struct{}{"/other": {}},
|
||||
},
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -1603,7 +1634,7 @@ func TestMultipleVolumesFrom(t *testing.T) {
|
|||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"/bin/echo", "-n", "foobar"},
|
||||
VolumesFrom: strings.Join([]string{container.ID, container2.ID}, ","),
|
||||
})
|
||||
}, "")
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
|
|
@ -151,6 +151,7 @@ Create a container
|
|||
}
|
||||
|
||||
:jsonparam config: the container's configuration
|
||||
:query name: container name to use
|
||||
:statuscode 201: no error
|
||||
:statuscode 404: no such container
|
||||
:statuscode 406: impossible to attach (container not running)
|
||||
|
|
|
@ -403,33 +403,6 @@ Insert file from github
|
|||
|
||||
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:
|
||||
|
||||
``login``
|
||||
|
@ -604,7 +577,8 @@ network communication.
|
|||
-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)
|
||||
-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
|
||||
--------
|
||||
|
@ -680,12 +654,20 @@ without publishing the port to the host system's interfaces.
|
|||
|
||||
.. 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
|
||||
newly created container with the alias ``redis``. The new container
|
||||
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:
|
||||
|
||||
|
|
|
@ -54,26 +54,14 @@ Run the redis container
|
|||
|
||||
.. 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
|
||||
------------------------
|
||||
|
@ -90,12 +78,12 @@ Now lets start our web application with a link into redis.
|
|||
|
||||
.. 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
|
||||
|
||||
HOSTNAME=4c01db0b339c
|
||||
DB_NAME=/4c01db0b339cf19958731255a796ee072040a652f51652a4ade190ab8c27006f/db
|
||||
DB_NAME=/webapp/db
|
||||
TERM=xterm
|
||||
DB_PORT=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
|
||||
|
||||
# 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
|
||||
DB_PORT=tcp://172.17.0.8:6379
|
||||
# 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
|
||||
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.
|
||||
|
|
|
@ -132,6 +132,11 @@ func (db *Database) Set(fullPath, id string) (*Entity, error) {
|
|||
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 {
|
||||
parent, err := db.get(parentPath)
|
||||
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
|
||||
func (db *Database) List(name string, depth int) 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
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
|
@ -327,10 +340,9 @@ type WalkMeta struct {
|
|||
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)
|
||||
e, err := db.get(name)
|
||||
if err != nil {
|
||||
if e == nil {
|
||||
close(out)
|
||||
return out
|
||||
}
|
||||
|
@ -370,7 +382,7 @@ func (db *Database) children(name string, depth int) <-chan WalkMeta {
|
|||
if depth != -1 {
|
||||
nDepth -= 1
|
||||
}
|
||||
sc := db.children(meta.FullPath, nDepth)
|
||||
sc := db.children(child, meta.FullPath, nDepth)
|
||||
for c := range sc {
|
||||
out <- c
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ func TestNewDatabase(t *testing.T) {
|
|||
if db == nil {
|
||||
t.Fatal("Database should not be nil")
|
||||
}
|
||||
db.Close()
|
||||
defer destroyTestDb(dbpath)
|
||||
}
|
||||
|
||||
|
@ -465,3 +466,26 @@ func TestRefPaths(t *testing.T) {
|
|||
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")
|
||||
}
|
||||
|
||||
}
|
||||
|
|
2
links.go
2
links.go
|
@ -54,7 +54,7 @@ func (l *Link) ToEnv() []string {
|
|||
alias := strings.ToUpper(l.Alias())
|
||||
|
||||
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
|
||||
|
|
|
@ -89,7 +89,7 @@ func TestLinkEnv(t *testing.T) {
|
|||
}
|
||||
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"])
|
||||
}
|
||||
if env["DOCKER_PORT_6379_TCP"] != "tcp://172.0.17.2:6379" {
|
||||
|
|
76
runtime.go
76
runtime.go
|
@ -265,7 +265,10 @@ func (runtime *Runtime) restore() error {
|
|||
// Any containers that are left over do not exist in the graph
|
||||
for _, container := range containers {
|
||||
// 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)
|
||||
}
|
||||
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
|
||||
img, err := runtime.repositories.LookupImage(config.Image)
|
||||
if err != nil {
|
||||
|
@ -345,8 +348,15 @@ func (runtime *Runtime) Create(config *Config) (*Container, []string, error) {
|
|||
// Generate id
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -378,6 +388,7 @@ func (runtime *Runtime) Create(config *Config) (*Container, []string, error) {
|
|||
NetworkSettings: &NetworkSettings{},
|
||||
// FIXME: do we need to store this in the container?
|
||||
SysInitPath: sysInitPath,
|
||||
Name: name,
|
||||
}
|
||||
container.root = runtime.containerRoot(container.ID)
|
||||
// Step 1: create the container directory.
|
||||
|
@ -483,16 +494,7 @@ func (runtime *Runtime) Commit(container *Container, repository, tag, comment, a
|
|||
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 {
|
||||
if name[0] == '/' {
|
||||
name = name[1:]
|
||||
}
|
||||
if id, err := runtime.idIndex.Get(name); err == nil {
|
||||
name = id
|
||||
}
|
||||
if name[0] != '/' {
|
||||
name = "/" + name
|
||||
}
|
||||
|
@ -500,9 +502,7 @@ func (runtime *Runtime) getFullName(name string) string {
|
|||
}
|
||||
|
||||
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 {
|
||||
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) {
|
||||
name = runtime.getFullName(name)
|
||||
children := make(map[string]*Container)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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 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()
|
||||
|
|
|
@ -197,6 +197,7 @@ func TestRuntimeCreate(t *testing.T) {
|
|||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"ls", "-al"},
|
||||
},
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -234,7 +235,7 @@ func TestRuntimeCreate(t *testing.T) {
|
|||
}
|
||||
|
||||
// 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")
|
||||
}
|
||||
|
||||
|
@ -243,6 +244,7 @@ func TestRuntimeCreate(t *testing.T) {
|
|||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{},
|
||||
},
|
||||
"",
|
||||
); err == nil {
|
||||
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"},
|
||||
PortSpecs: []string{"80"},
|
||||
}
|
||||
container, _, err = runtime.Create(config)
|
||||
container, _, err = runtime.Create(config, "")
|
||||
|
||||
_, err = runtime.Commit(container, "testrepo", "testtag", "", "", config)
|
||||
if err != nil {
|
||||
|
@ -267,7 +269,7 @@ func TestDestroy(t *testing.T) {
|
|||
container, _, err := runtime.Create(&Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"ls", "-al"},
|
||||
})
|
||||
}, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -361,7 +363,7 @@ func startEchoServerContainer(t *testing.T, proto string) (*Runtime, *Container,
|
|||
Cmd: []string{"sh", "-c", cmd},
|
||||
PortSpecs: []string{fmt.Sprintf("%s/%s", strPort, proto)},
|
||||
ExposedPorts: ep,
|
||||
})
|
||||
}, "")
|
||||
if err != nil {
|
||||
nuke(runtime)
|
||||
t.Fatal(err)
|
||||
|
@ -573,6 +575,9 @@ func TestReloadContainerLinks(t *testing.T) {
|
|||
h1 := &HostConfig{}
|
||||
// Add a link to container 2
|
||||
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 {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -620,7 +625,7 @@ func TestReloadContainerLinks(t *testing.T) {
|
|||
|
||||
t.Logf("Number of links: %d", runtime2.containerGraph.Refs("0"))
|
||||
// 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 {
|
||||
t.Fatal("Entity should not be nil")
|
||||
}
|
||||
|
@ -636,13 +641,17 @@ func TestDefaultContainerName(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
shortId, _, err := srv.ContainerCreate(config)
|
||||
shortId, _, err := srv.ContainerCreate(config, "some_name")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
container := runtime.Get(shortId)
|
||||
containerID := container.ID
|
||||
|
||||
if container.Name != "/some_name" {
|
||||
t.Fatalf("Expect /some_name got %s", container.Name)
|
||||
}
|
||||
|
||||
paths := runtime.containerGraph.RefPaths(containerID)
|
||||
if paths == nil || len(paths) == 0 {
|
||||
t.Fatalf("Could not find edges for %s", containerID)
|
||||
|
@ -654,12 +663,12 @@ func TestDefaultContainerName(t *testing.T) {
|
|||
if edge.EntityID != containerID {
|
||||
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)
|
||||
defer nuke(runtime)
|
||||
srv := &Server{runtime: runtime}
|
||||
|
@ -669,24 +678,30 @@ func TestDefaultContainerRename(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
shortId, _, err := srv.ContainerCreate(config)
|
||||
shortId, _, err := srv.ContainerCreate(config, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
container := runtime.Get(shortId)
|
||||
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)
|
||||
}
|
||||
|
||||
shortId, _, err := srv.ContainerCreate(config)
|
||||
shortId, _, err := srv.ContainerCreate(config, "/webapp")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
container := runtime.Get(shortId)
|
||||
|
||||
if err := runtime.RenameLink(fmt.Sprintf("/%s", container.ID), "/webapp"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
webapp, err := runtime.GetByName("/webapp")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -724,17 +735,14 @@ func TestLinkChildContainer(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
shortId, _, err = srv.ContainerCreate(config)
|
||||
shortId, _, err = srv.ContainerCreate(config, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -758,16 +766,12 @@ func TestGetAllChildren(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
shortId, _, err := srv.ContainerCreate(config)
|
||||
shortId, _, err := srv.ContainerCreate(config, "/webapp")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
container := runtime.Get(shortId)
|
||||
|
||||
if err := runtime.RenameLink(fmt.Sprintf("/%s", container.ID), "/webapp"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
webapp, err := runtime.GetByName("/webapp")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -782,17 +786,14 @@ func TestGetAllChildren(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
shortId, _, err = srv.ContainerCreate(config)
|
||||
shortId, _, err = srv.ContainerCreate(config, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
|
|
31
server.go
31
server.go
|
@ -156,7 +156,7 @@ func (srv *Server) ImageInsert(name, url, path string, out io.Writer, sf *utils.
|
|||
return "", err
|
||||
}
|
||||
|
||||
c, _, err := srv.runtime.Create(config)
|
||||
c, _, err := srv.runtime.Create(config, "")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -937,7 +937,7 @@ func (srv *Server) ImageImport(src, repo, tag string, in io.Reader, out io.Write
|
|||
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 {
|
||||
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 {
|
||||
config.MemorySwap = -1
|
||||
}
|
||||
container, buildWarnings, err := srv.runtime.Create(config)
|
||||
container, buildWarnings, err := srv.runtime.Create(config, name)
|
||||
if err != nil {
|
||||
if srv.runtime.graph.IsNotExist(err) {
|
||||
|
||||
|
@ -1209,13 +1209,12 @@ func (srv *Server) ImageGetCached(imgID string, config *Config) (*Image, error)
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
func (srv *Server) ContainerStart(name string, hostConfig *HostConfig) error {
|
||||
func (srv *Server) RegisterLinks(name string, hostConfig *HostConfig) error {
|
||||
runtime := srv.runtime
|
||||
container := runtime.Get(name)
|
||||
if container == nil {
|
||||
return fmt.Errorf("No such container: %s", name)
|
||||
}
|
||||
|
||||
// Register links
|
||||
if hostConfig != nil && hostConfig.Links != nil {
|
||||
for _, l := range hostConfig.Links {
|
||||
|
@ -1223,16 +1222,28 @@ func (srv *Server) ContainerStart(name string, hostConfig *HostConfig) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
childName := parts["name"]
|
||||
if childName[0] != '/' {
|
||||
childName = "/" + childName
|
||||
child, err := srv.runtime.GetByName(parts["name"])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := runtime.Link(fmt.Sprintf("/%s", container.ID), childName, parts["alias"]); err != nil {
|
||||
if child == nil {
|
||||
return fmt.Errorf("Could not get container for %s", parts["name"])
|
||||
}
|
||||
|
||||
if err := runtime.RegisterLink(container, child, parts["alias"]); err != nil {
|
||||
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 {
|
||||
return fmt.Errorf("Error starting container %s: %s", name, err)
|
||||
|
|
|
@ -89,7 +89,7 @@ func TestCreateRm(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
id, _, err := srv.ContainerCreate(config)
|
||||
id, _, err := srv.ContainerCreate(config, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -119,7 +119,7 @@ func TestCreateRmVolumes(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
id, _, err := srv.ContainerCreate(config)
|
||||
id, _, err := srv.ContainerCreate(config, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -158,7 +158,7 @@ func TestCommit(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
id, _, err := srv.ContainerCreate(config)
|
||||
id, _, err := srv.ContainerCreate(config, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -179,7 +179,7 @@ func TestCreateStartRestartStopStartKillRm(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
id, _, err := srv.ContainerCreate(config)
|
||||
id, _, err := srv.ContainerCreate(config, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -231,6 +231,7 @@ func TestRunWithTooLowMemoryLimit(t *testing.T) {
|
|||
CpuShares: 1000,
|
||||
Cmd: []string{"/bin/cat"},
|
||||
},
|
||||
"",
|
||||
); err == nil {
|
||||
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)
|
||||
}
|
||||
|
||||
containerID, _, err := srv.ContainerCreate(config)
|
||||
containerID, _, err := srv.ContainerCreate(config, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -418,7 +419,7 @@ func TestRmi(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
containerID, _, err = srv.ContainerCreate(config)
|
||||
containerID, _, err = srv.ContainerCreate(config, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
22
sorter.go
22
sorter.go
|
@ -81,25 +81,3 @@ func sortContainers(containers []*Container, predicate func(i, j *Container) boo
|
|||
s := &containerSorter{containers, predicate}
|
||||
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
utils.go
18
utils.go
|
@ -2,6 +2,7 @@ package docker
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/dotcloud/docker/namesgenerator"
|
||||
"github.com/dotcloud/docker/utils"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
@ -289,3 +290,20 @@ func migratePortMappings(config *Config) error {
|
|||
func parseLink(rawLink string) (map[string]string, error) {
|
||||
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
|
||||
}
|
||||
|
|
|
@ -129,7 +129,7 @@ func mkContainer(r *Runtime, args []string, t *testing.T) (*Container, *HostConf
|
|||
if config.Image == "_" {
|
||||
config.Image = GetTestImage(r).ID
|
||||
}
|
||||
c, _, err := r.Create(config)
|
||||
c, _, err := r.Create(config, "")
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue