... | ... |
@@ -1,5 +1,30 @@ |
1 | 1 |
# Changelog |
2 | 2 |
|
3 |
+## 0.3.1 (2013-05-08) |
|
4 |
+ + Builder: Implement the autorun capability within docker builder |
|
5 |
+ + Builder: Add caching to docker builder |
|
6 |
+ + Builder: Add support for docker builder with native API as top level command |
|
7 |
+ + Runtime: Add go version to debug infos |
|
8 |
+ + Builder: Implement ENV within docker builder |
|
9 |
+ + Registry: Add docker search top level command in order to search a repository |
|
10 |
+ + Images: output graph of images to dot (graphviz) |
|
11 |
+ + Documentation: new introduction and high-level overview |
|
12 |
+ + Documentation: Add the documentation for docker builder |
|
13 |
+ + Website: new high-level overview |
|
14 |
+ - Makefile: Swap "go get" for "go get -d", especially to compile on go1.1rc |
|
15 |
+ - Images: fix ByParent function |
|
16 |
+ - Builder: Check the command existance prior create and add Unit tests for the case |
|
17 |
+ - Registry: Fix pull for official images with specific tag |
|
18 |
+ - Registry: Fix issue when login in with a different user and trying to push |
|
19 |
+ - Documentation: CSS fix for docker documentation to make REST API docs look better. |
|
20 |
+ - Documentation: Fixed CouchDB example page header mistake |
|
21 |
+ - Documentation: fixed README formatting |
|
22 |
+ * Registry: Improve checksum - async calculation |
|
23 |
+ * Runtime: kernel version - don't show the dash if flavor is empty |
|
24 |
+ * Documentation: updated www.docker.io website. |
|
25 |
+ * Builder: use any whitespaces instead of tabs |
|
26 |
+ * Packaging: packaging ubuntu; issue #510: Use goland-stable PPA package to build docker |
|
27 |
+ |
|
3 | 28 |
## 0.3.0 (2013-05-06) |
4 | 29 |
+ Registry: Implement the new registry |
5 | 30 |
+ Documentation: new example: sharing data between 2 couchdb databases |
... | ... |
@@ -39,7 +39,7 @@ $(DOCKER_BIN): $(DOCKER_DIR) |
39 | 39 |
$(DOCKER_DIR): |
40 | 40 |
@mkdir -p $(dir $@) |
41 | 41 |
@if [ -h $@ ]; then rm -f $@; fi; ln -sf $(CURDIR)/ $@ |
42 |
- @(cd $(DOCKER_MAIN); go get $(GO_OPTIONS)) |
|
42 |
+ @(cd $(DOCKER_MAIN); go get -d $(GO_OPTIONS)) |
|
43 | 43 |
|
44 | 44 |
whichrelease: |
45 | 45 |
echo $(RELEASE_VERSION) |
... | ... |
@@ -22,7 +22,7 @@ import ( |
22 | 22 |
"unicode" |
23 | 23 |
) |
24 | 24 |
|
25 |
-const VERSION = "0.3.0" |
|
25 |
+const VERSION = "0.3.1" |
|
26 | 26 |
|
27 | 27 |
var ( |
28 | 28 |
GIT_COMMIT string |
... | ... |
@@ -362,7 +362,7 @@ func CmdInfo(args ...string) error { |
362 | 362 |
if err != nil { |
363 | 363 |
return err |
364 | 364 |
} |
365 |
- fmt.Printf("containers: %d\nversion: %s\nimages: %d\n", out.Containers, out.Version, out.Images) |
|
365 |
+ fmt.Printf("containers: %d\nversion: %s\nimages: %d\nGo version: %s\n", out.Containers, out.Version, out.Images, out.GoVersion) |
|
366 | 366 |
if out.Debug { |
367 | 367 |
fmt.Println("debug mode enabled") |
368 | 368 |
fmt.Printf("fds: %d\ngoroutines: %d\n", out.NFd, out.NGoroutines) |
... | ... |
@@ -9,14 +9,18 @@ import ( |
9 | 9 |
"path" |
10 | 10 |
"path/filepath" |
11 | 11 |
"strings" |
12 |
+ "sync" |
|
12 | 13 |
"time" |
13 | 14 |
) |
14 | 15 |
|
15 | 16 |
// A Graph is a store for versioned filesystem images and the relationship between them. |
16 | 17 |
type Graph struct { |
17 |
- Root string |
|
18 |
- idIndex *TruncIndex |
|
19 |
- httpClient *http.Client |
|
18 |
+ Root string |
|
19 |
+ idIndex *TruncIndex |
|
20 |
+ httpClient *http.Client |
|
21 |
+ checksumLock map[string]*sync.Mutex |
|
22 |
+ lockSumFile *sync.Mutex |
|
23 |
+ lockSumMap *sync.Mutex |
|
20 | 24 |
} |
21 | 25 |
|
22 | 26 |
// NewGraph instantiates a new graph at the given root path in the filesystem. |
... | ... |
@@ -27,12 +31,15 @@ func NewGraph(root string) (*Graph, error) { |
27 | 27 |
return nil, err |
28 | 28 |
} |
29 | 29 |
// Create the root directory if it doesn't exists |
30 |
- if err := os.Mkdir(root, 0700); err != nil && !os.IsExist(err) { |
|
30 |
+ if err := os.MkdirAll(root, 0700); err != nil && !os.IsExist(err) { |
|
31 | 31 |
return nil, err |
32 | 32 |
} |
33 | 33 |
graph := &Graph{ |
34 |
- Root: abspath, |
|
35 |
- idIndex: NewTruncIndex(), |
|
34 |
+ Root: abspath, |
|
35 |
+ idIndex: NewTruncIndex(), |
|
36 |
+ checksumLock: make(map[string]*sync.Mutex), |
|
37 |
+ lockSumFile: &sync.Mutex{}, |
|
38 |
+ lockSumMap: &sync.Mutex{}, |
|
36 | 39 |
} |
37 | 40 |
if err := graph.restore(); err != nil { |
38 | 41 |
return nil, err |
... | ... |
@@ -82,6 +89,11 @@ func (graph *Graph) Get(name string) (*Image, error) { |
82 | 82 |
return nil, fmt.Errorf("Image stored at '%s' has wrong id '%s'", id, img.Id) |
83 | 83 |
} |
84 | 84 |
img.graph = graph |
85 |
+ graph.lockSumMap.Lock() |
|
86 |
+ defer graph.lockSumMap.Unlock() |
|
87 |
+ if _, exists := graph.checksumLock[img.Id]; !exists { |
|
88 |
+ graph.checksumLock[img.Id] = &sync.Mutex{} |
|
89 |
+ } |
|
85 | 90 |
return img, nil |
86 | 91 |
} |
87 | 92 |
|
... | ... |
@@ -103,7 +115,7 @@ func (graph *Graph) Create(layerData Archive, container *Container, comment, aut |
103 | 103 |
if err := graph.Register(layerData, img); err != nil { |
104 | 104 |
return nil, err |
105 | 105 |
} |
106 |
- img.Checksum() |
|
106 |
+ go img.Checksum() |
|
107 | 107 |
return img, nil |
108 | 108 |
} |
109 | 109 |
|
... | ... |
@@ -131,6 +143,7 @@ func (graph *Graph) Register(layerData Archive, img *Image) error { |
131 | 131 |
} |
132 | 132 |
img.graph = graph |
133 | 133 |
graph.idIndex.Add(img.Id) |
134 |
+ graph.checksumLock[img.Id] = &sync.Mutex{} |
|
134 | 135 |
return nil |
135 | 136 |
} |
136 | 137 |
|
... | ... |
@@ -35,8 +35,9 @@ func LoadImage(root string) (*Image, error) { |
35 | 35 |
if err != nil { |
36 | 36 |
return nil, err |
37 | 37 |
} |
38 |
- var img Image |
|
39 |
- if err := json.Unmarshal(jsonData, &img); err != nil { |
|
38 |
+ img := &Image{} |
|
39 |
+ |
|
40 |
+ if err := json.Unmarshal(jsonData, img); err != nil { |
|
40 | 41 |
return nil, err |
41 | 42 |
} |
42 | 43 |
if err := ValidateId(img.Id); err != nil { |
... | ... |
@@ -52,8 +53,7 @@ func LoadImage(root string) (*Image, error) { |
52 | 52 |
} else if !stat.IsDir() { |
53 | 53 |
return nil, fmt.Errorf("Couldn't load image %s: %s is not a directory", img.Id, layerPath(root)) |
54 | 54 |
} |
55 |
- |
|
56 |
- return &img, nil |
|
55 |
+ return img, nil |
|
57 | 56 |
} |
58 | 57 |
|
59 | 58 |
func StoreImage(img *Image, layerData Archive, root string) error { |
... | ... |
@@ -261,19 +261,22 @@ func (img *Image) layer() (string, error) { |
261 | 261 |
} |
262 | 262 |
|
263 | 263 |
func (img *Image) Checksum() (string, error) { |
264 |
+ img.graph.checksumLock[img.Id].Lock() |
|
265 |
+ defer img.graph.checksumLock[img.Id].Unlock() |
|
266 |
+ |
|
264 | 267 |
root, err := img.root() |
265 | 268 |
if err != nil { |
266 | 269 |
return "", err |
267 | 270 |
} |
268 | 271 |
|
269 | 272 |
checksumDictPth := path.Join(root, "..", "..", "checksums") |
270 |
- checksums := new(map[string]string) |
|
273 |
+ checksums := make(map[string]string) |
|
271 | 274 |
|
272 | 275 |
if checksumDict, err := ioutil.ReadFile(checksumDictPth); err == nil { |
273 |
- if err := json.Unmarshal(checksumDict, checksums); err != nil { |
|
276 |
+ if err := json.Unmarshal(checksumDict, &checksums); err != nil { |
|
274 | 277 |
return "", err |
275 | 278 |
} |
276 |
- if checksum, ok := (*checksums)[img.Id]; ok { |
|
279 |
+ if checksum, ok := checksums[img.Id]; ok { |
|
277 | 280 |
return checksum, nil |
278 | 281 |
} |
279 | 282 |
} |
... | ... |
@@ -299,20 +302,26 @@ func (img *Image) Checksum() (string, error) { |
299 | 299 |
if _, err := h.Write([]byte("\n")); err != nil { |
300 | 300 |
return "", err |
301 | 301 |
} |
302 |
+ |
|
302 | 303 |
if _, err := io.Copy(h, layerData); err != nil { |
303 | 304 |
return "", err |
304 | 305 |
} |
305 | 306 |
|
306 | 307 |
hash := "sha256:" + hex.EncodeToString(h.Sum(nil)) |
307 |
- if *checksums == nil { |
|
308 |
- *checksums = map[string]string{} |
|
308 |
+ checksums[img.Id] = hash |
|
309 |
+ |
|
310 |
+ // Reload the json file to make sure not to overwrite faster sums |
|
311 |
+ img.graph.lockSumFile.Lock() |
|
312 |
+ defer img.graph.lockSumFile.Unlock() |
|
313 |
+ if checksumDict, err := ioutil.ReadFile(checksumDictPth); err == nil { |
|
314 |
+ if err := json.Unmarshal(checksumDict, &checksums); err != nil { |
|
315 |
+ return "", err |
|
316 |
+ } |
|
309 | 317 |
} |
310 |
- (*checksums)[img.Id] = hash |
|
311 | 318 |
checksumJson, err := json.Marshal(checksums) |
312 | 319 |
if err != nil { |
313 | 320 |
return hash, err |
314 | 321 |
} |
315 |
- |
|
316 | 322 |
if err := ioutil.WriteFile(checksumDictPth, checksumJson, 0600); err != nil { |
317 | 323 |
return hash, err |
318 | 324 |
} |
... | ... |
@@ -1,3 +1,30 @@ |
1 |
+lxc-docker (0.3.1-1) precise; urgency=low |
|
2 |
+ - Builder: Implement the autorun capability within docker builder |
|
3 |
+ - Builder: Add caching to docker builder |
|
4 |
+ - Builder: Add support for docker builder with native API as top level command |
|
5 |
+ - Runtime: Add go version to debug infos |
|
6 |
+ - Builder: Implement ENV within docker builder |
|
7 |
+ - Registry: Add docker search top level command in order to search a repository |
|
8 |
+ - Images: output graph of images to dot (graphviz) |
|
9 |
+ - Documentation: new introduction and high-level overview |
|
10 |
+ - Documentation: Add the documentation for docker builder |
|
11 |
+ - Website: new high-level overview |
|
12 |
+ - Makefile: Swap "go get" for "go get -d", especially to compile on go1.1rc |
|
13 |
+ - Images: fix ByParent function |
|
14 |
+ - Builder: Check the command existance prior create and add Unit tests for the case |
|
15 |
+ - Registry: Fix pull for official images with specific tag |
|
16 |
+ - Registry: Fix issue when login in with a different user and trying to push |
|
17 |
+ - Documentation: CSS fix for docker documentation to make REST API docs look better. |
|
18 |
+ - Documentation: Fixed CouchDB example page header mistake |
|
19 |
+ - Documentation: fixed README formatting |
|
20 |
+ - Registry: Improve checksum - async calculation |
|
21 |
+ - Runtime: kernel version - don't show the dash if flavor is empty |
|
22 |
+ - Documentation: updated www.docker.io website. |
|
23 |
+ - Builder: use any whitespaces instead of tabs |
|
24 |
+ - Packaging: packaging ubuntu; issue #510: Use goland-stable PPA package to build docker |
|
25 |
+ |
|
26 |
+ -- dotCloud <ops@dotcloud.com> Fri, 8 May 2013 00:00:00 -0700 |
|
27 |
+ |
|
1 | 28 |
lxc-docker (0.3.0-1) precise; urgency=low |
2 | 29 |
- Registry: Implement the new registry |
3 | 30 |
- Documentation: new example: sharing data between 2 couchdb databases |
... | ... |
@@ -194,18 +194,16 @@ func (graph *Graph) getRemoteTags(stdout io.Writer, registries []string, reposit |
194 | 194 |
return nil, fmt.Errorf("Repository not found") |
195 | 195 |
} |
196 | 196 |
|
197 |
- result := new(map[string]string) |
|
197 |
+ result := make(map[string]string) |
|
198 | 198 |
|
199 | 199 |
rawJson, err := ioutil.ReadAll(res.Body) |
200 | 200 |
if err != nil { |
201 | 201 |
return nil, err |
202 | 202 |
} |
203 |
- if err = json.Unmarshal(rawJson, result); err != nil { |
|
203 |
+ if err = json.Unmarshal(rawJson, &result); err != nil { |
|
204 | 204 |
return nil, err |
205 | 205 |
} |
206 |
- |
|
207 |
- return *result, nil |
|
208 |
- |
|
206 |
+ return result, nil |
|
209 | 207 |
} |
210 | 208 |
return nil, fmt.Errorf("Could not reach any registry endpoint") |
211 | 209 |
} |
... | ... |
@@ -308,6 +306,50 @@ func (graph *Graph) PullRepository(stdout io.Writer, remote, askedTag string, re |
308 | 308 |
return fmt.Errorf("Index response didn't contain any endpoints") |
309 | 309 |
} |
310 | 310 |
|
311 |
+ checksumsJson, err := ioutil.ReadAll(res.Body) |
|
312 |
+ if err != nil { |
|
313 |
+ return err |
|
314 |
+ } |
|
315 |
+ |
|
316 |
+ // Reload the json file to make sure not to overwrite faster sums |
|
317 |
+ err = func() error { |
|
318 |
+ localChecksums := make(map[string]string) |
|
319 |
+ remoteChecksums := []struct { |
|
320 |
+ Id string `json: "id"` |
|
321 |
+ Checksum string `json: "checksum"` |
|
322 |
+ }{} |
|
323 |
+ checksumDictPth := path.Join(graph.Root, "..", "checksums") |
|
324 |
+ |
|
325 |
+ if err := json.Unmarshal(checksumsJson, &remoteChecksums); err != nil { |
|
326 |
+ return err |
|
327 |
+ } |
|
328 |
+ |
|
329 |
+ graph.lockSumFile.Lock() |
|
330 |
+ defer graph.lockSumFile.Unlock() |
|
331 |
+ |
|
332 |
+ if checksumDict, err := ioutil.ReadFile(checksumDictPth); err == nil { |
|
333 |
+ if err := json.Unmarshal(checksumDict, &localChecksums); err != nil { |
|
334 |
+ return err |
|
335 |
+ } |
|
336 |
+ } |
|
337 |
+ |
|
338 |
+ for _, elem := range remoteChecksums { |
|
339 |
+ localChecksums[elem.Id] = elem.Checksum |
|
340 |
+ } |
|
341 |
+ |
|
342 |
+ checksumsJson, err = json.Marshal(localChecksums) |
|
343 |
+ if err != nil { |
|
344 |
+ return err |
|
345 |
+ } |
|
346 |
+ if err := ioutil.WriteFile(checksumDictPth, checksumsJson, 0600); err != nil { |
|
347 |
+ return err |
|
348 |
+ } |
|
349 |
+ return nil |
|
350 |
+ }() |
|
351 |
+ if err != nil { |
|
352 |
+ return err |
|
353 |
+ } |
|
354 |
+ |
|
311 | 355 |
var tagsList map[string]string |
312 | 356 |
if askedTag == "" { |
313 | 357 |
tagsList, err = graph.getRemoteTags(stdout, endpoints, remote, token) |
... | ... |
@@ -427,9 +469,15 @@ func pushImageRec(graph *Graph, stdout io.Writer, img *Image, registry string, t |
427 | 427 |
if err != nil { |
428 | 428 |
return fmt.Errorf("Failed to upload layer: %s", err) |
429 | 429 |
} |
430 |
- res3.Body.Close() |
|
430 |
+ defer res3.Body.Close() |
|
431 |
+ |
|
431 | 432 |
if res3.StatusCode != 200 { |
432 |
- return fmt.Errorf("Received HTTP code %d while uploading layer", res3.StatusCode) |
|
433 |
+ errBody, err := ioutil.ReadAll(res3.Body) |
|
434 |
+ if err != nil { |
|
435 |
+ return fmt.Errorf("HTTP code %d while uploading metadata and error when"+ |
|
436 |
+ " trying to parse response body: %v", res.StatusCode, err) |
|
437 |
+ } |
|
438 |
+ return fmt.Errorf("Received HTTP code %d while uploading layer: %s", res3.StatusCode, errBody) |
|
433 | 439 |
} |
434 | 440 |
return nil |
435 | 441 |
} |
... | ... |
@@ -612,8 +660,7 @@ func (graph *Graph) PushRepository(stdout io.Writer, remote string, localRepo Re |
612 | 612 |
} |
613 | 613 |
|
614 | 614 |
func (graph *Graph) Checksums(output io.Writer, repo Repository) ([]map[string]string, error) { |
615 |
- var result []map[string]string |
|
616 |
- checksums := map[string]string{} |
|
615 |
+ checksums := make(map[string]string) |
|
617 | 616 |
for _, id := range repo { |
618 | 617 |
img, err := graph.Get(id) |
619 | 618 |
if err != nil { |
... | ... |
@@ -634,7 +681,7 @@ func (graph *Graph) Checksums(output io.Writer, repo Repository) ([]map[string]s |
634 | 634 |
} |
635 | 635 |
} |
636 | 636 |
i := 0 |
637 |
- result = make([]map[string]string, len(checksums)) |
|
637 |
+ result := make([]map[string]string, len(checksums)) |
|
638 | 638 |
for id, sum := range checksums { |
639 | 639 |
result[i] = map[string]string{ |
640 | 640 |
"id": id, |
... | ... |
@@ -201,6 +201,7 @@ func (srv *Server) DockerInfo() ApiInfo { |
201 | 201 |
out.Containers = len(srv.runtime.List()) |
202 | 202 |
out.Version = VERSION |
203 | 203 |
out.Images = imgcount |
204 |
+ out.GoVersion = runtime.Version() |
|
204 | 205 |
if os.Getenv("DEBUG") != "" { |
205 | 206 |
out.Debug = true |
206 | 207 |
out.NFd = getTotalUsedFds() |