graph/load.go
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
 }