diff --git a/api/server/form.go b/api/server/form.go new file mode 100644 index 0000000000..af1cd2075e --- /dev/null +++ b/api/server/form.go @@ -0,0 +1,20 @@ +package server + +import ( + "net/http" + "strconv" + "strings" +) + +func boolValue(r *http.Request, k string) bool { + s := strings.ToLower(strings.TrimSpace(r.FormValue(k))) + return !(s == "" || s == "0" || s == "no" || s == "false" || s == "none") +} + +func int64Value(r *http.Request, k string) int64 { + val, err := strconv.ParseInt(r.FormValue(k), 10, 64) + if err != nil { + return 0 + } + return val +} diff --git a/api/server/form_test.go b/api/server/form_test.go new file mode 100644 index 0000000000..5cf6c82c14 --- /dev/null +++ b/api/server/form_test.go @@ -0,0 +1,55 @@ +package server + +import ( + "net/http" + "net/url" + "testing" +) + +func TestBoolValue(t *testing.T) { + cases := map[string]bool{ + "": false, + "0": false, + "no": false, + "false": false, + "none": false, + "1": true, + "yes": true, + "true": true, + "one": true, + "100": true, + } + + for c, e := range cases { + v := url.Values{} + v.Set("test", c) + r, _ := http.NewRequest("POST", "", nil) + r.Form = v + + a := boolValue(r, "test") + if a != e { + t.Fatalf("Value: %s, expected: %v, actual: %v", c, e, a) + } + } +} + +func TestInt64Value(t *testing.T) { + cases := map[string]int64{ + "": 0, + "asdf": 0, + "0": 0, + "1": 1, + } + + for c, e := range cases { + v := url.Values{} + v.Set("test", c) + r, _ := http.NewRequest("POST", "", nil) + r.Form = v + + a := int64Value(r, "test") + if a != e { + t.Fatalf("Value: %s, expected: %v, actual: %v", c, e, a) + } + } +} diff --git a/api/server/server.go b/api/server/server.go index b5b3e2db58..9142e530d0 100644 --- a/api/server/server.go +++ b/api/server/server.go @@ -23,6 +23,7 @@ import ( "github.com/docker/docker/api" "github.com/docker/docker/api/types" "github.com/docker/docker/autogen/dockerversion" + "github.com/docker/docker/builder" "github.com/docker/docker/daemon" "github.com/docker/docker/daemon/networkdriver/bridge" "github.com/docker/docker/engine" @@ -238,12 +239,12 @@ func writeJSON(w http.ResponseWriter, code int, v interface{}) error { return json.NewEncoder(w).Encode(v) } -func streamJSON(job *engine.Job, w http.ResponseWriter, flush bool) { +func streamJSON(out *engine.Output, w http.ResponseWriter, flush bool) { w.Header().Set("Content-Type", "application/json") if flush { - job.Stdout.Add(utils.NewWriteFlusher(w)) + out.Add(utils.NewWriteFlusher(w)) } else { - job.Stdout.Add(w) + out.Add(w) } } @@ -382,7 +383,7 @@ func (s *Server) getImagesJSON(eng *engine.Engine, version version.Version, w ht Filters: r.Form.Get("filters"), // FIXME this parameter could just be a match filter Filter: r.Form.Get("filter"), - All: toBool(r.Form.Get("all")), + All: boolValue(r, "all"), } images, err := s.daemon.Repositories().Images(&imagesConfig) @@ -598,8 +599,8 @@ func (s *Server) getContainersJSON(eng *engine.Engine, version version.Version, } config := &daemon.ContainersConfig{ - All: toBool(r.Form.Get("all")), - Size: toBool(r.Form.Get("size")), + All: boolValue(r, "all"), + Size: boolValue(r, "size"), Since: r.Form.Get("since"), Before: r.Form.Get("before"), Filters: r.Form.Get("filters"), @@ -641,14 +642,14 @@ func (s *Server) getContainersLogs(eng *engine.Engine, version version.Version, } // Validate args here, because we can't return not StatusOK after job.Run() call - stdout, stderr := toBool(r.Form.Get("stdout")), toBool(r.Form.Get("stderr")) + stdout, stderr := boolValue(r, "stdout"), boolValue(r, "stderr") if !(stdout || stderr) { return fmt.Errorf("Bad parameters: you must choose at least one stream") } logsConfig := &daemon.ContainerLogsConfig{ - Follow: toBool(r.Form.Get("follow")), - Timestamps: toBool(r.Form.Get("timestamps")), + Follow: boolValue(r, "follow"), + Timestamps: boolValue(r, "timestamps"), Tail: r.Form.Get("tail"), UseStdout: stdout, UseStderr: stderr, @@ -672,7 +673,7 @@ func (s *Server) postImagesTag(eng *engine.Engine, version version.Version, w ht repo := r.Form.Get("repo") tag := r.Form.Get("tag") - force := toBool(r.Form.Get("force")) + force := boolValue(r, "force") if err := s.daemon.Repositories().Tag(repo, tag, vars["name"], force); err != nil { return err } @@ -691,11 +692,20 @@ func (s *Server) postCommit(eng *engine.Engine, version version.Version, w http. cont := r.Form.Get("container") - pause := toBool(r.Form.Get("pause")) + pause := boolValue(r, "pause") if r.FormValue("pause") == "" && version.GreaterThanOrEqualTo("1.13") { pause = true } + c, _, err := runconfig.DecodeContainerConfig(r.Body) + if err != nil && err != io.EOF { //Do not fail if body is empty. + return err + } + + if c == nil { + c = &runconfig.Config{} + } + containerCommitConfig := &daemon.ContainerCommitConfig{ Pause: pause, Repo: r.Form.Get("repo"), @@ -703,10 +713,10 @@ func (s *Server) postCommit(eng *engine.Engine, version version.Version, w http. Author: r.Form.Get("author"), Comment: r.Form.Get("comment"), Changes: r.Form["changes"], - Config: r.Body, + Config: c, } - imgID, err := s.daemon.ContainerCommit(cont, containerCommitConfig) + imgID, err := builder.Commit(s.daemon, eng, cont, containerCommitConfig) if err != nil { return err } @@ -783,10 +793,15 @@ func (s *Server) postImagesCreate(eng *engine.Engine, version version.Version, w imageImportConfig.Json = false } - if err := s.daemon.Repositories().Import(src, repo, tag, imageImportConfig, eng); err != nil { + newConfig, err := builder.BuildFromConfig(s.daemon, eng, &runconfig.Config{}, imageImportConfig.Changes) + if err != nil { return err } + imageImportConfig.ContainerConfig = newConfig + if err := s.daemon.Repositories().Import(src, repo, tag, imageImportConfig); err != nil { + return err + } } return nil @@ -859,7 +874,7 @@ func (s *Server) postImagesPush(eng *engine.Engine, version version.Version, w h job.Setenv("tag", r.Form.Get("tag")) if version.GreaterThan("1.0") { job.SetenvBool("json", true) - streamJSON(job, w, true) + streamJSON(job.Stdout, w, true) } else { job.Stdout.Add(utils.NewWriteFlusher(w)) } @@ -978,9 +993,9 @@ func (s *Server) deleteContainers(eng *engine.Engine, version version.Version, w name := vars["name"] config := &daemon.ContainerRmConfig{ - ForceRemove: toBool(r.Form.Get("force")), - RemoveVolume: toBool(r.Form.Get("v")), - RemoveLink: toBool(r.Form.Get("link")), + ForceRemove: boolValue(r, "force"), + RemoveVolume: boolValue(r, "v"), + RemoveLink: boolValue(r, "link"), } if err := s.daemon.ContainerRm(name, config); err != nil { @@ -1005,8 +1020,8 @@ func (s *Server) deleteImages(eng *engine.Engine, version version.Version, w htt } name := vars["name"] - force := toBool(r.Form.Get("force")) - noprune := toBool(r.Form.Get("noprune")) + force := boolValue(r, "force") + noprune := boolValue(r, "noprune") list, err := s.daemon.ImageDelete(name, force, noprune) if err != nil { @@ -1153,19 +1168,19 @@ func (s *Server) postContainersAttach(eng *engine.Engine, version version.Versio } else { errStream = outStream } - logs := toBool(r.Form.Get("logs")) - stream := toBool(r.Form.Get("stream")) + logs := boolValue(r, "logs") + stream := boolValue(r, "stream") var stdin io.ReadCloser var stdout, stderr io.Writer - if toBool(r.Form.Get("stdin")) { + if boolValue(r, "stdin") { stdin = inStream } - if toBool(r.Form.Get("stdout")) { + if boolValue(r, "stdout") { stdout = outStream } - if toBool(r.Form.Get("stderr")) { + if boolValue(r, "stderr") { stderr = errStream } @@ -1209,7 +1224,7 @@ func (s *Server) getContainersByName(eng *engine.Engine, version version.Version if version.LessThan("1.12") { job.SetenvBool("raw", true) } - streamJSON(job, w, false) + streamJSON(job.Stdout, w, false) return job.Run() } @@ -1234,7 +1249,7 @@ func (s *Server) getImagesByName(eng *engine.Engine, version version.Version, w if version.LessThan("1.12") { job.SetenvBool("raw", true) } - streamJSON(job, w, false) + streamJSON(job.Stdout, w, false) return job.Run() } @@ -1247,7 +1262,7 @@ func (s *Server) postBuild(eng *engine.Engine, version version.Version, w http.R authConfig = ®istry.AuthConfig{} configFileEncoded = r.Header.Get("X-Registry-Config") configFile = ®istry.ConfigFile{} - job = eng.Job("build") + buildConfig = builder.NewBuildConfig() ) // This block can be removed when API versions prior to 1.9 are deprecated. @@ -1273,36 +1288,38 @@ func (s *Server) postBuild(eng *engine.Engine, version version.Version, w http.R } if version.GreaterThanOrEqualTo("1.8") { - job.SetenvBool("json", true) - streamJSON(job, w, true) - } else { - job.Stdout.Add(utils.NewWriteFlusher(w)) + w.Header().Set("Content-Type", "application/json") + buildConfig.JSONFormat = true } - if toBool(r.FormValue("forcerm")) && version.GreaterThanOrEqualTo("1.12") { - job.Setenv("rm", "1") + if boolValue(r, "forcerm") && version.GreaterThanOrEqualTo("1.12") { + buildConfig.Remove = true } else if r.FormValue("rm") == "" && version.GreaterThanOrEqualTo("1.12") { - job.Setenv("rm", "1") + buildConfig.Remove = true } else { - job.Setenv("rm", r.FormValue("rm")) + buildConfig.Remove = boolValue(r, "rm") } - if toBool(r.FormValue("pull")) && version.GreaterThanOrEqualTo("1.16") { - job.Setenv("pull", "1") + if boolValue(r, "pull") && version.GreaterThanOrEqualTo("1.16") { + buildConfig.Pull = true } - job.Stdin.Add(r.Body) - job.Setenv("remote", r.FormValue("remote")) - job.Setenv("dockerfile", r.FormValue("dockerfile")) - job.Setenv("t", r.FormValue("t")) - job.Setenv("q", r.FormValue("q")) - job.Setenv("nocache", r.FormValue("nocache")) - job.Setenv("forcerm", r.FormValue("forcerm")) - job.SetenvJson("authConfig", authConfig) - job.SetenvJson("configFile", configFile) - job.Setenv("memswap", r.FormValue("memswap")) - job.Setenv("memory", r.FormValue("memory")) - job.Setenv("cpusetcpus", r.FormValue("cpusetcpus")) - job.Setenv("cpusetmems", r.FormValue("cpusetmems")) - job.Setenv("cpushares", r.FormValue("cpushares")) + + output := utils.NewWriteFlusher(w) + buildConfig.Stdout = output + buildConfig.Context = r.Body + + buildConfig.RemoteURL = r.FormValue("remote") + buildConfig.DockerfileName = r.FormValue("dockerfile") + buildConfig.RepoName = r.FormValue("t") + buildConfig.SuppressOutput = boolValue(r, "q") + buildConfig.NoCache = boolValue(r, "nocache") + buildConfig.ForceRemove = boolValue(r, "forcerm") + buildConfig.AuthConfig = authConfig + buildConfig.ConfigFile = configFile + buildConfig.MemorySwap = int64Value(r, "memswap") + buildConfig.Memory = int64Value(r, "memory") + buildConfig.CpuShares = int64Value(r, "cpushares") + buildConfig.CpuSetCpus = r.FormValue("cpusetcpus") + buildConfig.CpuSetMems = r.FormValue("cpusetmems") // Job cancellation. Note: not all job types support this. if closeNotifier, ok := w.(http.CloseNotifier); ok { @@ -1312,14 +1329,16 @@ func (s *Server) postBuild(eng *engine.Engine, version version.Version, w http.R select { case <-finished: case <-closeNotifier.CloseNotify(): - logrus.Infof("Client disconnected, cancelling job: %s", job.Name) - job.Cancel() + logrus.Infof("Client disconnected, cancelling job: build") + buildConfig.Cancel() } }() } - if err := job.Run(); err != nil { - if !job.Stdout.Used() { + if err := builder.Build(s.daemon, eng, buildConfig); err != nil { + // Do not write the error in the http output if it's still empty. + // This prevents from writing a 200(OK) when there is an interal error. + if !output.Flushed() { return err } sf := streamformatter.NewStreamFormatter(version.GreaterThanOrEqualTo("1.8")) @@ -1673,8 +1692,3 @@ func allocateDaemonPort(addr string) error { } return nil } - -func toBool(s string) bool { - s = strings.ToLower(strings.TrimSpace(s)) - return !(s == "" || s == "0" || s == "no" || s == "false" || s == "none") -} diff --git a/builder/job.go b/builder/job.go index 930d7b7f16..8a1cf3054c 100644 --- a/builder/job.go +++ b/builder/job.go @@ -2,13 +2,13 @@ package builder import ( "bytes" - "encoding/json" "fmt" "io" "io/ioutil" "os" "os/exec" "strings" + "sync" "github.com/docker/docker/api" "github.com/docker/docker/builder/parser" @@ -36,44 +36,61 @@ var validCommitCommands = map[string]bool{ "onbuild": true, } -type BuilderJob struct { - Engine *engine.Engine - Daemon *daemon.Daemon +type Config struct { + DockerfileName string + RemoteURL string + RepoName string + SuppressOutput bool + NoCache bool + Remove bool + ForceRemove bool + Pull bool + JSONFormat bool + Memory int64 + MemorySwap int64 + CpuShares int64 + CpuSetCpus string + CpuSetMems string + AuthConfig *registry.AuthConfig + ConfigFile *registry.ConfigFile + + Stdout io.Writer + Context io.ReadCloser + // When closed, the job has been cancelled. + // Note: not all jobs implement cancellation. + // See Job.Cancel() and Job.WaitCancelled() + cancelled chan struct{} + cancelOnce sync.Once } -func (b *BuilderJob) Install() { - b.Engine.Register("build", b.CmdBuild) - b.Engine.Register("build_config", b.CmdBuildConfig) +// When called, causes the Job.WaitCancelled channel to unblock. +func (b *Config) Cancel() { + b.cancelOnce.Do(func() { + close(b.cancelled) + }) } -func (b *BuilderJob) CmdBuild(job *engine.Job) error { - if len(job.Args) != 0 { - return fmt.Errorf("Usage: %s\n", job.Name) +// Returns a channel which is closed ("never blocks") when the job is cancelled. +func (b *Config) WaitCancelled() <-chan struct{} { + return b.cancelled +} + +func NewBuildConfig() *Config { + return &Config{ + AuthConfig: ®istry.AuthConfig{}, + ConfigFile: ®istry.ConfigFile{}, + cancelled: make(chan struct{}), } +} + +func Build(d *daemon.Daemon, e *engine.Engine, buildConfig *Config) error { var ( - dockerfileName = job.Getenv("dockerfile") - remoteURL = job.Getenv("remote") - repoName = job.Getenv("t") - suppressOutput = job.GetenvBool("q") - noCache = job.GetenvBool("nocache") - rm = job.GetenvBool("rm") - forceRm = job.GetenvBool("forcerm") - pull = job.GetenvBool("pull") - memory = job.GetenvInt64("memory") - memorySwap = job.GetenvInt64("memswap") - cpuShares = job.GetenvInt64("cpushares") - cpuSetCpus = job.Getenv("cpusetcpus") - cpuSetMems = job.Getenv("cpusetmems") - authConfig = ®istry.AuthConfig{} - configFile = ®istry.ConfigFile{} - tag string - context io.ReadCloser + repoName string + tag string + context io.ReadCloser ) - job.GetenvJson("authConfig", authConfig) - job.GetenvJson("configFile", configFile) - - repoName, tag = parsers.ParseRepositoryTag(repoName) + repoName, tag = parsers.ParseRepositoryTag(buildConfig.RepoName) if repoName != "" { if err := registry.ValidateRepositoryName(repoName); err != nil { return err @@ -85,11 +102,11 @@ func (b *BuilderJob) CmdBuild(job *engine.Job) error { } } - if remoteURL == "" { - context = ioutil.NopCloser(job.Stdin) - } else if urlutil.IsGitURL(remoteURL) { - if !urlutil.IsGitTransport(remoteURL) { - remoteURL = "https://" + remoteURL + if buildConfig.RemoteURL == "" { + context = ioutil.NopCloser(buildConfig.Context) + } else if urlutil.IsGitURL(buildConfig.RemoteURL) { + if !urlutil.IsGitTransport(buildConfig.RemoteURL) { + buildConfig.RemoteURL = "https://" + buildConfig.RemoteURL } root, err := ioutil.TempDir("", "docker-build-git") if err != nil { @@ -97,7 +114,7 @@ func (b *BuilderJob) CmdBuild(job *engine.Job) error { } defer os.RemoveAll(root) - if output, err := exec.Command("git", "clone", "--recursive", remoteURL, root).CombinedOutput(); err != nil { + if output, err := exec.Command("git", "clone", "--recursive", buildConfig.RemoteURL, root).CombinedOutput(); err != nil { return fmt.Errorf("Error trying to use git: %s (%s)", err, output) } @@ -106,8 +123,8 @@ func (b *BuilderJob) CmdBuild(job *engine.Job) error { return err } context = c - } else if urlutil.IsURL(remoteURL) { - f, err := httputils.Download(remoteURL) + } else if urlutil.IsURL(buildConfig.RemoteURL) { + f, err := httputils.Download(buildConfig.RemoteURL) if err != nil { return err } @@ -119,9 +136,9 @@ func (b *BuilderJob) CmdBuild(job *engine.Job) error { // When we're downloading just a Dockerfile put it in // the default name - don't allow the client to move/specify it - dockerfileName = api.DefaultDockerfileName + buildConfig.DockerfileName = api.DefaultDockerfileName - c, err := archive.Generate(dockerfileName, string(dockerFile)) + c, err := archive.Generate(buildConfig.DockerfileName, string(dockerFile)) if err != nil { return err } @@ -129,35 +146,35 @@ func (b *BuilderJob) CmdBuild(job *engine.Job) error { } defer context.Close() - sf := streamformatter.NewStreamFormatter(job.GetenvBool("json")) + sf := streamformatter.NewStreamFormatter(buildConfig.JSONFormat) builder := &Builder{ - Daemon: b.Daemon, - Engine: b.Engine, + Daemon: d, + Engine: e, OutStream: &streamformatter.StdoutFormater{ - Writer: job.Stdout, + Writer: buildConfig.Stdout, StreamFormatter: sf, }, ErrStream: &streamformatter.StderrFormater{ - Writer: job.Stdout, + Writer: buildConfig.Stdout, StreamFormatter: sf, }, - Verbose: !suppressOutput, - UtilizeCache: !noCache, - Remove: rm, - ForceRemove: forceRm, - Pull: pull, - OutOld: job.Stdout, + Verbose: !buildConfig.SuppressOutput, + UtilizeCache: !buildConfig.NoCache, + Remove: buildConfig.Remove, + ForceRemove: buildConfig.ForceRemove, + Pull: buildConfig.Pull, + OutOld: buildConfig.Stdout, StreamFormatter: sf, - AuthConfig: authConfig, - ConfigFile: configFile, - dockerfileName: dockerfileName, - cpuShares: cpuShares, - cpuSetCpus: cpuSetCpus, - cpuSetMems: cpuSetMems, - memory: memory, - memorySwap: memorySwap, - cancelled: job.WaitCancelled(), + AuthConfig: buildConfig.AuthConfig, + ConfigFile: buildConfig.ConfigFile, + dockerfileName: buildConfig.DockerfileName, + cpuShares: buildConfig.CpuShares, + cpuSetCpus: buildConfig.CpuSetCpus, + cpuSetMems: buildConfig.CpuSetMems, + memory: buildConfig.Memory, + memorySwap: buildConfig.MemorySwap, + cancelled: buildConfig.WaitCancelled(), } id, err := builder.Run(context) @@ -166,41 +183,28 @@ func (b *BuilderJob) CmdBuild(job *engine.Job) error { } if repoName != "" { - b.Daemon.Repositories().Tag(repoName, tag, id, true) + return d.Repositories().Tag(repoName, tag, id, true) } return nil } -func (b *BuilderJob) CmdBuildConfig(job *engine.Job) error { - if len(job.Args) != 0 { - return fmt.Errorf("Usage: %s\n", job.Name) - } - - var ( - changes = job.GetenvList("changes") - newConfig runconfig.Config - ) - - if err := job.GetenvJson("config", &newConfig); err != nil { - return err - } - +func BuildFromConfig(d *daemon.Daemon, e *engine.Engine, c *runconfig.Config, changes []string) (*runconfig.Config, error) { ast, err := parser.Parse(bytes.NewBufferString(strings.Join(changes, "\n"))) if err != nil { - return err + return nil, err } // ensure that the commands are valid for _, n := range ast.Children { if !validCommitCommands[n.Value] { - return fmt.Errorf("%s is not a valid change command", n.Value) + return nil, fmt.Errorf("%s is not a valid change command", n.Value) } } builder := &Builder{ - Daemon: b.Daemon, - Engine: b.Engine, - Config: &newConfig, + Daemon: d, + Engine: e, + Config: c, OutStream: ioutil.Discard, ErrStream: ioutil.Discard, disableCommit: true, @@ -208,12 +212,32 @@ func (b *BuilderJob) CmdBuildConfig(job *engine.Job) error { for i, n := range ast.Children { if err := builder.dispatch(i, n); err != nil { - return err + return nil, err } } - if err := json.NewEncoder(job.Stdout).Encode(builder.Config); err != nil { - return err - } - return nil + return builder.Config, nil +} + +func Commit(d *daemon.Daemon, eng *engine.Engine, name string, c *daemon.ContainerCommitConfig) (string, error) { + container, err := d.Get(name) + if err != nil { + return "", err + } + + newConfig, err := BuildFromConfig(d, eng, c.Config, c.Changes) + if err != nil { + return "", err + } + + if err := runconfig.Merge(newConfig, container.Config); err != nil { + return "", err + } + + img, err := d.Commit(container, c.Repo, c.Tag, c.Comment, c.Author, c.Pause, newConfig) + if err != nil { + return "", err + } + + return img.ID, nil } diff --git a/daemon/commit.go b/daemon/commit.go index a60ed08191..0c49eb2c95 100644 --- a/daemon/commit.go +++ b/daemon/commit.go @@ -1,12 +1,6 @@ package daemon import ( - "bytes" - "encoding/json" - "io" - - "github.com/Sirupsen/logrus" - "github.com/docker/docker/engine" "github.com/docker/docker/image" "github.com/docker/docker/runconfig" ) @@ -18,49 +12,7 @@ type ContainerCommitConfig struct { Author string Comment string Changes []string - Config io.ReadCloser -} - -func (daemon *Daemon) ContainerCommit(name string, c *ContainerCommitConfig) (string, error) { - container, err := daemon.Get(name) - if err != nil { - return "", err - } - - var ( - subenv engine.Env - config = container.Config - stdoutBuffer = bytes.NewBuffer(nil) - newConfig runconfig.Config - ) - - if err := subenv.Decode(c.Config); err != nil { - logrus.Errorf("%s", err) - } - - buildConfigJob := daemon.eng.Job("build_config") - buildConfigJob.Stdout.Add(stdoutBuffer) - buildConfigJob.SetenvList("changes", c.Changes) - // FIXME this should be remove when we remove deprecated config param - buildConfigJob.SetenvSubEnv("config", &subenv) - - if err := buildConfigJob.Run(); err != nil { - return "", err - } - if err := json.NewDecoder(stdoutBuffer).Decode(&newConfig); err != nil { - return "", err - } - - if err := runconfig.Merge(&newConfig, config); err != nil { - return "", err - } - - img, err := daemon.Commit(container, c.Repo, c.Tag, c.Comment, c.Author, c.Pause, &newConfig) - if err != nil { - return "", err - } - - return img.ID, nil + Config *runconfig.Config } // Commit creates a new filesystem image from the current state of a container. diff --git a/docker/daemon.go b/docker/daemon.go index 0602ddf654..c6241b6060 100644 --- a/docker/daemon.go +++ b/docker/daemon.go @@ -11,7 +11,6 @@ import ( "github.com/Sirupsen/logrus" apiserver "github.com/docker/docker/api/server" "github.com/docker/docker/autogen/dockerversion" - "github.com/docker/docker/builder" "github.com/docker/docker/daemon" _ "github.com/docker/docker/daemon/execdriver/lxc" _ "github.com/docker/docker/daemon/execdriver/native" @@ -141,9 +140,6 @@ func mainDaemon() { "graphdriver": d.GraphDriver().String(), }).Info("Docker daemon") - b := &builder.BuilderJob{eng, d} - b.Install() - // after the daemon is done setting up we can tell the api to start // accepting connections with specified daemon api.AcceptConnections(d) @@ -155,7 +151,6 @@ func mainDaemon() { if errAPI != nil { logrus.Fatalf("Shutting down due to ServeAPI error: %v", errAPI) } - } // currentUserIsOwner checks whether the current user is the owner of the given diff --git a/graph/import.go b/graph/import.go index 5d86ba2cb9..50e605c948 100644 --- a/graph/import.go +++ b/graph/import.go @@ -1,13 +1,10 @@ package graph import ( - "bytes" - "encoding/json" "io" "net/http" "net/url" - "github.com/docker/docker/engine" "github.com/docker/docker/pkg/archive" "github.com/docker/docker/pkg/httputils" "github.com/docker/docker/pkg/progressreader" @@ -17,20 +14,18 @@ import ( ) type ImageImportConfig struct { - Changes []string - InConfig io.ReadCloser - Json bool - OutStream io.Writer - //OutStream WriteFlusher + Changes []string + InConfig io.ReadCloser + Json bool + OutStream io.Writer + ContainerConfig *runconfig.Config } -func (s *TagStore) Import(src string, repo string, tag string, imageImportConfig *ImageImportConfig, eng *engine.Engine) error { +func (s *TagStore) Import(src string, repo string, tag string, imageImportConfig *ImageImportConfig) error { var ( - sf = streamformatter.NewStreamFormatter(imageImportConfig.Json) - archive archive.ArchiveReader - resp *http.Response - stdoutBuffer = bytes.NewBuffer(nil) - newConfig runconfig.Config + sf = streamformatter.NewStreamFormatter(imageImportConfig.Json) + archive archive.ArchiveReader + resp *http.Response ) if src == "-" { @@ -63,20 +58,7 @@ func (s *TagStore) Import(src string, repo string, tag string, imageImportConfig archive = progressReader } - buildConfigJob := eng.Job("build_config") - buildConfigJob.Stdout.Add(stdoutBuffer) - buildConfigJob.SetenvList("changes", imageImportConfig.Changes) - // FIXME this should be remove when we remove deprecated config param - //buildConfigJob.Setenv("config", job.Getenv("config")) - - if err := buildConfigJob.Run(); err != nil { - return err - } - if err := json.NewDecoder(stdoutBuffer).Decode(&newConfig); err != nil { - return err - } - - img, err := s.graph.Create(archive, "", "", "Imported from "+src, "", nil, &newConfig) + img, err := s.graph.Create(archive, "", "", "Imported from "+src, "", nil, imageImportConfig.ContainerConfig) if err != nil { return err } diff --git a/utils/utils.go b/utils/utils.go index a151fc3f0e..ab59826783 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -128,12 +128,14 @@ type WriteFlusher struct { sync.Mutex w io.Writer flusher http.Flusher + flushed bool } func (wf *WriteFlusher) Write(b []byte) (n int, err error) { wf.Lock() defer wf.Unlock() n, err = wf.w.Write(b) + wf.flushed = true wf.flusher.Flush() return n, err } @@ -142,9 +144,16 @@ func (wf *WriteFlusher) Write(b []byte) (n int, err error) { func (wf *WriteFlusher) Flush() { wf.Lock() defer wf.Unlock() + wf.flushed = true wf.flusher.Flush() } +func (wf *WriteFlusher) Flushed() bool { + wf.Lock() + defer wf.Unlock() + return wf.flushed +} + func NewWriteFlusher(w io.Writer) *WriteFlusher { var flusher http.Flusher if f, ok := w.(http.Flusher); ok {