aed8f9f7 |
// +build linux windows |
2ec22379 |
|
f2029f7b |
package graph
import (
"encoding/json" |
70bb0d8e |
"io" |
f2029f7b |
"io/ioutil"
"os" |
bb1ecde1 |
"path/filepath" |
f2029f7b |
|
6f4d8470 |
"github.com/Sirupsen/logrus" |
f2029f7b |
"github.com/docker/docker/image" |
30d5a42c |
"github.com/docker/docker/pkg/archive" |
9c01bc24 |
"github.com/docker/docker/pkg/chrootarchive" |
f2029f7b |
)
|
1d6e4431 |
// Load uploads a set of images into the repository. This is the complementary of ImageExport. |
f2029f7b |
// The input stream is an uncompressed tar ball containing images and metadata. |
fa2c68a8 |
func (s *TagStore) Load(inTar io.ReadCloser, outStream io.Writer) error { |
f2029f7b |
tmpImageDir, err := ioutil.TempDir("", "docker-import-")
if err != nil { |
c79b9bab |
return err |
f2029f7b |
}
defer os.RemoveAll(tmpImageDir)
var ( |
bb1ecde1 |
repoDir = filepath.Join(tmpImageDir, "repo") |
f2029f7b |
)
if err := os.Mkdir(repoDir, os.ModeDir); err != nil { |
c79b9bab |
return err |
f2029f7b |
} |
cc955ae7 |
images := s.graph.Map() |
a34dd216 |
excludes := make([]string, len(images))
i := 0
for k := range images {
excludes[i] = k
i++
} |
fa2c68a8 |
if err := chrootarchive.Untar(inTar, repoDir, &archive.TarOptions{ExcludePatterns: excludes}); err != nil { |
c79b9bab |
return err |
f2029f7b |
}
dirs, err := ioutil.ReadDir(repoDir)
if err != nil { |
c79b9bab |
return err |
f2029f7b |
}
for _, d := range dirs {
if d.IsDir() { |
fa2c68a8 |
if err := s.recursiveLoad(d.Name(), tmpImageDir); err != nil { |
c79b9bab |
return err |
f2029f7b |
}
}
}
|
bb1ecde1 |
reposJSONFile, err := os.Open(filepath.Join(tmpImageDir, "repo", "repositories")) |
26543e03 |
if err != nil {
if !os.IsNotExist(err) { |
c79b9bab |
return err |
f2029f7b |
} |
26543e03 |
return nil
}
defer reposJSONFile.Close() |
f2029f7b |
|
26543e03 |
repositories := map[string]Repository{}
if err := json.NewDecoder(reposJSONFile).Decode(&repositories); err != nil {
return err
}
for imageName, tagMap := range repositories {
for tag, address := range tagMap { |
d4836cd7 |
if err := s.setLoad(imageName, tag, address, true, outStream); err != nil { |
26543e03 |
return err |
f2029f7b |
}
}
}
|
c79b9bab |
return nil |
f2029f7b |
}
|
fa2c68a8 |
func (s *TagStore) recursiveLoad(address, tmpImageDir string) error { |
d07fe183 |
if _, err := s.LookupImage(address); err != nil { |
6f4d8470 |
logrus.Debugf("Loading %s", address) |
f2029f7b |
|
1d6e4431 |
imageJSON, err := ioutil.ReadFile(filepath.Join(tmpImageDir, "repo", address, "json")) |
f2029f7b |
if err != nil { |
a5142f6a |
logrus.Debugf("Error reading json: %v", err) |
f2029f7b |
return err
}
|
bb1ecde1 |
layer, err := os.Open(filepath.Join(tmpImageDir, "repo", address, "layer.tar")) |
f2029f7b |
if err != nil { |
a5142f6a |
logrus.Debugf("Error reading embedded tar: %v", err) |
f2029f7b |
return err
} |
1d6e4431 |
img, err := image.NewImgJSON(imageJSON) |
f2029f7b |
if err != nil { |
a5142f6a |
logrus.Debugf("Error unmarshalling json: %v", err) |
f2029f7b |
return err
} |
c30a55f1 |
if err := image.ValidateID(img.ID); err != nil { |
a5142f6a |
logrus.Debugf("Error validating ID: %v", err) |
bff1d9db |
return err
} |
de35ef2e |
// ensure no two downloads of the same layer happen at the same time |
23e68679 |
poolKey := "layer:" + img.ID
broadcaster, found := s.poolAdd("pull", poolKey)
if found { |
80513d85 |
logrus.Debugf("Image (id: %s) load is already running, waiting", img.ID) |
23e68679 |
return broadcaster.Wait() |
de35ef2e |
}
|
23e68679 |
defer s.poolRemove("pull", poolKey) |
de35ef2e |
|
f2029f7b |
if img.Parent != "" {
if !s.graph.Exists(img.Parent) { |
fa2c68a8 |
if err := s.recursiveLoad(img.Parent, tmpImageDir); err != nil { |
f2029f7b |
return err
}
}
} |
504e67b8 |
if err := s.graph.Register(v1Descriptor{img}, layer); err != nil { |
f2029f7b |
return err
}
} |
6f4d8470 |
logrus.Debugf("Completed processing %s", address) |
f2029f7b |
return nil
} |