Sfoglia il codice sorgente

Merge pull request #1825 from dotcloud/merge-builder-runtime

Refactor to merge builder.go into runtime.go
Solomon Hykes 12 anni fa
parent
commit
e503f6a878
8 ha cambiato i file con 203 aggiunte e 237 eliminazioni
  1. 14 25
      api_test.go
  2. 0 154
      builder.go
  3. 4 6
      buildfile.go
  4. 32 38
      container_test.go
  5. 143 0
      runtime.go
  6. 5 7
      runtime_test.go
  7. 4 6
      server.go
  8. 1 1
      utils_test.go

+ 14 - 25
api_test.go

@@ -321,7 +321,7 @@ func TestGetContainersJSON(t *testing.T) {
 
 	srv := &Server{runtime: runtime}
 
-	container, err := NewBuilder(runtime).Create(&Config{
+	container, err := runtime.Create(&Config{
 		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"echo", "test"},
 	})
@@ -357,10 +357,8 @@ func TestGetContainersExport(t *testing.T) {
 
 	srv := &Server{runtime: runtime}
 
-	builder := NewBuilder(runtime)
-
 	// Create a container and remove a file
-	container, err := builder.Create(
+	container, err := runtime.Create(
 		&Config{
 			Image: GetTestImage(runtime).ID,
 			Cmd:   []string{"touch", "/test"},
@@ -409,10 +407,8 @@ func TestGetContainersChanges(t *testing.T) {
 
 	srv := &Server{runtime: runtime}
 
-	builder := NewBuilder(runtime)
-
 	// Create a container and remove a file
-	container, err := builder.Create(
+	container, err := runtime.Create(
 		&Config{
 			Image: GetTestImage(runtime).ID,
 			Cmd:   []string{"/bin/rm", "/etc/passwd"},
@@ -458,9 +454,7 @@ func TestGetContainersTop(t *testing.T) {
 
 	srv := &Server{runtime: runtime}
 
-	builder := NewBuilder(runtime)
-
-	container, err := builder.Create(
+	container, err := runtime.Create(
 		&Config{
 			Image:     GetTestImage(runtime).ID,
 			Cmd:       []string{"/bin/sh", "-c", "cat"},
@@ -541,10 +535,8 @@ func TestGetContainersByName(t *testing.T) {
 
 	srv := &Server{runtime: runtime}
 
-	builder := NewBuilder(runtime)
-
 	// Create a container and remove a file
-	container, err := builder.Create(
+	container, err := runtime.Create(
 		&Config{
 			Image: GetTestImage(runtime).ID,
 			Cmd:   []string{"echo", "test"},
@@ -574,10 +566,9 @@ func TestPostCommit(t *testing.T) {
 
 	srv := &Server{runtime: runtime}
 
-	builder := NewBuilder(runtime)
 
 	// Create a container and remove a file
-	container, err := builder.Create(
+	container, err := runtime.Create(
 		&Config{
 			Image: GetTestImage(runtime).ID,
 			Cmd:   []string{"touch", "/test"},
@@ -671,7 +662,7 @@ func TestPostContainersKill(t *testing.T) {
 
 	srv := &Server{runtime: runtime}
 
-	container, err := NewBuilder(runtime).Create(
+	container, err := runtime.Create(
 		&Config{
 			Image:     GetTestImage(runtime).ID,
 			Cmd:       []string{"/bin/cat"},
@@ -713,7 +704,7 @@ func TestPostContainersRestart(t *testing.T) {
 
 	srv := &Server{runtime: runtime}
 
-	container, err := NewBuilder(runtime).Create(
+	container, err := runtime.Create(
 		&Config{
 			Image:     GetTestImage(runtime).ID,
 			Cmd:       []string{"/bin/cat"},
@@ -767,7 +758,7 @@ func TestPostContainersStart(t *testing.T) {
 
 	srv := &Server{runtime: runtime}
 
-	container, err := NewBuilder(runtime).Create(
+	container, err := runtime.Create(
 		&Config{
 			Image:     GetTestImage(runtime).ID,
 			Cmd:       []string{"/bin/cat"},
@@ -817,7 +808,7 @@ func TestPostContainersStop(t *testing.T) {
 
 	srv := &Server{runtime: runtime}
 
-	container, err := NewBuilder(runtime).Create(
+	container, err := runtime.Create(
 		&Config{
 			Image:     GetTestImage(runtime).ID,
 			Cmd:       []string{"/bin/cat"},
@@ -864,7 +855,7 @@ func TestPostContainersWait(t *testing.T) {
 
 	srv := &Server{runtime: runtime}
 
-	container, err := NewBuilder(runtime).Create(
+	container, err := runtime.Create(
 		&Config{
 			Image:     GetTestImage(runtime).ID,
 			Cmd:       []string{"/bin/sleep", "1"},
@@ -906,7 +897,7 @@ func TestPostContainersAttach(t *testing.T) {
 
 	srv := &Server{runtime: runtime}
 
-	container, err := NewBuilder(runtime).Create(
+	container, err := runtime.Create(
 		&Config{
 			Image:     GetTestImage(runtime).ID,
 			Cmd:       []string{"/bin/cat"},
@@ -998,7 +989,7 @@ func TestDeleteContainers(t *testing.T) {
 
 	srv := &Server{runtime: runtime}
 
-	container, err := NewBuilder(runtime).Create(&Config{
+	container, err := runtime.Create(&Config{
 		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"touch", "/test"},
 	})
@@ -1185,10 +1176,8 @@ func TestPostContainersCopy(t *testing.T) {
 
 	srv := &Server{runtime: runtime}
 
-	builder := NewBuilder(runtime)
-
 	// Create a container and remove a file
-	container, err := builder.Create(
+	container, err := runtime.Create(
 		&Config{
 			Image: GetTestImage(runtime).ID,
 			Cmd:   []string{"touch", "/test.txt"},

+ 0 - 154
builder.go

@@ -1,154 +0,0 @@
-package docker
-
-import (
-	"fmt"
-	"github.com/dotcloud/docker/utils"
-	"os"
-	"path"
-	"time"
-)
-
-var defaultDns = []string{"8.8.8.8", "8.8.4.4"}
-
-type Builder struct {
-	runtime      *Runtime
-	repositories *TagStore
-	graph        *Graph
-
-	config *Config
-	image  *Image
-}
-
-func NewBuilder(runtime *Runtime) *Builder {
-	return &Builder{
-		runtime:      runtime,
-		graph:        runtime.graph,
-		repositories: runtime.repositories,
-	}
-}
-
-func (builder *Builder) Create(config *Config) (*Container, error) {
-	// Lookup image
-	img, err := builder.repositories.LookupImage(config.Image)
-	if err != nil {
-		return nil, err
-	}
-
-	if img.Config != nil {
-		MergeConfig(config, img.Config)
-	}
-
-	if len(config.Entrypoint) != 0 && config.Cmd == nil {
-		config.Cmd = []string{}
-	} else if config.Cmd == nil || len(config.Cmd) == 0 {
-		return nil, fmt.Errorf("No command specified")
-	}
-
-	// Generate id
-	id := GenerateID()
-	// Generate default hostname
-	// FIXME: the lxc template no longer needs to set a default hostname
-	if config.Hostname == "" {
-		config.Hostname = id[:12]
-	}
-
-	var args []string
-	var entrypoint string
-
-	if len(config.Entrypoint) != 0 {
-		entrypoint = config.Entrypoint[0]
-		args = append(config.Entrypoint[1:], config.Cmd...)
-	} else {
-		entrypoint = config.Cmd[0]
-		args = config.Cmd[1:]
-	}
-
-	container := &Container{
-		// FIXME: we should generate the ID here instead of receiving it as an argument
-		ID:              id,
-		Created:         time.Now(),
-		Path:            entrypoint,
-		Args:            args, //FIXME: de-duplicate from config
-		Config:          config,
-		Image:           img.ID, // Always use the resolved image id
-		NetworkSettings: &NetworkSettings{},
-		// FIXME: do we need to store this in the container?
-		SysInitPath: sysInitPath,
-	}
-	container.root = builder.runtime.containerRoot(container.ID)
-	// Step 1: create the container directory.
-	// This doubles as a barrier to avoid race conditions.
-	if err := os.Mkdir(container.root, 0700); err != nil {
-		return nil, err
-	}
-
-	resolvConf, err := utils.GetResolvConf()
-	if err != nil {
-		return nil, err
-	}
-
-	if len(config.Dns) == 0 && len(builder.runtime.Dns) == 0 && utils.CheckLocalDns(resolvConf) {
-		//"WARNING: Docker detected local DNS server on resolv.conf. Using default external servers: %v", defaultDns
-		builder.runtime.Dns = defaultDns
-	}
-
-	// If custom dns exists, then create a resolv.conf for the container
-	if len(config.Dns) > 0 || len(builder.runtime.Dns) > 0 {
-		var dns []string
-		if len(config.Dns) > 0 {
-			dns = config.Dns
-		} else {
-			dns = builder.runtime.Dns
-		}
-		container.ResolvConfPath = path.Join(container.root, "resolv.conf")
-		f, err := os.Create(container.ResolvConfPath)
-		if err != nil {
-			return nil, err
-		}
-		defer f.Close()
-		for _, dns := range dns {
-			if _, err := f.Write([]byte("nameserver " + dns + "\n")); err != nil {
-				return nil, err
-			}
-		}
-	} else {
-		container.ResolvConfPath = "/etc/resolv.conf"
-	}
-
-	// Step 2: save the container json
-	if err := container.ToDisk(); err != nil {
-		return nil, err
-	}
-	// Step 3: register the container
-	if err := builder.runtime.Register(container); err != nil {
-		return nil, err
-	}
-	return container, nil
-}
-
-// Commit creates a new filesystem image from the current state of a container.
-// The image can optionally be tagged into a repository
-func (builder *Builder) Commit(container *Container, repository, tag, comment, author string, config *Config) (*Image, error) {
-	// FIXME: freeze the container before copying it to avoid data corruption?
-	// FIXME: this shouldn't be in commands.
-	if err := container.EnsureMounted(); err != nil {
-		return nil, err
-	}
-
-	rwTar, err := container.ExportRw()
-	if err != nil {
-		return nil, err
-	}
-	// Create a new image from the container's base layers + a new layer from container changes
-	img, err := builder.graph.Create(rwTar, container, comment, author, config)
-	if err != nil {
-		return nil, err
-	}
-	// Register the image if needed
-	if repository != "" {
-		if err := builder.repositories.Set(repository, tag, img.ID, true); err != nil {
-			return img, err
-		}
-	}
-	return img, nil
-}

+ 4 - 6
buildfile.go

@@ -23,7 +23,6 @@ type BuildFile interface {
 
 type buildFile struct {
 	runtime *Runtime
-	builder *Builder
 	srv     *Server
 
 	image        string
@@ -337,7 +336,7 @@ func (b *buildFile) CmdAdd(args string) error {
 
 	b.config.Image = b.image
 	// Create the container and start it
-	container, err := b.builder.Create(b.config)
+	container, err := b.runtime.Create(b.config)
 	if err != nil {
 		return err
 	}
@@ -372,7 +371,7 @@ func (b *buildFile) run() (string, error) {
 	b.config.Image = b.image
 
 	// Create the container and start it
-	c, err := b.builder.Create(b.config)
+	c, err := b.runtime.Create(b.config)
 	if err != nil {
 		return "", err
 	}
@@ -428,7 +427,7 @@ func (b *buildFile) commit(id string, autoCmd []string, comment string) error {
 			}
 		}
 
-		container, err := b.builder.Create(b.config)
+		container, err := b.runtime.Create(b.config)
 		if err != nil {
 			return err
 		}
@@ -450,7 +449,7 @@ func (b *buildFile) commit(id string, autoCmd []string, comment string) error {
 	autoConfig := *b.config
 	autoConfig.Cmd = autoCmd
 	// Commit the container
-	image, err := b.builder.Commit(container, "", "", "", b.maintainer, &autoConfig)
+	image, err := b.runtime.Commit(container, "", "", "", b.maintainer, &autoConfig)
 	if err != nil {
 		return err
 	}
@@ -524,7 +523,6 @@ func (b *buildFile) Build(context io.Reader) (string, error) {
 
 func NewBuildFile(srv *Server, out io.Writer, verbose, utilizeCache bool) BuildFile {
 	return &buildFile{
-		builder:       NewBuilder(srv.runtime),
 		runtime:       srv.runtime,
 		srv:           srv,
 		config:        &Config{},

+ 32 - 38
container_test.go

@@ -18,7 +18,7 @@ import (
 func TestIDFormat(t *testing.T) {
 	runtime := mkRuntime(t)
 	defer nuke(runtime)
-	container1, err := NewBuilder(runtime).Create(
+	container1, err := runtime.Create(
 		&Config{
 			Image: GetTestImage(runtime).ID,
 			Cmd:   []string{"/bin/sh", "-c", "echo hello world"},
@@ -388,7 +388,7 @@ func TestRun(t *testing.T) {
 func TestOutput(t *testing.T) {
 	runtime := mkRuntime(t)
 	defer nuke(runtime)
-	container, err := NewBuilder(runtime).Create(
+	container, err := runtime.Create(
 		&Config{
 			Image: GetTestImage(runtime).ID,
 			Cmd:   []string{"echo", "-n", "foobar"},
@@ -411,7 +411,7 @@ func TestKillDifferentUser(t *testing.T) {
 	runtime := mkRuntime(t)
 	defer nuke(runtime)
 
-	container, err := NewBuilder(runtime).Create(&Config{
+	container, err := runtime.Create(&Config{
 		Image:     GetTestImage(runtime).ID,
 		Cmd:       []string{"cat"},
 		OpenStdin: true,
@@ -471,7 +471,7 @@ func TestCreateVolume(t *testing.T) {
 	if err != nil {
 		t.Fatal(err)
 	}
-	c, err := NewBuilder(runtime).Create(config)
+	c, err := runtime.Create(config)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -486,7 +486,7 @@ func TestCreateVolume(t *testing.T) {
 func TestKill(t *testing.T) {
 	runtime := mkRuntime(t)
 	defer nuke(runtime)
-	container, err := NewBuilder(runtime).Create(&Config{
+	container, err := runtime.Create(&Config{
 		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"sleep", "2"},
 	},
@@ -530,9 +530,7 @@ func TestExitCode(t *testing.T) {
 	runtime := mkRuntime(t)
 	defer nuke(runtime)
 
-	builder := NewBuilder(runtime)
-
-	trueContainer, err := builder.Create(&Config{
+	trueContainer, err := runtime.Create(&Config{
 		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"/bin/true", ""},
 	})
@@ -547,7 +545,7 @@ func TestExitCode(t *testing.T) {
 		t.Errorf("Unexpected exit code %d (expected 0)", trueContainer.State.ExitCode)
 	}
 
-	falseContainer, err := builder.Create(&Config{
+	falseContainer, err := runtime.Create(&Config{
 		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"/bin/false", ""},
 	})
@@ -566,7 +564,7 @@ func TestExitCode(t *testing.T) {
 func TestRestart(t *testing.T) {
 	runtime := mkRuntime(t)
 	defer nuke(runtime)
-	container, err := NewBuilder(runtime).Create(&Config{
+	container, err := runtime.Create(&Config{
 		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"echo", "-n", "foobar"},
 	},
@@ -596,7 +594,7 @@ func TestRestart(t *testing.T) {
 func TestRestartStdin(t *testing.T) {
 	runtime := mkRuntime(t)
 	defer nuke(runtime)
-	container, err := NewBuilder(runtime).Create(&Config{
+	container, err := runtime.Create(&Config{
 		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"cat"},
 
@@ -673,10 +671,8 @@ func TestUser(t *testing.T) {
 	runtime := mkRuntime(t)
 	defer nuke(runtime)
 
-	builder := NewBuilder(runtime)
-
 	// Default user must be root
-	container, err := builder.Create(&Config{
+	container, err := runtime.Create(&Config{
 		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"id"},
 	},
@@ -694,7 +690,7 @@ func TestUser(t *testing.T) {
 	}
 
 	// Set a username
-	container, err = builder.Create(&Config{
+	container, err = runtime.Create(&Config{
 		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"id"},
 
@@ -714,7 +710,7 @@ func TestUser(t *testing.T) {
 	}
 
 	// Set a UID
-	container, err = builder.Create(&Config{
+	container, err = runtime.Create(&Config{
 		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"id"},
 
@@ -734,7 +730,7 @@ func TestUser(t *testing.T) {
 	}
 
 	// Set a different user by uid
-	container, err = builder.Create(&Config{
+	container, err = runtime.Create(&Config{
 		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"id"},
 
@@ -756,7 +752,7 @@ func TestUser(t *testing.T) {
 	}
 
 	// Set a different user by username
-	container, err = builder.Create(&Config{
+	container, err = runtime.Create(&Config{
 		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"id"},
 
@@ -776,7 +772,7 @@ func TestUser(t *testing.T) {
 	}
 
 	// Test an wrong username
-	container, err = builder.Create(&Config{
+	container, err = runtime.Create(&Config{
 		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"id"},
 
@@ -797,9 +793,7 @@ func TestMultipleContainers(t *testing.T) {
 	runtime := mkRuntime(t)
 	defer nuke(runtime)
 
-	builder := NewBuilder(runtime)
-
-	container1, err := builder.Create(&Config{
+	container1, err := runtime.Create(&Config{
 		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"sleep", "2"},
 	},
@@ -809,7 +803,7 @@ func TestMultipleContainers(t *testing.T) {
 	}
 	defer runtime.Destroy(container1)
 
-	container2, err := builder.Create(&Config{
+	container2, err := runtime.Create(&Config{
 		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"sleep", "2"},
 	},
@@ -853,7 +847,7 @@ func TestMultipleContainers(t *testing.T) {
 func TestStdin(t *testing.T) {
 	runtime := mkRuntime(t)
 	defer nuke(runtime)
-	container, err := NewBuilder(runtime).Create(&Config{
+	container, err := runtime.Create(&Config{
 		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"cat"},
 
@@ -898,7 +892,7 @@ func TestStdin(t *testing.T) {
 func TestTty(t *testing.T) {
 	runtime := mkRuntime(t)
 	defer nuke(runtime)
-	container, err := NewBuilder(runtime).Create(&Config{
+	container, err := runtime.Create(&Config{
 		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"cat"},
 
@@ -943,7 +937,7 @@ func TestTty(t *testing.T) {
 func TestEnv(t *testing.T) {
 	runtime := mkRuntime(t)
 	defer nuke(runtime)
-	container, err := NewBuilder(runtime).Create(&Config{
+	container, err := runtime.Create(&Config{
 		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"env"},
 	},
@@ -992,7 +986,7 @@ func TestEnv(t *testing.T) {
 func TestEntrypoint(t *testing.T) {
 	runtime := mkRuntime(t)
 	defer nuke(runtime)
-	container, err := NewBuilder(runtime).Create(
+	container, err := runtime.Create(
 		&Config{
 			Image:      GetTestImage(runtime).ID,
 			Entrypoint: []string{"/bin/echo"},
@@ -1015,7 +1009,7 @@ func TestEntrypoint(t *testing.T) {
 func TestEntrypointNoCmd(t *testing.T) {
 	runtime := mkRuntime(t)
 	defer nuke(runtime)
-	container, err := NewBuilder(runtime).Create(
+	container, err := runtime.Create(
 		&Config{
 			Image:      GetTestImage(runtime).ID,
 			Entrypoint: []string{"/bin/echo", "foobar"},
@@ -1066,7 +1060,7 @@ func TestLXCConfig(t *testing.T) {
 	cpuMin := 100
 	cpuMax := 10000
 	cpu := cpuMin + rand.Intn(cpuMax-cpuMin)
-	container, err := NewBuilder(runtime).Create(&Config{
+	container, err := runtime.Create(&Config{
 		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"/bin/true"},
 
@@ -1090,7 +1084,7 @@ func TestLXCConfig(t *testing.T) {
 func TestCustomLxcConfig(t *testing.T) {
 	runtime := mkRuntime(t)
 	defer nuke(runtime)
-	container, err := NewBuilder(runtime).Create(&Config{
+	container, err := runtime.Create(&Config{
 		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"/bin/true"},
 
@@ -1121,7 +1115,7 @@ func BenchmarkRunSequencial(b *testing.B) {
 	runtime := mkRuntime(b)
 	defer nuke(runtime)
 	for i := 0; i < b.N; i++ {
-		container, err := NewBuilder(runtime).Create(&Config{
+		container, err := runtime.Create(&Config{
 			Image: GetTestImage(runtime).ID,
 			Cmd:   []string{"echo", "-n", "foo"},
 		},
@@ -1153,7 +1147,7 @@ func BenchmarkRunParallel(b *testing.B) {
 		complete := make(chan error)
 		tasks = append(tasks, complete)
 		go func(i int, complete chan error) {
-			container, err := NewBuilder(runtime).Create(&Config{
+			container, err := runtime.Create(&Config{
 				Image: GetTestImage(runtime).ID,
 				Cmd:   []string{"echo", "-n", "foo"},
 			},
@@ -1229,7 +1223,7 @@ func TestBindMounts(t *testing.T) {
 func TestVolumesFromReadonlyMount(t *testing.T) {
 	runtime := mkRuntime(t)
 	defer nuke(runtime)
-	container, err := NewBuilder(runtime).Create(
+	container, err := runtime.Create(
 		&Config{
 			Image:   GetTestImage(runtime).ID,
 			Cmd:     []string{"/bin/echo", "-n", "foobar"},
@@ -1248,7 +1242,7 @@ func TestVolumesFromReadonlyMount(t *testing.T) {
 		t.Fail()
 	}
 
-	container2, err := NewBuilder(runtime).Create(
+	container2, err := runtime.Create(
 		&Config{
 			Image:       GetTestImage(runtime).ID,
 			Cmd:         []string{"/bin/echo", "-n", "foobar"},
@@ -1284,7 +1278,7 @@ func TestRestartWithVolumes(t *testing.T) {
 	runtime := mkRuntime(t)
 	defer nuke(runtime)
 
-	container, err := NewBuilder(runtime).Create(&Config{
+	container, err := runtime.Create(&Config{
 		Image:   GetTestImage(runtime).ID,
 		Cmd:     []string{"echo", "-n", "foobar"},
 		Volumes: map[string]struct{}{"/test": {}},
@@ -1327,7 +1321,7 @@ func TestVolumesFromWithVolumes(t *testing.T) {
 	runtime := mkRuntime(t)
 	defer nuke(runtime)
 
-	container, err := NewBuilder(runtime).Create(&Config{
+	container, err := runtime.Create(&Config{
 		Image:   GetTestImage(runtime).ID,
 		Cmd:     []string{"sh", "-c", "echo -n bar > /test/foo"},
 		Volumes: map[string]struct{}{"/test": {}},
@@ -1354,7 +1348,7 @@ func TestVolumesFromWithVolumes(t *testing.T) {
 		t.Fail()
 	}
 
-	container2, err := NewBuilder(runtime).Create(
+	container2, err := runtime.Create(
 		&Config{
 			Image:       GetTestImage(runtime).ID,
 			Cmd:         []string{"cat", "/test/foo"},
@@ -1395,7 +1389,7 @@ func TestOnlyLoopbackExistsWhenUsingDisableNetworkOption(t *testing.T) {
 	if err != nil {
 		t.Fatal(err)
 	}
-	c, err := NewBuilder(runtime).Create(config)
+	c, err := runtime.Create(config)
 	if err != nil {
 		t.Fatal(err)
 	}

+ 143 - 0
runtime.go

@@ -12,8 +12,11 @@ import (
 	"path"
 	"sort"
 	"strings"
+	"time"
 )
 
+var defaultDns = []string{"8.8.8.8", "8.8.4.4"}
+
 type Capabilities struct {
 	MemoryLimit            bool
 	SwapLimit              bool
@@ -42,6 +45,7 @@ func init() {
 	sysInitPath = utils.SelfPath()
 }
 
+// List returns an array of all containers registered in the runtime.
 func (runtime *Runtime) List() []*Container {
 	containers := new(History)
 	for e := runtime.containers.Front(); e != nil; e = e.Next() {
@@ -60,6 +64,8 @@ func (runtime *Runtime) getContainerElement(id string) *list.Element {
 	return nil
 }
 
+// Get looks for a container by the specified ID or name, and returns it.
+// If the container is not found, or if an error occurs, nil is returned.
 func (runtime *Runtime) Get(name string) *Container {
 	id, err := runtime.idIndex.Get(name)
 	if err != nil {
@@ -72,6 +78,8 @@ func (runtime *Runtime) Get(name string) *Container {
 	return e.Value.(*Container)
 }
 
+// Exists returns a true if a container of the specified ID or name exists,
+// false otherwise.
 func (runtime *Runtime) Exists(id string) bool {
 	return runtime.Get(id) != nil
 }
@@ -80,6 +88,9 @@ func (runtime *Runtime) containerRoot(id string) string {
 	return path.Join(runtime.repository, id)
 }
 
+// Load reads the contents of a container from disk and registers
+// it with Register.
+// This is typically done at startup.
 func (runtime *Runtime) Load(id string) (*Container, error) {
 	container := &Container{root: runtime.containerRoot(id)}
 	if err := container.FromDisk(); err != nil {
@@ -177,6 +188,7 @@ func (runtime *Runtime) LogToDisk(src *utils.WriteBroadcaster, dst, stream strin
 	return nil
 }
 
+// Destroy unregisters a container from the runtime and cleanly removes its contents from the filesystem.
 func (runtime *Runtime) Destroy(container *Container) error {
 	if container == nil {
 		return fmt.Errorf("The given container is <nil>")
@@ -233,6 +245,7 @@ func (runtime *Runtime) restore() error {
 	return nil
 }
 
+// FIXME: comment please!
 func (runtime *Runtime) UpdateCapabilities(quiet bool) {
 	if cgroupMemoryMountpoint, err := utils.FindCgroupMountpoint("memory"); err != nil {
 		if !quiet {
@@ -260,6 +273,133 @@ func (runtime *Runtime) UpdateCapabilities(quiet bool) {
 	}
 }
 
+// Create creates a new container from the given configuration.
+func (runtime *Runtime) Create(config *Config) (*Container, error) {
+	// Lookup image
+	img, err := runtime.repositories.LookupImage(config.Image)
+	if err != nil {
+		return nil, err
+	}
+
+	if img.Config != nil {
+		MergeConfig(config, img.Config)
+	}
+
+	if len(config.Entrypoint) != 0 && config.Cmd == nil {
+		config.Cmd = []string{}
+	} else if config.Cmd == nil || len(config.Cmd) == 0 {
+		return nil, fmt.Errorf("No command specified")
+	}
+
+	// Generate id
+	id := GenerateID()
+	// Generate default hostname
+	// FIXME: the lxc template no longer needs to set a default hostname
+	if config.Hostname == "" {
+		config.Hostname = id[:12]
+	}
+
+	var args []string
+	var entrypoint string
+
+	if len(config.Entrypoint) != 0 {
+		entrypoint = config.Entrypoint[0]
+		args = append(config.Entrypoint[1:], config.Cmd...)
+	} else {
+		entrypoint = config.Cmd[0]
+		args = config.Cmd[1:]
+	}
+
+	container := &Container{
+		// FIXME: we should generate the ID here instead of receiving it as an argument
+		ID:              id,
+		Created:         time.Now(),
+		Path:            entrypoint,
+		Args:            args, //FIXME: de-duplicate from config
+		Config:          config,
+		Image:           img.ID, // Always use the resolved image id
+		NetworkSettings: &NetworkSettings{},
+		// 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.
+	if err := os.Mkdir(container.root, 0700); err != nil {
+		return nil, err
+	}
+
+	resolvConf, err := utils.GetResolvConf()
+	if err != nil {
+		return nil, err
+	}
+
+	if len(config.Dns) == 0 && len(runtime.Dns) == 0 && utils.CheckLocalDns(resolvConf) {
+		//"WARNING: Docker detected local DNS server on resolv.conf. Using default external servers: %v", defaultDns
+		runtime.Dns = defaultDns
+	}
+
+	// If custom dns exists, then create a resolv.conf for the container
+	if len(config.Dns) > 0 || len(runtime.Dns) > 0 {
+		var dns []string
+		if len(config.Dns) > 0 {
+			dns = config.Dns
+		} else {
+			dns = runtime.Dns
+		}
+		container.ResolvConfPath = path.Join(container.root, "resolv.conf")
+		f, err := os.Create(container.ResolvConfPath)
+		if err != nil {
+			return nil, err
+		}
+		defer f.Close()
+		for _, dns := range dns {
+			if _, err := f.Write([]byte("nameserver " + dns + "\n")); err != nil {
+				return nil, err
+			}
+		}
+	} else {
+		container.ResolvConfPath = "/etc/resolv.conf"
+	}
+
+	// Step 2: save the container json
+	if err := container.ToDisk(); err != nil {
+		return nil, err
+	}
+	// Step 3: register the container
+	if err := runtime.Register(container); err != nil {
+		return nil, err
+	}
+	return container, nil
+}
+
+// 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(container *Container, repository, tag, comment, author string, config *Config) (*Image, error) {
+	// FIXME: freeze the container before copying it to avoid data corruption?
+	// FIXME: this shouldn't be in commands.
+	if err := container.EnsureMounted(); err != nil {
+		return nil, err
+	}
+
+	rwTar, err := container.ExportRw()
+	if err != nil {
+		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, config)
+	if err != nil {
+		return nil, err
+	}
+	// Register the image if needed
+	if repository != "" {
+		if err := runtime.repositories.Set(repository, tag, img.ID, true); err != nil {
+			return img, err
+		}
+	}
+	return img, nil
+}
+
 // FIXME: harmonize with NewGraph()
 func NewRuntime(flGraphPath string, autoRestart bool, dns []string) (*Runtime, error) {
 	runtime, err := NewRuntimeFromDirectory(flGraphPath, autoRestart)
@@ -325,6 +465,8 @@ func NewRuntimeFromDirectory(root string, autoRestart bool) (*Runtime, error) {
 	return runtime, nil
 }
 
+// History is a convenience type for storing a list of containers,
+// ordered by creation date.
 type History []*Container
 
 func (history *History) Len() int {
@@ -347,3 +489,4 @@ func (history *History) Add(container *Container) {
 	*history = append(*history, container)
 	sort.Sort(history)
 }
+

+ 5 - 7
runtime_test.go

@@ -144,9 +144,7 @@ func TestRuntimeCreate(t *testing.T) {
 		t.Errorf("Expected 0 containers, %v found", len(runtime.List()))
 	}
 
-	builder := NewBuilder(runtime)
-
-	container, err := builder.Create(&Config{
+	container, err := runtime.Create(&Config{
 		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"ls", "-al"},
 	},
@@ -187,7 +185,7 @@ func TestRuntimeCreate(t *testing.T) {
 	}
 
 	// Make sure crete with bad parameters returns an error
-	_, err = builder.Create(
+	_, err = runtime.Create(
 		&Config{
 			Image: GetTestImage(runtime).ID,
 		},
@@ -196,7 +194,7 @@ func TestRuntimeCreate(t *testing.T) {
 		t.Fatal("Builder.Create should throw an error when Cmd is missing")
 	}
 
-	_, err = builder.Create(
+	_, err = runtime.Create(
 		&Config{
 			Image: GetTestImage(runtime).ID,
 			Cmd:   []string{},
@@ -210,7 +208,7 @@ func TestRuntimeCreate(t *testing.T) {
 func TestDestroy(t *testing.T) {
 	runtime := mkRuntime(t)
 	defer nuke(runtime)
-	container, err := NewBuilder(runtime).Create(&Config{
+	container, err := runtime.Create(&Config{
 		Image: GetTestImage(runtime).ID,
 		Cmd:   []string{"ls", "-al"},
 	},
@@ -296,7 +294,7 @@ func startEchoServerContainer(t *testing.T, proto string) (*Runtime, *Container,
 			t.Fatal(fmt.Errorf("Unknown protocol %v", proto))
 		}
 		t.Log("Trying port", strPort)
-		container, err = NewBuilder(runtime).Create(&Config{
+		container, err = runtime.Create(&Config{
 			Image:     GetTestImage(runtime).ID,
 			Cmd:       []string{"sh", "-c", cmd},
 			PortSpecs: []string{fmt.Sprintf("%s/%s", strPort, proto)},

+ 4 - 6
server.go

@@ -139,8 +139,7 @@ func (srv *Server) ImageInsert(name, url, path string, out io.Writer, sf *utils.
 		return "", err
 	}
 
-	b := NewBuilder(srv.runtime)
-	c, err := b.Create(config)
+	c, err := srv.runtime.Create(config)
 	if err != nil {
 		return "", err
 	}
@@ -149,7 +148,7 @@ func (srv *Server) ImageInsert(name, url, path string, out io.Writer, sf *utils.
 		return "", err
 	}
 	// FIXME: Handle custom repo, tag comment, author
-	img, err = b.Commit(c, "", "", img.Comment, img.Author, nil)
+	img, err = srv.runtime.Commit(c, "", "", img.Comment, img.Author, nil)
 	if err != nil {
 		return "", err
 	}
@@ -400,7 +399,7 @@ func (srv *Server) ContainerCommit(name, repo, tag, author, comment string, conf
 	if container == nil {
 		return "", fmt.Errorf("No such container: %s", name)
 	}
-	img, err := NewBuilder(srv.runtime).Commit(container, repo, tag, comment, author, config)
+	img, err := srv.runtime.Commit(container, repo, tag, comment, author, config)
 	if err != nil {
 		return "", err
 	}
@@ -915,8 +914,7 @@ func (srv *Server) ContainerCreate(config *Config) (string, error) {
 	if config.Memory > 0 && !srv.runtime.capabilities.SwapLimit {
 		config.MemorySwap = -1
 	}
-	b := NewBuilder(srv.runtime)
-	container, err := b.Create(config)
+	container, err := srv.runtime.Create(config)
 	if err != nil {
 		if srv.runtime.graph.IsNotExist(err) {
 

+ 1 - 1
utils_test.go

@@ -101,7 +101,7 @@ func mkContainer(r *Runtime, args []string, t *testing.T) (*Container, *HostConf
 	if config.Image == "_" {
 		config.Image = GetTestImage(r).ID
 	}
-	c, err := NewBuilder(r).Create(config)
+	c, err := r.Create(config)
 	if err != nil {
 		return nil, nil, err
 	}