From 51d6228261cdc379aade581ee504b2c59a3e02a9 Mon Sep 17 00:00:00 2001 From: "Guillaume J. Charmes" Date: Thu, 25 Apr 2013 16:48:31 -0700 Subject: [PATCH] Implement -config and -command in CmdCommit in order to allow autorun --- commands.go | 25 ++++++++++++++++++------ graph.go | 3 ++- image.go | 1 + runtime.go | 56 +++++++++++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 74 insertions(+), 11 deletions(-) diff --git a/commands.go b/commands.go index f0013d41e5..8e0a351728 100644 --- a/commands.go +++ b/commands.go @@ -477,7 +477,7 @@ func (srv *Server) CmdImport(stdin io.ReadCloser, stdout rcli.DockerConn, args . } archive = ProgressReader(resp.Body, int(resp.ContentLength), stdout, "Importing %v/%v (%v)") } - img, err := srv.runtime.graph.Create(archive, nil, "Imported from "+src, "") + img, err := srv.runtime.graph.Create(archive, nil, "Imported from "+src, "", nil) if err != nil { return err } @@ -726,6 +726,8 @@ func (srv *Server) CmdCommit(stdin io.ReadCloser, stdout io.Writer, args ...stri "Create a new image from a container's changes") flComment := cmd.String("m", "", "Commit message") flAuthor := cmd.String("author", "", "Author (eg. \"John Hannibal Smith \"") + flConfig := cmd.String("config", "", "Config automatically applied when the image is run. This option must be the last one.") + flCommand := cmd.String("command", "", "Command to run when starting the image") if err := cmd.Parse(args); err != nil { return nil } @@ -734,7 +736,22 @@ func (srv *Server) CmdCommit(stdin io.ReadCloser, stdout io.Writer, args ...stri cmd.Usage() return nil } - img, err := srv.runtime.Commit(containerName, repository, tag, *flComment, *flAuthor) + + var config []string + if *flConfig != "" { + config = strings.Split(*flConfig, " ") + } + if *flCommand != "" { + config = append(config, "", "/bin/sh", "-c", *flCommand) + } else if *flConfig != "" { + config = append(config, "", "") + } + c, err := ParseRun(config, stdout, srv.runtime.capabilities) + if err != nil { + return err + } + + img, err := srv.runtime.Commit(containerName, repository, tag, *flComment, *flAuthor, c) if err != nil { return err } @@ -925,10 +942,6 @@ func (srv *Server) CmdRun(stdin io.ReadCloser, stdout rcli.DockerConn, args ...s fmt.Fprintln(stdout, "Error: Image not specified") return fmt.Errorf("Image not specified") } - if len(config.Cmd) == 0 { - fmt.Fprintln(stdout, "Error: Command not specified") - return fmt.Errorf("Command not specified") - } if config.Tty { stdout.SetOptionRawTerminal() diff --git a/graph.go b/graph.go index c0e5000913..bf22bb19f0 100644 --- a/graph.go +++ b/graph.go @@ -84,13 +84,14 @@ func (graph *Graph) Get(name string) (*Image, error) { } // Create creates a new image and registers it in the graph. -func (graph *Graph) Create(layerData Archive, container *Container, comment, author string) (*Image, error) { +func (graph *Graph) Create(layerData Archive, container *Container, comment, author string, config *Config) (*Image, error) { img := &Image{ Id: GenerateId(), Comment: comment, Created: time.Now(), DockerVersion: VERSION, Author: author, + Config: config, } if container != nil { img.Parent = container.Image diff --git a/image.go b/image.go index 78a7f02c68..09c0f8dcf6 100644 --- a/image.go +++ b/image.go @@ -24,6 +24,7 @@ type Image struct { ContainerConfig Config `json:"container_config,omitempty"` DockerVersion string `json:"docker_version,omitempty"` Author string `json:"author,omitempty"` + Config *Config `json:"config,omitempty"` graph *Graph } diff --git a/runtime.go b/runtime.go index d6eb0f3c91..9d2d889e8d 100644 --- a/runtime.go +++ b/runtime.go @@ -77,12 +77,59 @@ func (runtime *Runtime) containerRoot(id string) string { return path.Join(runtime.repository, id) } +func (runtime *Runtime) mergeConfig(userConf, imageConf *Config) { + if userConf.Hostname != "" { + userConf.Hostname = imageConf.Hostname + } + if userConf.User != "" { + userConf.User = imageConf.User + } + if userConf.Memory == 0 { + userConf.Memory = imageConf.Memory + } + if userConf.MemorySwap == 0 { + userConf.MemorySwap = imageConf.MemorySwap + } + if userConf.PortSpecs == nil || len(userConf.PortSpecs) == 0 { + userConf.PortSpecs = imageConf.PortSpecs + } + if !userConf.Tty { + userConf.Tty = userConf.Tty + } + if !userConf.OpenStdin { + userConf.OpenStdin = imageConf.OpenStdin + } + if !userConf.StdinOnce { + userConf.StdinOnce = imageConf.StdinOnce + } + if userConf.Env == nil || len(userConf.Env) == 0 { + userConf.Env = imageConf.Env + } + if userConf.Cmd == nil || len(userConf.Cmd) == 0 { + userConf.Cmd = imageConf.Cmd + } + if userConf.Dns == nil || len(userConf.Dns) == 0 { + userConf.Dns = imageConf.Dns + } +} + func (runtime *Runtime) Create(config *Config) (*Container, error) { + // Lookup image img, err := runtime.repositories.LookupImage(config.Image) if err != nil { return nil, err } + + //runtime.mergeConfig(config, img.Config) + if img.Config != nil { + config = img.Config + } + + if config.Cmd == nil { + return nil, fmt.Errorf("No command specified") + } + // Generate id id := GenerateId() // Generate default hostname @@ -103,6 +150,7 @@ func (runtime *Runtime) Create(config *Config) (*Container, error) { // FIXME: do we need to store this in the container? SysInitPath: sysInitPath, } + container.root = runtime.containerRoot(container.Id) // Step 1: create the container directory. // This doubles as a barrier to avoid race conditions. @@ -249,7 +297,7 @@ func (runtime *Runtime) Destroy(container *Container) error { // Commit creates a new filesystem image from the current state of a container. // The image can optionally be tagged into a repository -func (runtime *Runtime) Commit(id, repository, tag, comment, author string) (*Image, error) { +func (runtime *Runtime) Commit(id, repository, tag, comment, author string, config *Config) (*Image, error) { container := runtime.Get(id) if container == nil { return nil, fmt.Errorf("No such container: %s", id) @@ -261,7 +309,7 @@ func (runtime *Runtime) Commit(id, repository, tag, comment, author string) (*Im return nil, err } // Create a new image from the container's base layers + a new layer from container changes - img, err := runtime.graph.Create(rwTar, container, comment, author) + img, err := runtime.graph.Create(rwTar, container, comment, author, config) if err != nil { return nil, err } @@ -314,13 +362,13 @@ func NewRuntime() (*Runtime, error) { _, err2 := ioutil.ReadFile(path.Join(cgroupMemoryMountpoint, "memory.soft_limit_in_bytes")) runtime.capabilities.MemoryLimit = err1 == nil && err2 == nil if !runtime.capabilities.MemoryLimit { - log.Printf("WARNING: Your kernel does not support cgroup memory limit.") + log.Printf("WARNING: Your kernel does not support cgroup memory limit.") } _, err = ioutil.ReadFile(path.Join(cgroupMemoryMountpoint, "memory.memsw.limit_in_bytes")) runtime.capabilities.SwapLimit = err == nil if !runtime.capabilities.SwapLimit { - log.Printf("WARNING: Your kernel does not support cgroup swap limit.") + log.Printf("WARNING: Your kernel does not support cgroup swap limit.") } } return runtime, nil