Browse code

Implement -config and -command in CmdCommit in order to allow autorun

Guillaume J. Charmes authored on 2013/04/26 08:48:31
Showing 4 changed files
... ...
@@ -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
... ...
@@ -24,6 +24,7 @@ type Image struct {
24 24
 	ContainerConfig Config    `json:"container_config,omitempty"`
25 25
 	DockerVersion   string    `json:"docker_version,omitempty"`
26 26
 	Author          string    `json:"author,omitempty"`
27
+	Config          *Config   `json:"config,omitempty"`
27 28
 	graph           *Graph
28 29
 }
29 30
 
... ...
@@ -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