github.com/alexandrev/docker@v1.9.0/graph/load.go (about)

     1  // +build linux windows
     2  
     3  package graph
     4  
     5  import (
     6  	"encoding/json"
     7  	"io"
     8  	"io/ioutil"
     9  	"os"
    10  	"path/filepath"
    11  
    12  	"github.com/Sirupsen/logrus"
    13  	"github.com/docker/docker/image"
    14  	"github.com/docker/docker/pkg/archive"
    15  	"github.com/docker/docker/pkg/chrootarchive"
    16  )
    17  
    18  // Load uploads a set of images into the repository. This is the complementary of ImageExport.
    19  // The input stream is an uncompressed tar ball containing images and metadata.
    20  func (s *TagStore) Load(inTar io.ReadCloser, outStream io.Writer) error {
    21  	tmpImageDir, err := ioutil.TempDir("", "docker-import-")
    22  	if err != nil {
    23  		return err
    24  	}
    25  	defer os.RemoveAll(tmpImageDir)
    26  
    27  	var (
    28  		repoDir = filepath.Join(tmpImageDir, "repo")
    29  	)
    30  
    31  	if err := os.Mkdir(repoDir, os.ModeDir); err != nil {
    32  		return err
    33  	}
    34  	images := s.graph.Map()
    35  	excludes := make([]string, len(images))
    36  	i := 0
    37  	for k := range images {
    38  		excludes[i] = k
    39  		i++
    40  	}
    41  	if err := chrootarchive.Untar(inTar, repoDir, &archive.TarOptions{ExcludePatterns: excludes}); err != nil {
    42  		return err
    43  	}
    44  
    45  	dirs, err := ioutil.ReadDir(repoDir)
    46  	if err != nil {
    47  		return err
    48  	}
    49  
    50  	for _, d := range dirs {
    51  		if d.IsDir() {
    52  			if err := s.recursiveLoad(d.Name(), tmpImageDir); err != nil {
    53  				return err
    54  			}
    55  		}
    56  	}
    57  
    58  	reposJSONFile, err := os.Open(filepath.Join(tmpImageDir, "repo", "repositories"))
    59  	if err != nil {
    60  		if !os.IsNotExist(err) {
    61  			return err
    62  		}
    63  		return nil
    64  	}
    65  	defer reposJSONFile.Close()
    66  
    67  	repositories := map[string]Repository{}
    68  	if err := json.NewDecoder(reposJSONFile).Decode(&repositories); err != nil {
    69  		return err
    70  	}
    71  
    72  	for imageName, tagMap := range repositories {
    73  		for tag, address := range tagMap {
    74  			if err := s.setLoad(imageName, tag, address, true, outStream); err != nil {
    75  				return err
    76  			}
    77  		}
    78  	}
    79  
    80  	return nil
    81  }
    82  
    83  func (s *TagStore) recursiveLoad(address, tmpImageDir string) error {
    84  	if _, err := s.LookupImage(address); err != nil {
    85  		logrus.Debugf("Loading %s", address)
    86  
    87  		imageJSON, err := ioutil.ReadFile(filepath.Join(tmpImageDir, "repo", address, "json"))
    88  		if err != nil {
    89  			logrus.Debugf("Error reading json: %v", err)
    90  			return err
    91  		}
    92  
    93  		layer, err := os.Open(filepath.Join(tmpImageDir, "repo", address, "layer.tar"))
    94  		if err != nil {
    95  			logrus.Debugf("Error reading embedded tar: %v", err)
    96  			return err
    97  		}
    98  		img, err := image.NewImgJSON(imageJSON)
    99  		if err != nil {
   100  			logrus.Debugf("Error unmarshalling json: %v", err)
   101  			return err
   102  		}
   103  		if err := image.ValidateID(img.ID); err != nil {
   104  			logrus.Debugf("Error validating ID: %v", err)
   105  			return err
   106  		}
   107  
   108  		// ensure no two downloads of the same layer happen at the same time
   109  		poolKey := "layer:" + img.ID
   110  		broadcaster, found := s.poolAdd("pull", poolKey)
   111  		if found {
   112  			logrus.Debugf("Image (id: %s) load is already running, waiting", img.ID)
   113  			return broadcaster.Wait()
   114  		}
   115  
   116  		defer s.poolRemove("pull", poolKey)
   117  
   118  		if img.Parent != "" {
   119  			if !s.graph.Exists(img.Parent) {
   120  				if err := s.recursiveLoad(img.Parent, tmpImageDir); err != nil {
   121  					return err
   122  				}
   123  			}
   124  		}
   125  		if err := s.graph.Register(v1Descriptor{img}, layer); err != nil {
   126  			return err
   127  		}
   128  	}
   129  	logrus.Debugf("Completed processing %s", address)
   130  
   131  	return nil
   132  }