Browse code

Moving runtime.Create to builder.Create

Guillaume J. Charmes authored on 2013/04/25 07:14:10
Showing 3 changed files
... ...
@@ -4,38 +4,80 @@ import (
4 4
 	"bufio"
5 5
 	"fmt"
6 6
 	"io"
7
+	"os"
8
+	"path"
7 9
 	"strings"
10
+	"time"
8 11
 )
9 12
 
10 13
 type Builder struct {
11
-	runtime *Runtime
14
+	runtime      *Runtime
15
+	repositories *TagStore
12 16
 }
13 17
 
14 18
 func NewBuilder(runtime *Runtime) *Builder {
15 19
 	return &Builder{
16
-		runtime: runtime,
20
+		runtime:      runtime,
21
+		repositories: runtime.repositories,
17 22
 	}
18 23
 }
19 24
 
20
-func (builder *Builder) Run(image *Image, cmd ...string) (*Container, error) {
21
-	// FIXME: pass a NopWriter instead of nil
22
-	config, err := ParseRun(append([]string{"-d", image.Id}, cmd...), nil, builder.runtime.capabilities)
23
-	if config.Image == "" {
24
-		return nil, fmt.Errorf("Image not specified")
25
+func (builder *Builder) Create(config *Config) (*Container, error) {
26
+	// Lookup image
27
+	img, err := builder.repositories.LookupImage(config.Image)
28
+	if err != nil {
29
+		return nil, err
25 30
 	}
26
-	if len(config.Cmd) == 0 {
27
-		return nil, fmt.Errorf("Command not specified")
31
+	// Generate id
32
+	id := GenerateId()
33
+	// Generate default hostname
34
+	// FIXME: the lxc template no longer needs to set a default hostname
35
+	if config.Hostname == "" {
36
+		config.Hostname = id[:12]
28 37
 	}
29
-	if config.Tty {
30
-		return nil, fmt.Errorf("The tty mode is not supported within the builder")
38
+
39
+	container := &Container{
40
+		// FIXME: we should generate the ID here instead of receiving it as an argument
41
+		Id:              id,
42
+		Created:         time.Now(),
43
+		Path:            config.Cmd[0],
44
+		Args:            config.Cmd[1:], //FIXME: de-duplicate from config
45
+		Config:          config,
46
+		Image:           img.Id, // Always use the resolved image id
47
+		NetworkSettings: &NetworkSettings{},
48
+		// FIXME: do we need to store this in the container?
49
+		SysInitPath: sysInitPath,
50
+	}
51
+	container.root = builder.runtime.containerRoot(container.Id)
52
+	// Step 1: create the container directory.
53
+	// This doubles as a barrier to avoid race conditions.
54
+	if err := os.Mkdir(container.root, 0700); err != nil {
55
+		return nil, err
31 56
 	}
32 57
 
33
-	// Create new container
34
-	container, err := builder.runtime.Create(config)
35
-	if err != nil {
58
+	// If custom dns exists, then create a resolv.conf for the container
59
+	if len(config.Dns) > 0 {
60
+		container.ResolvConfPath = path.Join(container.root, "resolv.conf")
61
+		f, err := os.Create(container.ResolvConfPath)
62
+		if err != nil {
63
+			return nil, err
64
+		}
65
+		defer f.Close()
66
+		for _, dns := range config.Dns {
67
+			if _, err := f.Write([]byte("nameserver " + dns + "\n")); err != nil {
68
+				return nil, err
69
+			}
70
+		}
71
+	} else {
72
+		container.ResolvConfPath = "/etc/resolv.conf"
73
+	}
74
+
75
+	// Step 2: save the container json
76
+	if err := container.ToDisk(); err != nil {
36 77
 		return nil, err
37 78
 	}
38
-	if err := container.Start(); err != nil {
79
+	// Step 3: register the container
80
+	if err := builder.runtime.Register(container); err != nil {
39 81
 		return nil, err
40 82
 	}
41 83
 	return container, nil
... ...
@@ -96,12 +138,19 @@ func (builder *Builder) Build(dockerfile io.Reader, stdout io.Writer) error {
96 96
 			if image == nil {
97 97
 				return fmt.Errorf("Please provide a source image with `from` prior to run")
98 98
 			}
99
+			config, err := ParseRun([]string{image.Id, "/bin/sh", "-c", tmp[1]}, nil, builder.runtime.capabilities)
100
+			if err != nil {
101
+				return err
102
+			}
99 103
 
100 104
 			// Create the container and start it
101
-			c, err := builder.Run(image, "/bin/sh", "-c", tmp[1])
105
+			c, err := builder.Create(config)
102 106
 			if err != nil {
103 107
 				return err
104 108
 			}
109
+			if err := c.Start(); err != nil {
110
+				return err
111
+			}
105 112
 			tmpContainers[c.Id] = struct{}{}
106 113
 
107 114
 			// Wait for it to finish
... ...
@@ -134,11 +183,24 @@ func (builder *Builder) Build(dockerfile io.Reader, stdout io.Writer) error {
134 134
 			}
135 135
 			defer file.Body.Close()
136 136
 
137
-			c, err := builder.Run(base, "echo", "insert", tmp2[0], tmp2[1])
137
+			config, err := ParseRun([]string{base.Id, "echo", "insert", tmp2[0], tmp2[1]}, nil, builder.runtime.capabilities)
138
+			if err != nil {
139
+				return err
140
+			}
141
+			c, err := builder.Create(config)
138 142
 			if err != nil {
139 143
 				return err
140 144
 			}
141 145
 
146
+			if err := c.Start(); err != nil {
147
+				return err
148
+			}
149
+
150
+			// Wait for echo to finish
151
+			if result := c.Wait(); result != 0 {
152
+				return fmt.Errorf("!!! '%s' return non-zero exit code '%d'. Aborting.", tmp[1], result)
153
+			}
154
+
142 155
 			if err := c.Inject(file.Body, tmp2[1]); err != nil {
143 156
 				return err
144 157
 			}
... ...
@@ -91,8 +91,13 @@ func (srv *Server) CmdInsert(stdin io.ReadCloser, stdout rcli.DockerConn, args .
91 91
 	}
92 92
 	defer file.Body.Close()
93 93
 
94
+	config, err := ParseRun([]string{img.Id, "echo", "insert", url, path}, nil, srv.runtime.capabilities)
95
+	if err != nil {
96
+		return err
97
+	}
98
+
94 99
 	b := NewBuilder(srv.runtime)
95
-	c, err := b.Run(img, "echo", "insert", url, path)
100
+	c, err := b.Create(config)
96 101
 	if err != nil {
97 102
 		return err
98 103
 	}
... ...
@@ -1065,8 +1070,10 @@ func (srv *Server) CmdRun(stdin io.ReadCloser, stdout rcli.DockerConn, args ...s
1065 1065
 	// or tell the client there is no options
1066 1066
 	stdout.Flush()
1067 1067
 
1068
+	b := NewBuilder(srv.runtime)
1069
+
1068 1070
 	// Create new container
1069
-	container, err := srv.runtime.Create(config)
1071
+	container, err := b.Create(config)
1070 1072
 	if err != nil {
1071 1073
 		// If container not found, try to pull it
1072 1074
 		if srv.runtime.graph.IsNotExist(err) {
... ...
@@ -1074,7 +1081,7 @@ func (srv *Server) CmdRun(stdin io.ReadCloser, stdout rcli.DockerConn, args ...s
1074 1074
 			if err = srv.CmdPull(stdin, stdout, config.Image); err != nil {
1075 1075
 				return err
1076 1076
 			}
1077
-			if container, err = srv.runtime.Create(config); err != nil {
1077
+			if container, err = b.Create(config); err != nil {
1078 1078
 				return err
1079 1079
 			}
1080 1080
 		} else {
... ...
@@ -12,7 +12,6 @@ import (
12 12
 	"path"
13 13
 	"sort"
14 14
 	"strings"
15
-	"time"
16 15
 )
17 16
 
18 17
 type Capabilities struct {
... ...
@@ -116,7 +115,6 @@ func (runtime *Runtime) mergeConfig(userConf, imageConf *Config) {
116 116
 }
117 117
 
118 118
 func (runtime *Runtime) Create(config *Config) (*Container, error) {
119
-
120 119
 	// Lookup image
121 120
 	img, err := runtime.repositories.LookupImage(config.Image)
122 121
 	if err != nil {
... ...
@@ -151,7 +149,6 @@ func (runtime *Runtime) Create(config *Config) (*Container, error) {
151 151
 		// FIXME: do we need to store this in the container?
152 152
 		SysInitPath: sysInitPath,
153 153
 	}
154
-
155 154
 	container.root = runtime.containerRoot(container.Id)
156 155
 	// Step 1: create the container directory.
157 156
 	// This doubles as a barrier to avoid race conditions.
... ...
@@ -187,6 +184,7 @@ func (runtime *Runtime) Create(config *Config) (*Container, error) {
187 187
 	return container, nil
188 188
 }
189 189
 
190
+======= end
190 191
 func (runtime *Runtime) Load(id string) (*Container, error) {
191 192
 	container := &Container{root: runtime.containerRoot(id)}
192 193
 	if err := container.FromDisk(); err != nil {