Bladeren bron

+ Commit default runtime options with a layer

Solomon Hykes 12 jaren geleden
bovenliggende
commit
f7aaa06606
6 gewijzigde bestanden met toevoegingen van 149 en 17 verwijderingen
  1. 11 6
      commands.go
  2. 80 2
      container_test.go
  3. 2 1
      graph.go
  4. 6 6
      graph_test.go
  5. 1 0
      image.go
  6. 49 2
      runtime.go

+ 11 - 6
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)")
 		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 {
 	if err != nil {
 		return err
 		return err
 	}
 	}
@@ -726,6 +726,7 @@ func (srv *Server) CmdCommit(stdin io.ReadCloser, stdout io.Writer, args ...stri
 		"Create a new image from a container's changes")
 		"Create a new image from a container's changes")
 	flComment := cmd.String("m", "", "Commit message")
 	flComment := cmd.String("m", "", "Commit message")
 	flAuthor := cmd.String("author", "", "Author (eg. \"John Hannibal Smith <hannibal@a-team.com>\"")
 	flAuthor := cmd.String("author", "", "Author (eg. \"John Hannibal Smith <hannibal@a-team.com>\"")
+	flConfig := cmd.String("config", "", "Config automatically applied when the image is run. "+`(ex: -config '{"Cmd": ["cat", "/world"], "PortSpecs": ["22"]}')`)
 	if err := cmd.Parse(args); err != nil {
 	if err := cmd.Parse(args); err != nil {
 		return nil
 		return nil
 	}
 	}
@@ -734,7 +735,15 @@ func (srv *Server) CmdCommit(stdin io.ReadCloser, stdout io.Writer, args ...stri
 		cmd.Usage()
 		cmd.Usage()
 		return nil
 		return nil
 	}
 	}
-	img, err := srv.runtime.Commit(containerName, repository, tag, *flComment, *flAuthor)
+
+	config := &Config{}
+	if *flConfig != "" {
+		if err := json.Unmarshal([]byte(*flConfig), config); err != nil {
+			return err
+		}
+	}
+
+	img, err := srv.runtime.Commit(containerName, repository, tag, *flComment, *flAuthor, config)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
@@ -925,10 +934,6 @@ func (srv *Server) CmdRun(stdin io.ReadCloser, stdout rcli.DockerConn, args ...s
 		fmt.Fprintln(stdout, "Error: Image not specified")
 		fmt.Fprintln(stdout, "Error: Image not specified")
 		return fmt.Errorf("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 {
 	if config.Tty {
 		stdout.SetOptionRawTerminal()
 		stdout.SetOptionRawTerminal()

+ 80 - 2
container_test.go

@@ -184,7 +184,7 @@ func TestDiff(t *testing.T) {
 	if err != nil {
 	if err != nil {
 		t.Error(err)
 		t.Error(err)
 	}
 	}
-	img, err := runtime.graph.Create(rwTar, container1, "unit test commited image - diff", "")
+	img, err := runtime.graph.Create(rwTar, container1, "unit test commited image - diff", "", nil)
 	if err != nil {
 	if err != nil {
 		t.Error(err)
 		t.Error(err)
 	}
 	}
@@ -217,6 +217,84 @@ func TestDiff(t *testing.T) {
 	}
 	}
 }
 }
 
 
+func TestCommitAutoRun(t *testing.T) {
+	runtime, err := newTestRuntime()
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer nuke(runtime)
+	container1, err := runtime.Create(
+		&Config{
+			Image: GetTestImage(runtime).Id,
+			Cmd:   []string{"/bin/sh", "-c", "echo hello > /world"},
+		},
+	)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer runtime.Destroy(container1)
+
+	if container1.State.Running {
+		t.Errorf("Container shouldn't be running")
+	}
+	if err := container1.Run(); err != nil {
+		t.Fatal(err)
+	}
+	if container1.State.Running {
+		t.Errorf("Container shouldn't be running")
+	}
+
+	rwTar, err := container1.ExportRw()
+	if err != nil {
+		t.Error(err)
+	}
+	img, err := runtime.graph.Create(rwTar, container1, "unit test commited image", "", &Config{Cmd: []string{"cat", "/world"}})
+	if err != nil {
+		t.Error(err)
+	}
+
+	// FIXME: Make a TestCommit that stops here and check docker.root/layers/img.id/world
+
+	container2, err := runtime.Create(
+		&Config{
+			Image: img.Id,
+		},
+	)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer runtime.Destroy(container2)
+	stdout, err := container2.StdoutPipe()
+	if err != nil {
+		t.Fatal(err)
+	}
+	stderr, err := container2.StderrPipe()
+	if err != nil {
+		t.Fatal(err)
+	}
+	if err := container2.Start(); err != nil {
+		t.Fatal(err)
+	}
+	container2.Wait()
+	output, err := ioutil.ReadAll(stdout)
+	if err != nil {
+		t.Fatal(err)
+	}
+	output2, err := ioutil.ReadAll(stderr)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if err := stdout.Close(); err != nil {
+		t.Fatal(err)
+	}
+	if err := stderr.Close(); err != nil {
+		t.Fatal(err)
+	}
+	if string(output) != "hello\n" {
+		t.Fatalf("Unexpected output. Expected %s, received: %s (err: %s)", "hello\n", output, output2)
+	}
+}
+
 func TestCommitRun(t *testing.T) {
 func TestCommitRun(t *testing.T) {
 	runtime, err := newTestRuntime()
 	runtime, err := newTestRuntime()
 	if err != nil {
 	if err != nil {
@@ -248,7 +326,7 @@ func TestCommitRun(t *testing.T) {
 	if err != nil {
 	if err != nil {
 		t.Error(err)
 		t.Error(err)
 	}
 	}
-	img, err := runtime.graph.Create(rwTar, container1, "unit test commited image", "")
+	img, err := runtime.graph.Create(rwTar, container1, "unit test commited image", "", nil)
 	if err != nil {
 	if err != nil {
 		t.Error(err)
 		t.Error(err)
 	}
 	}

+ 2 - 1
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.
 // 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{
 	img := &Image{
 		Id:            GenerateId(),
 		Id:            GenerateId(),
 		Comment:       comment,
 		Comment:       comment,
 		Created:       time.Now(),
 		Created:       time.Now(),
 		DockerVersion: VERSION,
 		DockerVersion: VERSION,
 		Author:        author,
 		Author:        author,
+		Config:        config,
 	}
 	}
 	if container != nil {
 	if container != nil {
 		img.Parent = container.Image
 		img.Parent = container.Image

+ 6 - 6
graph_test.go

@@ -62,7 +62,7 @@ func TestGraphCreate(t *testing.T) {
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
-	image, err := graph.Create(archive, nil, "Testing", "")
+	image, err := graph.Create(archive, nil, "Testing", "", nil)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -122,7 +122,7 @@ func TestMount(t *testing.T) {
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
-	image, err := graph.Create(archive, nil, "Testing", "")
+	image, err := graph.Create(archive, nil, "Testing", "", nil)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -166,7 +166,7 @@ func createTestImage(graph *Graph, t *testing.T) *Image {
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
-	img, err := graph.Create(archive, nil, "Test image", "")
+	img, err := graph.Create(archive, nil, "Test image", "", nil)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -181,7 +181,7 @@ func TestDelete(t *testing.T) {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 	assertNImages(graph, t, 0)
 	assertNImages(graph, t, 0)
-	img, err := graph.Create(archive, nil, "Bla bla", "")
+	img, err := graph.Create(archive, nil, "Bla bla", "", nil)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -192,11 +192,11 @@ func TestDelete(t *testing.T) {
 	assertNImages(graph, t, 0)
 	assertNImages(graph, t, 0)
 
 
 	// Test 2 create (same name) / 1 delete
 	// Test 2 create (same name) / 1 delete
-	img1, err := graph.Create(archive, nil, "Testing", "")
+	img1, err := graph.Create(archive, nil, "Testing", "", nil)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
-	if _, err = graph.Create(archive, nil, "Testing", ""); err != nil {
+	if _, err = graph.Create(archive, nil, "Testing", "", nil); err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 	assertNImages(graph, t, 2)
 	assertNImages(graph, t, 2)

+ 1 - 0
image.go

@@ -24,6 +24,7 @@ type Image struct {
 	ContainerConfig Config    `json:"container_config,omitempty"`
 	ContainerConfig Config    `json:"container_config,omitempty"`
 	DockerVersion   string    `json:"docker_version,omitempty"`
 	DockerVersion   string    `json:"docker_version,omitempty"`
 	Author          string    `json:"author,omitempty"`
 	Author          string    `json:"author,omitempty"`
+	Config          *Config   `json:"config,omitempty"`
 	graph           *Graph
 	graph           *Graph
 }
 }
 
 

+ 49 - 2
runtime.go

@@ -78,12 +78,58 @@ func (runtime *Runtime) containerRoot(id string) string {
 	return path.Join(runtime.repository, id)
 	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) {
 func (runtime *Runtime) Create(config *Config) (*Container, error) {
+
 	// Lookup image
 	// Lookup image
 	img, err := runtime.repositories.LookupImage(config.Image)
 	img, err := runtime.repositories.LookupImage(config.Image)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
+
+	if img.Config != nil {
+		runtime.mergeConfig(config, img.Config)
+	}
+
+	if config.Cmd == nil {
+		return nil, fmt.Errorf("No command specified")
+	}
+
 	// Generate id
 	// Generate id
 	id := GenerateId()
 	id := GenerateId()
 	// Generate default hostname
 	// Generate default hostname
@@ -104,6 +150,7 @@ func (runtime *Runtime) Create(config *Config) (*Container, error) {
 		// FIXME: do we need to store this in the container?
 		// FIXME: do we need to store this in the container?
 		SysInitPath: sysInitPath,
 		SysInitPath: sysInitPath,
 	}
 	}
+
 	container.root = runtime.containerRoot(container.Id)
 	container.root = runtime.containerRoot(container.Id)
 	// Step 1: create the container directory.
 	// Step 1: create the container directory.
 	// This doubles as a barrier to avoid race conditions.
 	// This doubles as a barrier to avoid race conditions.
@@ -265,7 +312,7 @@ func (runtime *Runtime) Destroy(container *Container) error {
 
 
 // Commit creates a new filesystem image from the current state of a container.
 // Commit creates a new filesystem image from the current state of a container.
 // The image can optionally be tagged into a repository
 // 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)
 	container := runtime.Get(id)
 	if container == nil {
 	if container == nil {
 		return nil, fmt.Errorf("No such container: %s", id)
 		return nil, fmt.Errorf("No such container: %s", id)
@@ -277,7 +324,7 @@ func (runtime *Runtime) Commit(id, repository, tag, comment, author string) (*Im
 		return nil, err
 		return nil, err
 	}
 	}
 	// Create a new image from the container's base layers + a new layer from container changes
 	// 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 {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}