func postCommit(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } var ( config engine.Env env engine.Env job = eng.Job("commit", r.Form.Get("container")) stdoutBuffer = bytes.NewBuffer(nil) ) if err := config.Decode(r.Body); err != nil { utils.Errorf("%s", err) } job.Setenv("repo", r.Form.Get("repo")) job.Setenv("tag", r.Form.Get("tag")) job.Setenv("author", r.Form.Get("author")) job.Setenv("comment", r.Form.Get("comment")) job.SetenvSubEnv("config", &config) job.Stdout.Add(stdoutBuffer) if err := job.Run(); err != nil { return err } env.Set("Id", engine.Tail(stdoutBuffer, 1)) return writeJSON(w, http.StatusCreated, env) }
func postContainersCreate(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return nil } var ( out engine.Env job = eng.Job("create", r.Form.Get("name")) outWarnings []string stdoutBuffer = bytes.NewBuffer(nil) warnings = bytes.NewBuffer(nil) ) if err := job.DecodeEnv(r.Body); err != nil { return err } // Read container ID from the first line of stdout job.Stdout.Add(stdoutBuffer) // Read warnings from stderr job.Stderr.Add(warnings) if err := job.Run(); err != nil { return err } // Parse warnings from stderr scanner := bufio.NewScanner(warnings) for scanner.Scan() { outWarnings = append(outWarnings, scanner.Text()) } out.Set("Id", engine.Tail(stdoutBuffer, 1)) out.SetList("Warnings", outWarnings) return writeJSON(w, http.StatusCreated, out) }
func TestMergeConfigOnCommit(t *testing.T) { eng := NewTestEngine(t) runtime := mkDaemonFromEngine(eng, t) defer runtime.Nuke() container1, _, _ := mkContainer(runtime, []string{"-e", "FOO=bar", unitTestImageID, "echo test > /tmp/foo"}, t) defer runtime.Destroy(container1) config, _, _, err := runconfig.Parse([]string{container1.ID, "cat /tmp/foo"}, nil) if err != nil { t.Error(err) } job := eng.Job("commit", container1.ID) job.Setenv("repo", "testrepo") job.Setenv("tag", "testtag") job.SetenvJson("config", config) var outputBuffer = bytes.NewBuffer(nil) job.Stdout.Add(outputBuffer) if err := job.Run(); err != nil { t.Error(err) } container2, _, _ := mkContainer(runtime, []string{engine.Tail(outputBuffer, 1)}, t) defer runtime.Destroy(container2) job = eng.Job("container_inspect", container1.Name) baseContainer, _ := job.Stdout.AddEnv() if err := job.Run(); err != nil { t.Error(err) } job = eng.Job("container_inspect", container2.Name) commitContainer, _ := job.Stdout.AddEnv() if err := job.Run(); err != nil { t.Error(err) } baseConfig := baseContainer.GetSubEnv("Config") commitConfig := commitContainer.GetSubEnv("Config") if commitConfig.Get("Env") != baseConfig.Get("Env") { t.Fatalf("Env config in committed container should be %v, was %v", baseConfig.Get("Env"), commitConfig.Get("Env")) } if baseConfig.Get("Cmd") != "[\"echo test \\u003e /tmp/foo\"]" { t.Fatalf("Cmd in base container should be [\"echo test \\u003e /tmp/foo\"], was %s", baseConfig.Get("Cmd")) } if commitConfig.Get("Cmd") != "[\"cat /tmp/foo\"]" { t.Fatalf("Cmd in committed container should be [\"cat /tmp/foo\"], was %s", commitConfig.Get("Cmd")) } }
func createNamedTestContainer(eng *engine.Engine, config *runconfig.Config, f utils.Fataler, name string) (shortId string) { job := eng.Job("create", name) if err := job.ImportEnv(config); err != nil { f.Fatal(err) } var outputBuffer = bytes.NewBuffer(nil) job.Stdout.Add(outputBuffer) if err := job.Run(); err != nil { f.Fatal(err) } return engine.Tail(outputBuffer, 1) }
func TestContainerNameValidation(t *testing.T) { eng := NewTestEngine(t) daemon := mkDaemonFromEngine(eng, t) defer nuke(daemon) for _, test := range []struct { Name string Valid bool }{ {"abc-123_AAA.1", true}, {"\000asdf", false}, } { config, _, _, err := runconfig.Parse([]string{unitTestImageID, "echo test"}, nil) if err != nil { if !test.Valid { continue } t.Fatal(err) } var outputBuffer = bytes.NewBuffer(nil) job := eng.Job("create", test.Name) if err := job.ImportEnv(config); err != nil { t.Fatal(err) } job.Stdout.Add(outputBuffer) if err := job.Run(); err != nil { if !test.Valid { continue } t.Fatal(err) } container := daemon.Get(engine.Tail(outputBuffer, 1)) if container.Name != "/"+test.Name { t.Fatalf("Expect /%s got %s", test.Name, container.Name) } if c := daemon.Get("/" + test.Name); c == nil { t.Fatalf("Couldn't retrieve test container as /%s", test.Name) } else if c.ID != container.ID { t.Fatalf("Container /%s has ID %s instead of %s", test.Name, c.ID, container.ID) } } }
func postContainersWait(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } var ( env engine.Env stdoutBuffer = bytes.NewBuffer(nil) job = eng.Job("wait", vars["name"]) ) job.Stdout.Add(stdoutBuffer) if err := job.Run(); err != nil { return err } env.Set("StatusCode", engine.Tail(stdoutBuffer, 1)) return writeJSON(w, http.StatusOK, env) }
func postAuth(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { var ( authConfig, err = ioutil.ReadAll(r.Body) job = eng.Job("auth") stdoutBuffer = bytes.NewBuffer(nil) ) if err != nil { return err } job.Setenv("authConfig", string(authConfig)) job.Stdout.Add(stdoutBuffer) if err = job.Run(); err != nil { return err } if status := engine.Tail(stdoutBuffer, 1); status != "" { var env engine.Env env.Set("Status", status) return writeJSON(w, http.StatusOK, env) } w.WriteHeader(http.StatusNoContent) return nil }
func TestRmi(t *testing.T) { eng := NewTestEngine(t) srv := mkServerFromEngine(eng, t) defer mkDaemonFromEngine(eng, t).Nuke() initialImages := getAllImages(eng, t) config, hostConfig, _, err := runconfig.Parse([]string{unitTestImageID, "echo", "test"}, nil) if err != nil { t.Fatal(err) } containerID := createTestContainer(eng, config, t) //To remove job := eng.Job("start", containerID) if err := job.ImportEnv(hostConfig); err != nil { t.Fatal(err) } if err := job.Run(); err != nil { t.Fatal(err) } if err := eng.Job("wait", containerID).Run(); err != nil { t.Fatal(err) } job = eng.Job("commit", containerID) job.Setenv("repo", "test") var outputBuffer = bytes.NewBuffer(nil) job.Stdout.Add(outputBuffer) if err := job.Run(); err != nil { t.Fatal(err) } if err := eng.Job("tag", engine.Tail(outputBuffer, 1), "test", "0.1").Run(); err != nil { t.Fatal(err) } containerID = createTestContainer(eng, config, t) //To remove job = eng.Job("start", containerID) if err := job.ImportEnv(hostConfig); err != nil { t.Fatal(err) } if err := job.Run(); err != nil { t.Fatal(err) } if err := eng.Job("wait", containerID).Run(); err != nil { t.Fatal(err) } job = eng.Job("commit", containerID) job.Setenv("repo", "test") if err := job.Run(); err != nil { t.Fatal(err) } images := getAllImages(eng, t) if images.Len()-initialImages.Len() != 2 { t.Fatalf("Expected 2 new images, found %d.", images.Len()-initialImages.Len()) } if err = srv.DeleteImage(engine.Tail(outputBuffer, 1), engine.NewTable("", 0), true, false, false); err != nil { t.Fatal(err) } images = getAllImages(eng, t) if images.Len()-initialImages.Len() != 1 { t.Fatalf("Expected 1 new image, found %d.", images.Len()-initialImages.Len()) } for _, image := range images.Data { if strings.Contains(unitTestImageID, image.Get("Id")) { continue } if image.GetList("RepoTags")[0] == "<none>:<none>" { t.Fatalf("Expected tagged image, got untagged one.") } } }
func startEchoServerContainer(t *testing.T, proto string) (*daemon.Daemon, *daemon.Container, string) { var ( err error id string outputBuffer = bytes.NewBuffer(nil) 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{}{} jobCreate := eng.Job("create") jobCreate.Setenv("Image", unitTestImageID) jobCreate.SetenvList("Cmd", []string{"sh", "-c", cmd}) jobCreate.SetenvList("PortSpecs", []string{fmt.Sprintf("%s/%s", strPort, proto)}) jobCreate.SetenvJson("ExposedPorts", ep) jobCreate.Stdout.Add(outputBuffer) if err := jobCreate.Run(); err != nil { t.Fatal(err) } id = engine.Tail(outputBuffer, 1) // 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) } jobStart := eng.Job("start", id) portBindings := make(map[nat.Port][]nat.PortBinding) portBindings[p] = []nat.PortBinding{ {}, } if err := jobStart.SetenvJson("PortsBindings", portBindings); err != nil { t.Fatal(err) } if err := jobStart.Run(); err != nil { t.Fatal(err) } container := daemon.Get(id) if container == nil { t.Fatalf("Couldn't fetch test container %s", id) } setTimeout(t, "Waiting for the container to be started timed out", 2*time.Second, func() { for !container.State.IsRunning() { time.Sleep(10 * time.Millisecond) } }) // Even if the state is running, lets give some time to lxc to spawn the process container.WaitTimeout(500 * time.Millisecond) strPort = container.NetworkSettings.Ports[p][0].HostPort return daemon, container, strPort }