2015-05-11 13:23:32 -04:00
|
|
|
// +build linux windows
|
2014-11-24 18:28:20 -05:00
|
|
|
|
2014-08-05 01:19:23 -04:00
|
|
|
package graph
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
2015-04-20 21:26:15 -04:00
|
|
|
"io"
|
2014-08-05 01:19:23 -04:00
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
2015-05-04 18:14:39 -04:00
|
|
|
"path/filepath"
|
2014-08-05 01:19:23 -04:00
|
|
|
|
2015-03-26 18:22:04 -04:00
|
|
|
"github.com/Sirupsen/logrus"
|
2014-08-05 01:19:23 -04:00
|
|
|
"github.com/docker/docker/image"
|
2014-09-30 02:23:36 -04:00
|
|
|
"github.com/docker/docker/pkg/archive"
|
2014-11-08 10:38:42 -05:00
|
|
|
"github.com/docker/docker/pkg/chrootarchive"
|
2014-08-05 01:19:23 -04:00
|
|
|
)
|
|
|
|
|
2015-07-21 12:21:45 -04:00
|
|
|
// Load uploads a set of images into the repository. This is the complementary of ImageExport.
|
2014-08-05 01:19:23 -04:00
|
|
|
// The input stream is an uncompressed tar ball containing images and metadata.
|
2015-04-23 15:05:21 -04:00
|
|
|
func (s *TagStore) Load(inTar io.ReadCloser, outStream io.Writer) error {
|
2014-08-05 01:19:23 -04:00
|
|
|
tmpImageDir, err := ioutil.TempDir("", "docker-import-")
|
|
|
|
if err != nil {
|
2015-03-25 03:44:12 -04:00
|
|
|
return err
|
2014-08-05 01:19:23 -04:00
|
|
|
}
|
|
|
|
defer os.RemoveAll(tmpImageDir)
|
|
|
|
|
|
|
|
var (
|
2015-05-04 18:14:39 -04:00
|
|
|
repoDir = filepath.Join(tmpImageDir, "repo")
|
2014-08-05 01:19:23 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
if err := os.Mkdir(repoDir, os.ModeDir); err != nil {
|
2015-03-25 03:44:12 -04:00
|
|
|
return err
|
2014-08-05 01:19:23 -04:00
|
|
|
}
|
2015-06-19 11:01:39 -04:00
|
|
|
images := s.graph.Map()
|
2014-07-31 03:33:59 -04:00
|
|
|
excludes := make([]string, len(images))
|
|
|
|
i := 0
|
|
|
|
for k := range images {
|
|
|
|
excludes[i] = k
|
|
|
|
i++
|
|
|
|
}
|
2015-04-23 15:05:21 -04:00
|
|
|
if err := chrootarchive.Untar(inTar, repoDir, &archive.TarOptions{ExcludePatterns: excludes}); err != nil {
|
2015-03-25 03:44:12 -04:00
|
|
|
return err
|
2014-08-05 01:19:23 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
dirs, err := ioutil.ReadDir(repoDir)
|
|
|
|
if err != nil {
|
2015-03-25 03:44:12 -04:00
|
|
|
return err
|
2014-08-05 01:19:23 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, d := range dirs {
|
|
|
|
if d.IsDir() {
|
2015-04-23 15:05:21 -04:00
|
|
|
if err := s.recursiveLoad(d.Name(), tmpImageDir); err != nil {
|
2015-03-25 03:44:12 -04:00
|
|
|
return err
|
2014-08-05 01:19:23 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-04 18:14:39 -04:00
|
|
|
reposJSONFile, err := os.Open(filepath.Join(tmpImageDir, "repo", "repositories"))
|
2015-04-21 18:47:51 -04:00
|
|
|
if err != nil {
|
|
|
|
if !os.IsNotExist(err) {
|
2015-03-25 03:44:12 -04:00
|
|
|
return err
|
2014-08-05 01:19:23 -04:00
|
|
|
}
|
2015-04-21 18:47:51 -04:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
defer reposJSONFile.Close()
|
2014-08-05 01:19:23 -04:00
|
|
|
|
2015-04-21 18:47:51 -04:00
|
|
|
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 {
|
2015-07-29 19:45:47 -04:00
|
|
|
if err := s.setLoad(imageName, tag, address, true, outStream); err != nil {
|
2015-04-21 18:47:51 -04:00
|
|
|
return err
|
2014-08-05 01:19:23 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-25 03:44:12 -04:00
|
|
|
return nil
|
2014-08-05 01:19:23 -04:00
|
|
|
}
|
|
|
|
|
2015-04-23 15:05:21 -04:00
|
|
|
func (s *TagStore) recursiveLoad(address, tmpImageDir string) error {
|
2015-04-21 13:42:06 -04:00
|
|
|
if _, err := s.LookupImage(address); err != nil {
|
2015-03-26 18:22:04 -04:00
|
|
|
logrus.Debugf("Loading %s", address)
|
2014-08-05 01:19:23 -04:00
|
|
|
|
2015-07-21 12:21:45 -04:00
|
|
|
imageJSON, err := ioutil.ReadFile(filepath.Join(tmpImageDir, "repo", address, "json"))
|
2014-08-05 01:19:23 -04:00
|
|
|
if err != nil {
|
2015-07-15 15:25:50 -04:00
|
|
|
logrus.Debugf("Error reading json: %v", err)
|
2014-08-05 01:19:23 -04:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2015-05-04 18:14:39 -04:00
|
|
|
layer, err := os.Open(filepath.Join(tmpImageDir, "repo", address, "layer.tar"))
|
2014-08-05 01:19:23 -04:00
|
|
|
if err != nil {
|
2015-07-15 15:25:50 -04:00
|
|
|
logrus.Debugf("Error reading embedded tar: %v", err)
|
2014-08-05 01:19:23 -04:00
|
|
|
return err
|
|
|
|
}
|
2015-07-21 12:21:45 -04:00
|
|
|
img, err := image.NewImgJSON(imageJSON)
|
2014-08-05 01:19:23 -04:00
|
|
|
if err != nil {
|
2015-07-15 15:25:50 -04:00
|
|
|
logrus.Debugf("Error unmarshalling json: %v", err)
|
2014-08-05 01:19:23 -04:00
|
|
|
return err
|
|
|
|
}
|
2015-03-29 17:17:23 -04:00
|
|
|
if err := image.ValidateID(img.ID); err != nil {
|
2015-07-15 15:25:50 -04:00
|
|
|
logrus.Debugf("Error validating ID: %v", err)
|
2014-11-27 16:55:03 -05:00
|
|
|
return err
|
|
|
|
}
|
2015-02-18 21:45:39 -05:00
|
|
|
|
|
|
|
// ensure no two downloads of the same layer happen at the same time
|
2015-08-25 17:23:52 -04:00
|
|
|
poolKey := "layer:" + img.ID
|
|
|
|
broadcaster, found := s.poolAdd("pull", poolKey)
|
|
|
|
if found {
|
2015-08-11 12:44:50 -04:00
|
|
|
logrus.Debugf("Image (id: %s) load is already running, waiting", img.ID)
|
2015-08-25 17:23:52 -04:00
|
|
|
return broadcaster.Wait()
|
2015-02-18 21:45:39 -05:00
|
|
|
}
|
|
|
|
|
2015-08-25 17:23:52 -04:00
|
|
|
defer s.poolRemove("pull", poolKey)
|
2015-02-18 21:45:39 -05:00
|
|
|
|
2014-08-05 01:19:23 -04:00
|
|
|
if img.Parent != "" {
|
|
|
|
if !s.graph.Exists(img.Parent) {
|
2015-04-23 15:05:21 -04:00
|
|
|
if err := s.recursiveLoad(img.Parent, tmpImageDir); err != nil {
|
2014-08-05 01:19:23 -04:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-10-27 14:00:29 -04:00
|
|
|
if err := s.graph.Register(img, layer); err != nil {
|
2014-08-05 01:19:23 -04:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
2015-03-26 18:22:04 -04:00
|
|
|
logrus.Debugf("Completed processing %s", address)
|
2014-08-05 01:19:23 -04:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|