| ... | ... |
@@ -477,7 +477,7 @@ func (srv *Server) CmdImport(stdin io.ReadCloser, stdout rcli.DockerConn, args . |
| 477 | 477 |
} |
| 478 | 478 |
archive = ProgressReader(resp.Body, int(resp.ContentLength), stdout, "Importing %v/%v (%v)") |
| 479 | 479 |
} |
| 480 |
- img, err := srv.runtime.graph.Create(archive, nil, "Imported from "+src, "") |
|
| 480 |
+ img, err := srv.runtime.graph.Create(archive, nil, "Imported from "+src, "", nil) |
|
| 481 | 481 |
if err != nil {
|
| 482 | 482 |
return err |
| 483 | 483 |
} |
| ... | ... |
@@ -726,6 +726,8 @@ func (srv *Server) CmdCommit(stdin io.ReadCloser, stdout io.Writer, args ...stri |
| 726 | 726 |
"Create a new image from a container's changes") |
| 727 | 727 |
flComment := cmd.String("m", "", "Commit message")
|
| 728 | 728 |
flAuthor := cmd.String("author", "", "Author (eg. \"John Hannibal Smith <hannibal@a-team.com>\"")
|
| 729 |
+ flConfig := cmd.String("config", "", "Config automatically applied when the image is run. This option must be the last one.")
|
|
| 730 |
+ flCommand := cmd.String("command", "", "Command to run when starting the image")
|
|
| 729 | 731 |
if err := cmd.Parse(args); err != nil {
|
| 730 | 732 |
return nil |
| 731 | 733 |
} |
| ... | ... |
@@ -734,7 +736,22 @@ func (srv *Server) CmdCommit(stdin io.ReadCloser, stdout io.Writer, args ...stri |
| 734 | 734 |
cmd.Usage() |
| 735 | 735 |
return nil |
| 736 | 736 |
} |
| 737 |
- img, err := srv.runtime.Commit(containerName, repository, tag, *flComment, *flAuthor) |
|
| 737 |
+ |
|
| 738 |
+ var config []string |
|
| 739 |
+ if *flConfig != "" {
|
|
| 740 |
+ config = strings.Split(*flConfig, " ") |
|
| 741 |
+ } |
|
| 742 |
+ if *flCommand != "" {
|
|
| 743 |
+ config = append(config, "", "/bin/sh", "-c", *flCommand) |
|
| 744 |
+ } else if *flConfig != "" {
|
|
| 745 |
+ config = append(config, "", "") |
|
| 746 |
+ } |
|
| 747 |
+ c, err := ParseRun(config, stdout, srv.runtime.capabilities) |
|
| 748 |
+ if err != nil {
|
|
| 749 |
+ return err |
|
| 750 |
+ } |
|
| 751 |
+ |
|
| 752 |
+ img, err := srv.runtime.Commit(containerName, repository, tag, *flComment, *flAuthor, c) |
|
| 738 | 753 |
if err != nil {
|
| 739 | 754 |
return err |
| 740 | 755 |
} |
| ... | ... |
@@ -925,10 +942,6 @@ func (srv *Server) CmdRun(stdin io.ReadCloser, stdout rcli.DockerConn, args ...s |
| 925 | 925 |
fmt.Fprintln(stdout, "Error: Image not specified") |
| 926 | 926 |
return fmt.Errorf("Image not specified")
|
| 927 | 927 |
} |
| 928 |
- if len(config.Cmd) == 0 {
|
|
| 929 |
- fmt.Fprintln(stdout, "Error: Command not specified") |
|
| 930 |
- return fmt.Errorf("Command not specified")
|
|
| 931 |
- } |
|
| 932 | 928 |
|
| 933 | 929 |
if config.Tty {
|
| 934 | 930 |
stdout.SetOptionRawTerminal() |
| ... | ... |
@@ -84,13 +84,14 @@ func (graph *Graph) Get(name string) (*Image, error) {
|
| 84 | 84 |
} |
| 85 | 85 |
|
| 86 | 86 |
// Create creates a new image and registers it in the graph. |
| 87 |
-func (graph *Graph) Create(layerData Archive, container *Container, comment, author string) (*Image, error) {
|
|
| 87 |
+func (graph *Graph) Create(layerData Archive, container *Container, comment, author string, config *Config) (*Image, error) {
|
|
| 88 | 88 |
img := &Image{
|
| 89 | 89 |
Id: GenerateId(), |
| 90 | 90 |
Comment: comment, |
| 91 | 91 |
Created: time.Now(), |
| 92 | 92 |
DockerVersion: VERSION, |
| 93 | 93 |
Author: author, |
| 94 |
+ Config: config, |
|
| 94 | 95 |
} |
| 95 | 96 |
if container != nil {
|
| 96 | 97 |
img.Parent = container.Image |
| ... | ... |
@@ -77,12 +77,59 @@ func (runtime *Runtime) containerRoot(id string) string {
|
| 77 | 77 |
return path.Join(runtime.repository, id) |
| 78 | 78 |
} |
| 79 | 79 |
|
| 80 |
+func (runtime *Runtime) mergeConfig(userConf, imageConf *Config) {
|
|
| 81 |
+ if userConf.Hostname != "" {
|
|
| 82 |
+ userConf.Hostname = imageConf.Hostname |
|
| 83 |
+ } |
|
| 84 |
+ if userConf.User != "" {
|
|
| 85 |
+ userConf.User = imageConf.User |
|
| 86 |
+ } |
|
| 87 |
+ if userConf.Memory == 0 {
|
|
| 88 |
+ userConf.Memory = imageConf.Memory |
|
| 89 |
+ } |
|
| 90 |
+ if userConf.MemorySwap == 0 {
|
|
| 91 |
+ userConf.MemorySwap = imageConf.MemorySwap |
|
| 92 |
+ } |
|
| 93 |
+ if userConf.PortSpecs == nil || len(userConf.PortSpecs) == 0 {
|
|
| 94 |
+ userConf.PortSpecs = imageConf.PortSpecs |
|
| 95 |
+ } |
|
| 96 |
+ if !userConf.Tty {
|
|
| 97 |
+ userConf.Tty = userConf.Tty |
|
| 98 |
+ } |
|
| 99 |
+ if !userConf.OpenStdin {
|
|
| 100 |
+ userConf.OpenStdin = imageConf.OpenStdin |
|
| 101 |
+ } |
|
| 102 |
+ if !userConf.StdinOnce {
|
|
| 103 |
+ userConf.StdinOnce = imageConf.StdinOnce |
|
| 104 |
+ } |
|
| 105 |
+ if userConf.Env == nil || len(userConf.Env) == 0 {
|
|
| 106 |
+ userConf.Env = imageConf.Env |
|
| 107 |
+ } |
|
| 108 |
+ if userConf.Cmd == nil || len(userConf.Cmd) == 0 {
|
|
| 109 |
+ userConf.Cmd = imageConf.Cmd |
|
| 110 |
+ } |
|
| 111 |
+ if userConf.Dns == nil || len(userConf.Dns) == 0 {
|
|
| 112 |
+ userConf.Dns = imageConf.Dns |
|
| 113 |
+ } |
|
| 114 |
+} |
|
| 115 |
+ |
|
| 80 | 116 |
func (runtime *Runtime) Create(config *Config) (*Container, error) {
|
| 117 |
+ |
|
| 81 | 118 |
// Lookup image |
| 82 | 119 |
img, err := runtime.repositories.LookupImage(config.Image) |
| 83 | 120 |
if err != nil {
|
| 84 | 121 |
return nil, err |
| 85 | 122 |
} |
| 123 |
+ |
|
| 124 |
+ //runtime.mergeConfig(config, img.Config) |
|
| 125 |
+ if img.Config != nil {
|
|
| 126 |
+ config = img.Config |
|
| 127 |
+ } |
|
| 128 |
+ |
|
| 129 |
+ if config.Cmd == nil {
|
|
| 130 |
+ return nil, fmt.Errorf("No command specified")
|
|
| 131 |
+ } |
|
| 132 |
+ |
|
| 86 | 133 |
// Generate id |
| 87 | 134 |
id := GenerateId() |
| 88 | 135 |
// Generate default hostname |
| ... | ... |
@@ -103,6 +150,7 @@ func (runtime *Runtime) Create(config *Config) (*Container, error) {
|
| 103 | 103 |
// FIXME: do we need to store this in the container? |
| 104 | 104 |
SysInitPath: sysInitPath, |
| 105 | 105 |
} |
| 106 |
+ |
|
| 106 | 107 |
container.root = runtime.containerRoot(container.Id) |
| 107 | 108 |
// Step 1: create the container directory. |
| 108 | 109 |
// This doubles as a barrier to avoid race conditions. |
| ... | ... |
@@ -249,7 +297,7 @@ func (runtime *Runtime) Destroy(container *Container) error {
|
| 249 | 249 |
|
| 250 | 250 |
// Commit creates a new filesystem image from the current state of a container. |
| 251 | 251 |
// The image can optionally be tagged into a repository |
| 252 |
-func (runtime *Runtime) Commit(id, repository, tag, comment, author string) (*Image, error) {
|
|
| 252 |
+func (runtime *Runtime) Commit(id, repository, tag, comment, author string, config *Config) (*Image, error) {
|
|
| 253 | 253 |
container := runtime.Get(id) |
| 254 | 254 |
if container == nil {
|
| 255 | 255 |
return nil, fmt.Errorf("No such container: %s", id)
|
| ... | ... |
@@ -261,7 +309,7 @@ func (runtime *Runtime) Commit(id, repository, tag, comment, author string) (*Im |
| 261 | 261 |
return nil, err |
| 262 | 262 |
} |
| 263 | 263 |
// Create a new image from the container's base layers + a new layer from container changes |
| 264 |
- img, err := runtime.graph.Create(rwTar, container, comment, author) |
|
| 264 |
+ img, err := runtime.graph.Create(rwTar, container, comment, author, config) |
|
| 265 | 265 |
if err != nil {
|
| 266 | 266 |
return nil, err |
| 267 | 267 |
} |
| ... | ... |
@@ -314,13 +362,13 @@ func NewRuntime() (*Runtime, error) {
|
| 314 | 314 |
_, err2 := ioutil.ReadFile(path.Join(cgroupMemoryMountpoint, "memory.soft_limit_in_bytes")) |
| 315 | 315 |
runtime.capabilities.MemoryLimit = err1 == nil && err2 == nil |
| 316 | 316 |
if !runtime.capabilities.MemoryLimit {
|
| 317 |
- log.Printf("WARNING: Your kernel does not support cgroup memory limit.")
|
|
| 317 |
+ log.Printf("WARNING: Your kernel does not support cgroup memory limit.")
|
|
| 318 | 318 |
} |
| 319 | 319 |
|
| 320 | 320 |
_, err = ioutil.ReadFile(path.Join(cgroupMemoryMountpoint, "memory.memsw.limit_in_bytes")) |
| 321 | 321 |
runtime.capabilities.SwapLimit = err == nil |
| 322 | 322 |
if !runtime.capabilities.SwapLimit {
|
| 323 |
- log.Printf("WARNING: Your kernel does not support cgroup swap limit.")
|
|
| 323 |
+ log.Printf("WARNING: Your kernel does not support cgroup swap limit.")
|
|
| 324 | 324 |
} |
| 325 | 325 |
} |
| 326 | 326 |
return runtime, nil |