func (b *Builder) commit(id string, autoCmd *runconfig.Command, comment string) error { if b.disableCommit { return nil } if b.image == "" && !b.noBaseImage { return fmt.Errorf("Please provide a source image with `from` prior to commit") } b.Config.Image = b.image if id == "" { cmd := b.Config.Cmd if runtime.GOOS != "windows" { b.Config.Cmd = runconfig.NewCommand("/bin/sh", "-c", "#(nop) "+comment) } else { b.Config.Cmd = runconfig.NewCommand("cmd", "/S /C", "REM (nop) "+comment) } defer func(cmd *runconfig.Command) { b.Config.Cmd = cmd }(cmd) hit, err := b.probeCache() if err != nil { return err } if hit { return nil } container, err := b.create() if err != nil { return err } id = container.ID if err := container.Mount(); err != nil { return err } defer container.Unmount() } container, err := b.Daemon.Get(id) if err != nil { return err } // Note: Actually copy the struct autoConfig := *b.Config autoConfig.Cmd = autoCmd commitCfg := &daemon.ContainerCommitConfig{ Author: b.maintainer, Pause: true, Config: &autoConfig, } // Commit the container image, err := b.Daemon.Commit(container, commitCfg) if err != nil { return err } b.image = image.ID return nil }
func BenchmarkRunSequential(b *testing.B) { daemon := mkDaemon(b) defer nuke(daemon) for i := 0; i < b.N; i++ { container, _, err := daemon.Create(&runconfig.Config{ Image: GetTestImage(daemon).ID, Cmd: runconfig.NewCommand("echo", "-n", "foo"), }, &runconfig.HostConfig{}, "", ) if err != nil { b.Fatal(err) } defer daemon.Rm(container) output, err := container.Output() if err != nil { b.Fatal(err) } if string(output) != "foo" { b.Fatalf("Unexpected output: %s", output) } if err := daemon.Rm(container); err != nil { b.Fatal(err) } } }
func TestPostContainersWait(t *testing.T) { eng := NewTestEngine(t) defer mkDaemonFromEngine(eng, t).Nuke() containerID := createTestContainer(eng, &runconfig.Config{ Image: unitTestImageID, Cmd: runconfig.NewCommand("/bin/sleep", "1"), OpenStdin: true, }, t, ) startContainer(eng, containerID, t) setTimeout(t, "Wait timed out", 3*time.Second, func() { r := httptest.NewRecorder() req, err := http.NewRequest("POST", "/containers/"+containerID+"/wait", bytes.NewReader([]byte{})) if err != nil { t.Fatal(err) } server.ServeRequest(eng, api.APIVERSION, r, req) assertHttpNotError(r, t) var apiWait engine.Env if err := apiWait.Decode(r.Body); err != nil { t.Fatal(err) } if apiWait.GetInt("StatusCode") != 0 { t.Fatalf("Non zero exit code for sleep: %d\n", apiWait.GetInt("StatusCode")) } }) if containerRunning(eng, containerID, t) { t.Fatalf("The container should be stopped after wait") } }
// CMD foo // // Set the default command to run in the container (which may be empty). // Argument handling is the same as RUN. // func cmd(b *builder, args []string, attributes map[string]bool, original string) error { if err := b.BuilderFlags.Parse(); err != nil { return err } cmdSlice := handleJSONArgs(args, attributes) if !attributes["json"] { if runtime.GOOS != "windows" { cmdSlice = append([]string{"/bin/sh", "-c"}, cmdSlice...) } else { cmdSlice = append([]string{"cmd", "/S /C"}, cmdSlice...) } } b.Config.Cmd = runconfig.NewCommand(cmdSlice...) if err := b.commit("", b.Config.Cmd, fmt.Sprintf("CMD %q", cmdSlice)); err != nil { return err } if len(args) != 0 { b.cmdSet = true } return nil }
func TestPostContainersCopy(t *testing.T) { eng := NewTestEngine(t) defer mkDaemonFromEngine(eng, t).Nuke() // Create a container and remove a file containerID := createTestContainer(eng, &runconfig.Config{ Image: unitTestImageID, Cmd: runconfig.NewCommand("touch", "/test.txt"), }, t, ) containerRun(eng, containerID, t) r := httptest.NewRecorder() var copyData engine.Env copyData.Set("Resource", "/test.txt") copyData.Set("HostPath", ".") jsonData := bytes.NewBuffer(nil) if err := copyData.Encode(jsonData); err != nil { t.Fatal(err) } req, err := http.NewRequest("POST", "/containers/"+containerID+"/copy", jsonData) if err != nil { t.Fatal(err) } req.Header.Add("Content-Type", "application/json") server.ServeRequest(eng, api.APIVERSION, r, req) assertHttpNotError(r, t) if r.Code != http.StatusOK { t.Fatalf("%d OK expected, received %d\n", http.StatusOK, r.Code) } found := false for tarReader := tar.NewReader(r.Body); ; { h, err := tarReader.Next() if err != nil { if err == io.EOF { break } t.Fatal(err) } if h.Name == "test.txt" { found = true break } } if !found { t.Fatalf("The created test file has not been found in the copied output") } }
func (b *Builder) create() (*daemon.Container, error) { if b.image == "" && !b.noBaseImage { return nil, fmt.Errorf("Please provide a source image with `from` prior to run") } b.Config.Image = b.image config := *b.Config // Create the Pod podId := fmt.Sprintf("buildpod-%s", utils.RandStr(10, "alpha")) podString, err := MakeBasicPod(podId, b.image, b.Config.Cmd.Slice()) if err != nil { return nil, err } err = b.Hyperdaemon.CreatePod(podId, podString, false) if err != nil { return nil, err } // Get the container var ( containerId = "" c *daemon.Container ) ps, ok := b.Hyperdaemon.PodList.GetStatus(podId) if !ok { return nil, fmt.Errorf("Cannot find pod %s", podId) } for _, i := range ps.Containers { containerId = i.Id } c, err = b.Daemon.Get(containerId) if err != nil { glog.Error(err.Error()) return nil, err } b.TmpContainers[c.ID] = struct{}{} b.TmpPods[podId] = struct{}{} fmt.Fprintf(b.OutStream, " ---> Running in %s\n", stringid.TruncateID(c.ID)) if config.Cmd.Len() > 0 { // override the entry point that may have been picked up from the base image s := config.Cmd.Slice() c.Path = s[0] c.Args = s[1:] } else { config.Cmd = runconfig.NewCommand() } return c, nil }
func BenchmarkRunParallel(b *testing.B) { daemon := mkDaemon(b) defer nuke(daemon) var tasks []chan error for i := 0; i < b.N; i++ { complete := make(chan error) tasks = append(tasks, complete) go func(i int, complete chan error) { container, _, err := daemon.Create(&runconfig.Config{ Image: GetTestImage(daemon).ID, Cmd: runconfig.NewCommand("echo", "-n", "foo"), }, &runconfig.HostConfig{}, "", ) if err != nil { complete <- err return } defer daemon.Rm(container) if err := container.Start(); err != nil { complete <- err return } if _, err := container.WaitStop(15 * time.Second); err != nil { complete <- err return } // if string(output) != "foo" { // complete <- fmt.Errorf("Unexecpted output: %v", string(output)) // } if err := daemon.Rm(container); err != nil { complete <- err return } complete <- nil }(i, complete) } var errors []error for _, task := range tasks { err := <-task if err != nil { errors = append(errors, err) } } if len(errors) > 0 { b.Fatal(errors) } }
func TestPostContainersStop(t *testing.T) { eng := NewTestEngine(t) defer mkDaemonFromEngine(eng, t).Nuke() containerID := createTestContainer(eng, &runconfig.Config{ Image: unitTestImageID, Cmd: runconfig.NewCommand("/bin/top"), OpenStdin: true, }, t, ) startContainer(eng, containerID, t) // Give some time to the process to start containerWaitTimeout(eng, containerID, t) if !containerRunning(eng, containerID, t) { t.Errorf("Container should be running") } // Note: as it is a POST request, it requires a body. req, err := http.NewRequest("POST", "/containers/"+containerID+"/stop?t=1", bytes.NewReader([]byte{})) if err != nil { t.Fatal(err) } r := httptest.NewRecorder() server.ServeRequest(eng, api.APIVERSION, r, req) assertHttpNotError(r, t) if r.Code != http.StatusNoContent { t.Fatalf("%d NO CONTENT expected, received %d\n", http.StatusNoContent, r.Code) } if containerRunning(eng, containerID, t) { t.Fatalf("The container hasn't been stopped") } req, err = http.NewRequest("POST", "/containers/"+containerID+"/stop?t=1", bytes.NewReader([]byte{})) if err != nil { t.Fatal(err) } r = httptest.NewRecorder() server.ServeRequest(eng, api.APIVERSION, r, req) // Stopping an already stopper container should return a 304 assertHttpNotError(r, t) if r.Code != http.StatusNotModified { t.Fatalf("%d NOT MODIFIER expected, received %d\n", http.StatusNotModified, r.Code) } }
func (d *Daemon) ContainerExecCreate(job *engine.Job) error { if len(job.Args) != 1 { return fmt.Errorf("Usage: %s [options] container command [args]", job.Name) } if strings.HasPrefix(d.execDriver.Name(), lxc.DriverName) { return lxc.ErrExec } var name = job.Args[0] container, err := d.getActiveContainer(name) if err != nil { return err } config, err := runconfig.ExecConfigFromJob(job) if err != nil { return err } cmd := runconfig.NewCommand(config.Cmd...) entrypoint, args := d.getEntrypointAndArgs(runconfig.NewEntrypoint(), cmd) processConfig := execdriver.ProcessConfig{ Tty: config.Tty, Entrypoint: entrypoint, Arguments: args, User: config.User, Privileged: config.Privileged, } execConfig := &execConfig{ ID: stringid.GenerateRandomID(), OpenStdin: config.AttachStdin, OpenStdout: config.AttachStdout, OpenStderr: config.AttachStderr, StreamConfig: StreamConfig{}, ProcessConfig: processConfig, Container: container, Running: false, } container.LogEvent("exec_create: " + execConfig.ProcessConfig.Entrypoint + " " + strings.Join(execConfig.ProcessConfig.Arguments, " ")) d.registerExecCommand(execConfig) job.Printf("%s\n", execConfig.ID) return nil }
func TestPostContainersStart(t *testing.T) { eng := NewTestEngine(t) defer mkDaemonFromEngine(eng, t).Nuke() containerID := createTestContainer( eng, &runconfig.Config{ Image: unitTestImageID, Cmd: runconfig.NewCommand("/bin/cat"), OpenStdin: true, }, t, ) hostConfigJSON, err := json.Marshal(&runconfig.HostConfig{}) req, err := http.NewRequest("POST", "/containers/"+containerID+"/start", bytes.NewReader(hostConfigJSON)) if err != nil { t.Fatal(err) } req.Header.Set("Content-Type", "application/json") r := httptest.NewRecorder() server.ServeRequest(eng, api.APIVERSION, r, req) assertHttpNotError(r, t) if r.Code != http.StatusNoContent { t.Fatalf("%d NO CONTENT expected, received %d\n", http.StatusNoContent, r.Code) } containerAssertExists(eng, containerID, t) req, err = http.NewRequest("POST", "/containers/"+containerID+"/start", bytes.NewReader(hostConfigJSON)) if err != nil { t.Fatal(err) } req.Header.Set("Content-Type", "application/json") r = httptest.NewRecorder() server.ServeRequest(eng, api.APIVERSION, r, req) // Starting an already started container should return a 304 assertHttpNotError(r, t) if r.Code != http.StatusNotModified { t.Fatalf("%d NOT MODIFIER expected, received %d\n", http.StatusNotModified, r.Code) } containerAssertExists(eng, containerID, t) containerKill(eng, containerID, t) }
func (b *Builder) commit(id string, autoCmd *runconfig.Command, comment string) error { if b.disableCommit { return nil } if b.image == "" && !b.noBaseImage { return fmt.Errorf("Please provide a source image with `from` prior to commit") } b.Config.Image = b.image if id == "" { cmd := b.Config.Cmd b.Config.Cmd = runconfig.NewCommand("/bin/sh", "-c", "#(nop) "+comment) defer func(cmd *runconfig.Command) { b.Config.Cmd = cmd }(cmd) hit, err := b.probeCache() if err != nil { return err } if hit { return nil } container, err := b.create() if err != nil { return err } id = container.ID if err := container.Mount(); err != nil { return err } defer container.Unmount() } container, err := b.Daemon.Get(id) if err != nil { return err } // Note: Actually copy the struct autoConfig := *b.Config autoConfig.Cmd = autoCmd // Commit the container image, err := b.Daemon.Commit(container, "", "", "", b.maintainer, true, &autoConfig) if err != nil { return err } b.image = image.ID return nil }
func (d *Daemon) ContainerExecCreate(config *runconfig.ExecConfig) (string, error) { // Not all drivers support Exec (LXC for example) if err := checkExecSupport(d.execDriver.Name()); err != nil { return "", err } container, err := d.getActiveContainer(config.Container) if err != nil { return "", err } cmd := runconfig.NewCommand(config.Cmd...) entrypoint, args := d.getEntrypointAndArgs(runconfig.NewEntrypoint(), cmd) user := config.User if len(user) == 0 { user = container.Config.User } processConfig := &execdriver.ProcessConfig{ Tty: config.Tty, Entrypoint: entrypoint, Arguments: args, User: user, Privileged: config.Privileged, } execConfig := &execConfig{ ID: stringid.GenerateNonCryptoID(), OpenStdin: config.AttachStdin, OpenStdout: config.AttachStdout, OpenStderr: config.AttachStderr, StreamConfig: StreamConfig{}, ProcessConfig: processConfig, Container: container, Running: false, waitStart: make(chan struct{}), } d.registerExecCommand(execConfig) container.LogEvent("exec_create: " + execConfig.ProcessConfig.Entrypoint + " " + strings.Join(execConfig.ProcessConfig.Arguments, " ")) return execConfig.ID, nil }
// CMD foo // // Set the default command to run in the container (which may be empty). // Argument handling is the same as RUN. // func cmd(b *Builder, args []string, attributes map[string]bool, original string) error { cmdSlice := handleJsonArgs(args, attributes) if !attributes["json"] { cmdSlice = append([]string{"/bin/sh", "-c"}, cmdSlice...) } b.Config.Cmd = runconfig.NewCommand(cmdSlice...) if err := b.commit("", b.Config.Cmd, fmt.Sprintf("CMD %q", cmdSlice)); err != nil { return err } if len(args) != 0 { b.cmdSet = true } return nil }
func (b *Builder) create() (*daemon.Container, error) { if b.image == "" && !b.noBaseImage { return nil, fmt.Errorf("Please provide a source image with `from` prior to run") } b.Config.Image = b.image hostConfig := &runconfig.HostConfig{ CpuShares: b.cpuShares, CpuPeriod: b.cpuPeriod, CpuQuota: b.cpuQuota, CpusetCpus: b.cpuSetCpus, CpusetMems: b.cpuSetMems, CgroupParent: b.cgroupParent, Memory: b.memory, MemorySwap: b.memorySwap, NetworkMode: "bridge", } config := *b.Config // Create the container c, warnings, err := b.Daemon.Create(b.Config, hostConfig, "") if err != nil { return nil, err } for _, warning := range warnings { fmt.Fprintf(b.OutStream, " ---> [Warning] %s\n", warning) } b.TmpContainers[c.ID] = struct{}{} fmt.Fprintf(b.OutStream, " ---> Running in %s\n", stringid.TruncateID(c.ID)) if config.Cmd.Len() > 0 { // override the entry point that may have been picked up from the base image s := config.Cmd.Slice() c.Path = s[0] c.Args = s[1:] } else { config.Cmd = runconfig.NewCommand() } return c, nil }
func TestPostContainersRestart(t *testing.T) { eng := NewTestEngine(t) defer mkDaemonFromEngine(eng, t).Nuke() containerID := createTestContainer(eng, &runconfig.Config{ Image: unitTestImageID, Cmd: runconfig.NewCommand("/bin/top"), OpenStdin: true, }, t, ) startContainer(eng, containerID, t) // Give some time to the process to start containerWaitTimeout(eng, containerID, t) if !containerRunning(eng, containerID, t) { t.Errorf("Container should be running") } req, err := http.NewRequest("POST", "/containers/"+containerID+"/restart?t=1", bytes.NewReader([]byte{})) if err != nil { t.Fatal(err) } r := httptest.NewRecorder() server.ServeRequest(eng, api.APIVERSION, r, req) assertHttpNotError(r, t) if r.Code != http.StatusNoContent { t.Fatalf("%d NO CONTENT expected, received %d\n", http.StatusNoContent, r.Code) } // Give some time to the process to restart containerWaitTimeout(eng, containerID, t) if !containerRunning(eng, containerID, t) { t.Fatalf("Container should be running") } containerKill(eng, containerID, t) }
func TestDestroyWithInitLayer(t *testing.T) { daemon := mkDaemon(t) defer nuke(daemon) container, _, err := daemon.Create(&runconfig.Config{ Image: GetTestImage(daemon).ID, Cmd: runconfig.NewCommand("ls", "-al"), }, &runconfig.HostConfig{}, "") if err != nil { t.Fatal(err) } // Destroy if err := daemon.Rm(container); err != nil { t.Fatal(err) } // Make sure daemon.Exists() behaves correctly if daemon.Exists("test_destroy") { t.Fatalf("Exists() returned true") } // Make sure daemon.List() doesn't list the destroyed container if len(daemon.List()) != 0 { t.Fatalf("Expected 0 container, %v found", len(daemon.List())) } driver := daemon.Graph().Driver() // Make sure that the container does not exist in the driver if _, err := driver.Get(container.ID, ""); err == nil { t.Fatal("Conttainer should not exist in the driver") } // Make sure that the init layer is removed from the driver if _, err := driver.Get(fmt.Sprintf("%s-init", container.ID), ""); err == nil { t.Fatal("Container's init layer should not exist in the driver") } }
func (d *Daemon) ContainerExecCreate(config *runconfig.ExecConfig) (string, error) { if strings.HasPrefix(d.execDriver.Name(), lxc.DriverName) { return "", lxc.ErrExec } container, err := d.getActiveContainer(config.Container) if err != nil { return "", err } cmd := runconfig.NewCommand(config.Cmd...) entrypoint, args := d.getEntrypointAndArgs(runconfig.NewEntrypoint(), cmd) processConfig := execdriver.ProcessConfig{ Tty: config.Tty, Entrypoint: entrypoint, Arguments: args, User: config.User, Privileged: config.Privileged, } execConfig := &execConfig{ ID: stringid.GenerateRandomID(), OpenStdin: config.AttachStdin, OpenStdout: config.AttachStdout, OpenStderr: config.AttachStderr, StreamConfig: StreamConfig{}, ProcessConfig: processConfig, Container: container, Running: false, } container.LogEvent("exec_create: " + execConfig.ProcessConfig.Entrypoint + " " + strings.Join(execConfig.ProcessConfig.Arguments, " ")) d.registerExecCommand(execConfig) return execConfig.ID, nil }
func TestStdin(t *testing.T) { daemon := mkDaemon(t) defer nuke(daemon) container, _, err := daemon.Create(&runconfig.Config{ Image: GetTestImage(daemon).ID, Cmd: runconfig.NewCommand("cat"), OpenStdin: true, }, &runconfig.HostConfig{}, "", ) if err != nil { t.Fatal(err) } defer daemon.Rm(container) stdin := container.StdinPipe() stdout := container.StdoutPipe() if err := container.Start(); err != nil { t.Fatal(err) } defer stdin.Close() defer stdout.Close() if _, err := io.WriteString(stdin, "hello world"); err != nil { t.Fatal(err) } if err := stdin.Close(); err != nil { t.Fatal(err) } container.WaitStop(-1 * time.Second) output, err := ioutil.ReadAll(stdout) if err != nil { t.Fatal(err) } if string(output) != "hello world" { t.Fatalf("Unexpected output. Expected %s, received: %s", "hello world", string(output)) } }
func TestDestroy(t *testing.T) { daemon := mkDaemon(t) defer nuke(daemon) container, _, err := daemon.Create(&runconfig.Config{ Image: GetTestImage(daemon).ID, Cmd: runconfig.NewCommand("ls", "-al"), }, &runconfig.HostConfig{}, "") if err != nil { t.Fatal(err) } // Destroy if err := daemon.Rm(container); err != nil { t.Error(err) } // Make sure daemon.Exists() behaves correctly if daemon.Exists("test_destroy") { t.Errorf("Exists() returned true") } // Make sure daemon.List() doesn't list the destroyed container if len(daemon.List()) != 0 { t.Errorf("Expected 0 container, %v found", len(daemon.List())) } // Make sure daemon.Get() refuses to return the unexisting container if c, _ := daemon.Get(container.ID); c != nil { t.Errorf("Got a container that should not exist") } // Test double destroy if err := daemon.Rm(container); err == nil { // It should have failed t.Errorf("Double destroy did not fail") } }
func TestDaemonCreate(t *testing.T) { daemon := mkDaemon(t) defer nuke(daemon) // Make sure we start we 0 containers if len(daemon.List()) != 0 { t.Errorf("Expected 0 containers, %v found", len(daemon.List())) } container, _, err := daemon.Create(&runconfig.Config{ Image: GetTestImage(daemon).ID, Cmd: runconfig.NewCommand("ls", "-al"), }, &runconfig.HostConfig{}, "", ) if err != nil { t.Fatal(err) } defer func() { if err := daemon.Rm(container); err != nil { t.Error(err) } }() // Make sure we can find the newly created container with List() if len(daemon.List()) != 1 { t.Errorf("Expected 1 container, %v found", len(daemon.List())) } // Make sure the container List() returns is the right one if daemon.List()[0].ID != container.ID { t.Errorf("Unexpected container %v returned by List", daemon.List()[0]) } // Make sure we can get the container with Get() if _, err := daemon.Get(container.ID); err != nil { t.Errorf("Unable to get newly created container") } // Make sure it is the right container if c, _ := daemon.Get(container.ID); c != container { t.Errorf("Get() returned the wrong container") } // Make sure Exists returns it as existing if !daemon.Exists(container.ID) { t.Errorf("Exists() returned false for a newly created container") } // Test that conflict error displays correct details cmd := runconfig.NewCommand("ls", "-al") testContainer, _, _ := daemon.Create( &runconfig.Config{ Image: GetTestImage(daemon).ID, Cmd: cmd, }, &runconfig.HostConfig{}, "conflictname", ) if _, _, err := daemon.Create(&runconfig.Config{Image: GetTestImage(daemon).ID, Cmd: cmd}, &runconfig.HostConfig{}, testContainer.Name); err == nil || !strings.Contains(err.Error(), stringid.TruncateID(testContainer.ID)) { t.Fatalf("Name conflict error doesn't include the correct short id. Message was: %v", err) } // Make sure create with bad parameters returns an error if _, _, err = daemon.Create(&runconfig.Config{Image: GetTestImage(daemon).ID}, &runconfig.HostConfig{}, ""); err == nil { t.Fatal("Builder.Create should throw an error when Cmd is missing") } if _, _, err := daemon.Create( &runconfig.Config{ Image: GetTestImage(daemon).ID, Cmd: runconfig.NewCommand(), }, &runconfig.HostConfig{}, "", ); err == nil { t.Fatal("Builder.Create should throw an error when Cmd is empty") } config := &runconfig.Config{ Image: GetTestImage(daemon).ID, Cmd: runconfig.NewCommand("/bin/ls"), PortSpecs: []string{"80"}, } container, _, err = daemon.Create(config, &runconfig.HostConfig{}, "") _, err = daemon.Commit(container, "testrepo", "testtag", "", "", true, config) if err != nil { t.Error(err) } // test expose 80:8000 container, warnings, err := daemon.Create(&runconfig.Config{ Image: GetTestImage(daemon).ID, Cmd: runconfig.NewCommand("ls", "-al"), PortSpecs: []string{"80:8000"}, }, &runconfig.HostConfig{}, "", ) if err != nil { t.Fatal(err) } if warnings == nil || len(warnings) != 1 { t.Error("Expected a warning, got none") } }
func TestPostContainersAttachStderr(t *testing.T) { eng := NewTestEngine(t) defer mkDaemonFromEngine(eng, t).Nuke() containerID := createTestContainer(eng, &runconfig.Config{ Image: unitTestImageID, Cmd: runconfig.NewCommand("/bin/sh", "-c", "/bin/cat >&2"), OpenStdin: true, }, t, ) // Start the process startContainer(eng, containerID, t) stdin, stdinPipe := io.Pipe() stdout, stdoutPipe := io.Pipe() // Try to avoid the timeout in destroy. Best effort, don't check error defer func() { closeWrap(stdin, stdinPipe, stdout, stdoutPipe) containerKill(eng, containerID, t) }() // Attach to it c1 := make(chan struct{}) go func() { defer close(c1) r := &hijackTester{ ResponseRecorder: httptest.NewRecorder(), in: stdin, out: stdoutPipe, } req, err := http.NewRequest("POST", "/containers/"+containerID+"/attach?stream=1&stdin=1&stdout=1&stderr=1", bytes.NewReader([]byte{})) if err != nil { t.Fatal(err) } server.ServeRequest(eng, api.APIVERSION, r, req) assertHttpNotError(r.ResponseRecorder, t) }() // Acknowledge hijack setTimeout(t, "hijack acknowledge timed out", 2*time.Second, func() { stdout.Read([]byte{}) stdout.Read(make([]byte, 4096)) }) setTimeout(t, "read/write assertion timed out", 2*time.Second, func() { if err := assertPipe("hello\n", string([]byte{2, 0, 0, 0, 0, 0, 0, 6})+"hello", stdout, stdinPipe, 150); err != nil { t.Fatal(err) } }) // Close pipes (client disconnects) if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil { t.Fatal(err) } // Wait for attach to finish, the client disconnected, therefore, Attach finished his job setTimeout(t, "Waiting for CmdAttach timed out", 10*time.Second, func() { <-c1 }) // We closed stdin, expect /bin/cat to still be running // Wait a little bit to make sure container.monitor() did his thing containerWaitTimeout(eng, containerID, t) // Try to avoid the timeout in destroy. Best effort, don't check error cStdin, _ := containerAttach(eng, containerID, t) cStdin.Close() containerWait(eng, containerID, t) }
func (b *Builder) runContextCommand(args []string, allowRemote bool, allowDecompression bool, cmdName string) error { if b.context == nil { return fmt.Errorf("No context given. Impossible to use %s", cmdName) } if len(args) < 2 { return fmt.Errorf("Invalid %s format - at least two arguments required", cmdName) } dest := args[len(args)-1] // last one is always the dest copyInfos := []*copyInfo{} b.Config.Image = b.image defer func() { for _, ci := range copyInfos { if ci.tmpDir != "" { os.RemoveAll(ci.tmpDir) } } }() // Loop through each src file and calculate the info we need to // do the copy (e.g. hash value if cached). Don't actually do // the copy until we've looked at all src files for _, orig := range args[0 : len(args)-1] { if err := calcCopyInfo( b, cmdName, ©Infos, orig, dest, allowRemote, allowDecompression, true, ); err != nil { return err } } if len(copyInfos) == 0 { return fmt.Errorf("No source files were specified") } if len(copyInfos) > 1 && !strings.HasSuffix(dest, "/") { return fmt.Errorf("When using %s with more than one source file, the destination must be a directory and end with a /", cmdName) } // For backwards compat, if there's just one CI then use it as the // cache look-up string, otherwise hash 'em all into one var srcHash string var origPaths string if len(copyInfos) == 1 { srcHash = copyInfos[0].hash origPaths = copyInfos[0].origPath } else { var hashs []string var origs []string for _, ci := range copyInfos { hashs = append(hashs, ci.hash) origs = append(origs, ci.origPath) } hasher := sha256.New() hasher.Write([]byte(strings.Join(hashs, ","))) srcHash = "multi:" + hex.EncodeToString(hasher.Sum(nil)) origPaths = strings.Join(origs, " ") } cmd := b.Config.Cmd if runtime.GOOS != "windows" { b.Config.Cmd = runconfig.NewCommand("/bin/sh", "-c", fmt.Sprintf("#(nop) %s %s in %s", cmdName, srcHash, dest)) } else { b.Config.Cmd = runconfig.NewCommand("cmd", "/S /C", fmt.Sprintf("REM (nop) %s %s in %s", cmdName, srcHash, dest)) } defer func(cmd *runconfig.Command) { b.Config.Cmd = cmd }(cmd) hit, err := b.probeCache() if err != nil { return err } if hit { return nil } container, _, err := b.Daemon.Create(b.Config, nil, "") if err != nil { return err } b.TmpContainers[container.ID] = struct{}{} if err := container.Mount(); err != nil { return err } defer container.Unmount() if err := container.PrepareStorage(); err != nil { return err } for _, ci := range copyInfos { if err := b.addContext(container, ci.origPath, ci.destPath, ci.decompress); err != nil { return err } } if err := container.CleanupStorage(); err != nil { return err } if err := b.commit(container.ID, cmd, fmt.Sprintf("%s %s in %s", cmdName, origPaths, dest)); err != nil { return err } return nil }
func Convert(c *project.ServiceConfig) (*runconfig.Config, *runconfig.HostConfig, error) { vs := Filter(c.Volumes, isVolume) volumes := make(map[string]struct{}, len(vs)) for _, v := range vs { volumes[v] = struct{}{} } ports, binding, err := nat.ParsePortSpecs(c.Ports) if err != nil { return nil, nil, err } restart, err := runconfig.ParseRestartPolicy(c.Restart) if err != nil { return nil, nil, err } if exposedPorts, _, err := nat.ParsePortSpecs(c.Expose); err != nil { return nil, nil, err } else { for k, v := range exposedPorts { ports[k] = v } } deviceMappings, err := parseDevices(c.Devices) if err != nil { return nil, nil, err } config := &runconfig.Config{ Entrypoint: runconfig.NewEntrypoint(c.Entrypoint.Slice()...), Hostname: c.Hostname, Domainname: c.DomainName, User: c.User, Env: c.Environment.Slice(), Cmd: runconfig.NewCommand(c.Command.Slice()...), Image: c.Image, Labels: c.Labels.MapParts(), ExposedPorts: ports, Tty: c.Tty, OpenStdin: c.StdinOpen, WorkingDir: c.WorkingDir, VolumeDriver: c.VolumeDriver, Volumes: volumes, } host_config := &runconfig.HostConfig{ VolumesFrom: c.VolumesFrom, CapAdd: runconfig.NewCapList(c.CapAdd), CapDrop: runconfig.NewCapList(c.CapDrop), CpuShares: c.CpuShares, CpusetCpus: c.CpuSet, ExtraHosts: c.ExtraHosts, Privileged: c.Privileged, Binds: Filter(c.Volumes, isBind), Devices: deviceMappings, Dns: c.Dns.Slice(), DnsSearch: c.DnsSearch.Slice(), LogConfig: runconfig.LogConfig{ Type: c.LogDriver, Config: c.LogOpt, }, Memory: c.MemLimit, MemorySwap: c.MemSwapLimit, NetworkMode: runconfig.NetworkMode(c.Net), ReadonlyRootfs: c.ReadOnly, PidMode: runconfig.PidMode(c.Pid), UTSMode: runconfig.UTSMode(c.Uts), IpcMode: runconfig.IpcMode(c.Ipc), PortBindings: binding, RestartPolicy: restart, SecurityOpt: c.SecurityOpt, } return config, host_config, nil }
func Convert(c *project.ServiceConfig) (*runconfig.Config, *runconfig.HostConfig, error) { vs := Filter(c.Volumes, isVolume) volumes := make(map[string]struct{}, len(vs)) for _, v := range vs { volumes[v] = struct{}{} } cmd, _ := shlex.Split(c.Command) entrypoint, _ := shlex.Split(c.Entrypoint) ports, binding, err := nat.ParsePortSpecs(c.Ports) if err != nil { return nil, nil, err } restart, err := runconfig.ParseRestartPolicy(c.Restart) if err != nil { return nil, nil, err } dns := c.Dns.Slice() dnssearch := c.DnsSearch.Slice() labels := c.Labels.MapParts() if len(c.Expose) > 0 { exposedPorts, _, err := nat.ParsePortSpecs(c.Expose) ports = exposedPorts if err != nil { return nil, nil, err } } config := &runconfig.Config{ Entrypoint: runconfig.NewEntrypoint(entrypoint...), Hostname: c.Hostname, Domainname: c.DomainName, User: c.User, Env: c.Environment.Slice(), Cmd: runconfig.NewCommand(cmd...), Image: c.Image, Labels: labels, ExposedPorts: ports, Tty: c.Tty, OpenStdin: c.StdinOpen, WorkingDir: c.WorkingDir, Volumes: volumes, } host_config := &runconfig.HostConfig{ VolumesFrom: c.VolumesFrom, CapAdd: c.CapAdd, CapDrop: c.CapDrop, CpuShares: c.CpuShares, Privileged: c.Privileged, Binds: Filter(c.Volumes, isBind), Dns: dns, DnsSearch: dnssearch, LogConfig: runconfig.LogConfig{ Type: c.LogDriver, }, Memory: c.MemLimit, NetworkMode: runconfig.NetworkMode(c.Net), ReadonlyRootfs: c.ReadOnly, PidMode: runconfig.PidMode(c.Pid), IpcMode: runconfig.IpcMode(c.Ipc), PortBindings: binding, RestartPolicy: restart, } return config, host_config, nil }
func startEchoServerContainer(t *testing.T, proto string) (*daemon.Daemon, *daemon.Container, string) { var ( err error id string strPort string eng = NewTestEngine(t) daemon = mkDaemonFromEngine(eng, t) port = 5554 p nat.Port ) defer func() { if err != nil { daemon.Nuke() } }() for { port += 1 strPort = strconv.Itoa(port) var cmd string if proto == "tcp" { cmd = "socat TCP-LISTEN:" + strPort + ",reuseaddr,fork EXEC:/bin/cat" } else if proto == "udp" { cmd = "socat UDP-RECVFROM:" + strPort + ",fork EXEC:/bin/cat" } else { t.Fatal(fmt.Errorf("Unknown protocol %v", proto)) } ep := make(map[nat.Port]struct{}, 1) p = nat.Port(fmt.Sprintf("%s/%s", strPort, proto)) ep[p] = struct{}{} c := &runconfig.Config{ Image: unitTestImageID, Cmd: runconfig.NewCommand("sh", "-c", cmd), PortSpecs: []string{fmt.Sprintf("%s/%s", strPort, proto)}, ExposedPorts: ep, } id, _, err = daemon.ContainerCreate(unitTestImageID, c, &runconfig.HostConfig{}) // FIXME: this relies on the undocumented behavior of daemon.Create // which will return a nil error AND container if the exposed ports // are invalid. That behavior should be fixed! if id != "" { break } t.Logf("Port %v already in use, trying another one", strPort) } if err := daemon.ContainerStart(id, &runconfig.HostConfig{}); err != nil { t.Fatal(err) } container, err := daemon.Get(id) if err != nil { t.Fatal(err) } setTimeout(t, "Waiting for the container to be started timed out", 2*time.Second, func() { for !container.IsRunning() { time.Sleep(10 * time.Millisecond) } }) // Even if the state is running, lets give some time to lxc to spawn the process container.WaitStop(500 * time.Millisecond) strPort = container.NetworkSettings.Ports[p][0].HostPort return daemon, container, strPort }