зеркало из https://github.com/microsoft/docker.git
Merge pull request #2425 from dotcloud/links-allow-name
Add -name for docker run
This commit is contained in:
Коммит
a52e23c5e4
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
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче