diff --git a/commands.go b/commands.go index 241923cef7..06443b559e 100644 --- a/commands.go +++ b/commands.go @@ -529,9 +529,6 @@ func (srv *Server) CmdPush(stdin io.ReadCloser, stdout rcli.DockerConn, args ... Debugf("Pushing [%s] to [%s]\n", local, remote) // Try to get the image - // FIXME: Handle lookup - // FIXME: Also push the tags in case of ./docker push myrepo:mytag - // img, err := srv.runtime.LookupImage(cmd.Arg(0)) img, err := srv.runtime.graph.Get(local) if err != nil { Debugf("The push refers to a repository [%s] (len: %d)\n", local, len(srv.runtime.repositories.Repositories[local])) diff --git a/graph.go b/graph.go index d7a53be7c3..6e443f206b 100644 --- a/graph.go +++ b/graph.go @@ -81,13 +81,6 @@ func (graph *Graph) Get(name string) (*Image, error) { return nil, fmt.Errorf("Image stored at '%s' has wrong id '%s'", id, img.Id) } img.graph = graph - - if img.Checksum == "" { - err := img.FixChecksum() - if err != nil { - return nil, err - } - } return img, nil } @@ -105,17 +98,11 @@ func (graph *Graph) Create(layerData Archive, container *Container, comment, aut img.Parent = container.Image img.Container = container.Id img.ContainerConfig = *container.Config - // FIXME: If an image is imported from a raw URL (not created from a container), - // its checksum will not be computed, which will cause a push to fail - checksum, err := container.RwChecksum() - if err != nil { - return nil, err - } - img.Checksum = checksum } if err := graph.Register(layerData, img); err != nil { return nil, err } + img.Checksum() return img, nil } @@ -309,7 +296,10 @@ func (graph *Graph) Checksums(repo Repository) ([]map[string]string, error) { return nil, err } err = img.WalkHistory(func(image *Image) error { - checksums[image.Id] = image.Checksum + checksums[image.Id], err = image.Checksum() + if err != nil { + return err + } return nil }) if err != nil { diff --git a/image.go b/image.go index 4d625d6c0f..dcad130d3b 100644 --- a/image.go +++ b/image.go @@ -1,7 +1,9 @@ package docker import ( + "bytes" "crypto/rand" + "crypto/sha256" "encoding/hex" "encoding/json" "fmt" @@ -18,7 +20,6 @@ import ( type Image struct { Id string `json:"id"` Parent string `json:"parent,omitempty"` - Checksum string `json:"checksum,omitempty"` Comment string `json:"comment,omitempty"` Created time.Time `json:"created"` Container string `json:"container,omitempty"` @@ -260,30 +261,57 @@ func (img *Image) layer() (string, error) { return layerPath(root), nil } -func (img *Image) FixChecksum() error { +func (img *Image) Checksum() (string, error) { + root, err := img.root() + if err != nil { + return "", err + } + + checksumDictPth := path.Join(root, "..", "..", "checksums") + checksums := new(map[string]string) + + if checksumDict, err := ioutil.ReadFile(checksumDictPth); err == nil { + if err := json.Unmarshal(checksumDict, checksums); err != nil { + return "", err + } + if checksum, ok := (*checksums)[img.Id]; ok { + return checksum, nil + } + } + layer, err := img.layer() if err != nil { - return err + return "", err } layerData, err := Tar(layer, Xz) if err != nil { - return err + return "", err } - sum, err := HashData(layerData) + h := sha256.New() + if _, err := io.Copy(h, layerData); err != nil { + return "", err + } + + jsonData, err := ioutil.ReadFile(jsonPath(root)) if err != nil { - return err + return "", err } - img.Checksum = sum - jsonData, err := json.Marshal(img) + if _, err := io.Copy(h, bytes.NewBuffer(jsonData)); err != nil { + return "", err + } + + hash := "sha256:"+hex.EncodeToString(h.Sum(nil)) + if *checksums == nil { + *checksums = map[string]string{} + } + (*checksums)[img.Id] = hash + checksumJson, err := json.Marshal(checksums) if err != nil { - return err + return hash, err } - root, err := img.root() - if err != nil { - return err + + if err := ioutil.WriteFile(checksumDictPth, checksumJson, 0600); err != nil { + return hash, err } - if err := ioutil.WriteFile(jsonPath(root), jsonData, 0600); err != nil { - return err - } - return nil + return hash, nil } diff --git a/registry.go b/registry.go index 5da811b123..be9d37edc1 100644 --- a/registry.go +++ b/registry.go @@ -327,6 +327,12 @@ func pushImageRec(graph *Graph, stdout io.Writer, img *Image, registry string, t } req.Header.Add("Content-type", "application/json") req.Header.Set("Authorization", "Token " + strings.Join(token, ",")) + + checksum, err := img.Checksum() + if err != nil { + return fmt.Errorf("Error while retrieving checksum for %s: %v", img.Id, err) + } + req.Header.Set("X-Docker-Checksum", checksum) res, err := doWithCookies(client, req) if err != nil { return fmt.Errorf("Failed to upload metadata: %s", err) @@ -457,7 +463,7 @@ func (graph *Graph) PushRepository(stdout io.Writer, remote string, localRepo Re return err } - req, err := http.NewRequest("PUT", INDEX_ENDPOINT+"/repositories/"+remote, bytes.NewReader(imgListJson)) + req, err := http.NewRequest("PUT", INDEX_ENDPOINT+"/repositories/"+remote+"/", bytes.NewReader(imgListJson)) if err != nil { return err } @@ -468,7 +474,7 @@ func (graph *Graph) PushRepository(stdout io.Writer, remote string, localRepo Re if err != nil { return err } - res.Body.Close() + defer res.Body.Close() for res.StatusCode >= 300 && res.StatusCode < 400 { Debugf("Redirected to %s\n", res.Header.Get("Location")) req, err = http.NewRequest("PUT", res.Header.Get("Location"), bytes.NewReader(imgListJson)) @@ -482,10 +488,12 @@ func (graph *Graph) PushRepository(stdout io.Writer, remote string, localRepo Re if err != nil { return err } - res.Body.Close() + defer res.Body.Close() } if res.StatusCode != 200 && res.StatusCode != 201 { + info, err := ioutil.ReadAll(res.Body) + Debugf("%v %v", err, string(info)) return fmt.Errorf("Error: Status %d trying to push repository %s", res.StatusCode, remote) }