github.com/chenchun/docker@v1.3.2-0.20150629222414-20467faf132b/graph/graph.go (about)

     1  package graph
     2  
     3  import (
     4  	"compress/gzip"
     5  	"crypto/sha256"
     6  	"encoding/json"
     7  	"errors"
     8  	"fmt"
     9  	"io"
    10  	"io/ioutil"
    11  	"os"
    12  	"path/filepath"
    13  	"runtime"
    14  	"strconv"
    15  	"strings"
    16  	"time"
    17  
    18  	"github.com/Sirupsen/logrus"
    19  	"github.com/docker/distribution/digest"
    20  	"github.com/docker/docker/autogen/dockerversion"
    21  	"github.com/docker/docker/daemon/graphdriver"
    22  	"github.com/docker/docker/image"
    23  	"github.com/docker/docker/pkg/archive"
    24  	"github.com/docker/docker/pkg/progressreader"
    25  	"github.com/docker/docker/pkg/streamformatter"
    26  	"github.com/docker/docker/pkg/stringid"
    27  	"github.com/docker/docker/pkg/system"
    28  	"github.com/docker/docker/pkg/truncindex"
    29  	"github.com/docker/docker/runconfig"
    30  )
    31  
    32  // A Graph is a store for versioned filesystem images and the relationship between them.
    33  type Graph struct {
    34  	root       string
    35  	idIndex    *truncindex.TruncIndex
    36  	driver     graphdriver.Driver
    37  	imageMutex imageMutex // protect images in driver.
    38  }
    39  
    40  var (
    41  	// ErrDigestNotSet is used when request the digest for a layer
    42  	// but the layer has no digest value or content to compute the
    43  	// the digest.
    44  	ErrDigestNotSet = errors.New("digest is not set for layer")
    45  )
    46  
    47  // NewGraph instantiates a new graph at the given root path in the filesystem.
    48  // `root` will be created if it doesn't exist.
    49  func NewGraph(root string, driver graphdriver.Driver) (*Graph, error) {
    50  	abspath, err := filepath.Abs(root)
    51  	if err != nil {
    52  		return nil, err
    53  	}
    54  	// Create the root directory if it doesn't exists
    55  	if err := system.MkdirAll(root, 0700); err != nil && !os.IsExist(err) {
    56  		return nil, err
    57  	}
    58  
    59  	graph := &Graph{
    60  		root:    abspath,
    61  		idIndex: truncindex.NewTruncIndex([]string{}),
    62  		driver:  driver,
    63  	}
    64  	if err := graph.restore(); err != nil {
    65  		return nil, err
    66  	}
    67  	return graph, nil
    68  }
    69  
    70  func (graph *Graph) restore() error {
    71  	dir, err := ioutil.ReadDir(graph.root)
    72  	if err != nil {
    73  		return err
    74  	}
    75  	var ids = []string{}
    76  	for _, v := range dir {
    77  		id := v.Name()
    78  		if graph.driver.Exists(id) {
    79  			ids = append(ids, id)
    80  		}
    81  	}
    82  	graph.idIndex = truncindex.NewTruncIndex(ids)
    83  	logrus.Debugf("Restored %d elements", len(ids))
    84  	return nil
    85  }
    86  
    87  // FIXME: Implement error subclass instead of looking at the error text
    88  // Note: This is the way golang implements os.IsNotExists on Plan9
    89  func (graph *Graph) IsNotExist(err error, id string) bool {
    90  	return err != nil && (strings.Contains(strings.ToLower(err.Error()), "does not exist") || strings.Contains(strings.ToLower(err.Error()), "no such")) && strings.Contains(err.Error(), id)
    91  }
    92  
    93  // Exists returns true if an image is registered at the given id.
    94  // If the image doesn't exist or if an error is encountered, false is returned.
    95  func (graph *Graph) Exists(id string) bool {
    96  	if _, err := graph.Get(id); err != nil {
    97  		return false
    98  	}
    99  	return true
   100  }
   101  
   102  // Get returns the image with the given id, or an error if the image doesn't exist.
   103  func (graph *Graph) Get(name string) (*image.Image, error) {
   104  	id, err := graph.idIndex.Get(name)
   105  	if err != nil {
   106  		return nil, fmt.Errorf("could not find image: %v", err)
   107  	}
   108  	img, err := graph.loadImage(id)
   109  	if err != nil {
   110  		return nil, err
   111  	}
   112  	if img.ID != id {
   113  		return nil, fmt.Errorf("Image stored at '%s' has wrong id '%s'", id, img.ID)
   114  	}
   115  
   116  	if img.Size < 0 {
   117  		size, err := graph.driver.DiffSize(img.ID, img.Parent)
   118  		if err != nil {
   119  			return nil, fmt.Errorf("unable to calculate size of image id %q: %s", img.ID, err)
   120  		}
   121  
   122  		img.Size = size
   123  		if err := graph.saveSize(graph.imageRoot(id), int(img.Size)); err != nil {
   124  			return nil, err
   125  		}
   126  	}
   127  	return img, nil
   128  }
   129  
   130  // Create creates a new image and registers it in the graph.
   131  func (graph *Graph) Create(layerData archive.ArchiveReader, containerID, containerImage, comment, author string, containerConfig, config *runconfig.Config) (*image.Image, error) {
   132  	img := &image.Image{
   133  		ID:            stringid.GenerateRandomID(),
   134  		Comment:       comment,
   135  		Created:       time.Now().UTC(),
   136  		DockerVersion: dockerversion.VERSION,
   137  		Author:        author,
   138  		Config:        config,
   139  		Architecture:  runtime.GOARCH,
   140  		OS:            runtime.GOOS,
   141  	}
   142  
   143  	if containerID != "" {
   144  		img.Parent = containerImage
   145  		img.Container = containerID
   146  		img.ContainerConfig = *containerConfig
   147  	}
   148  
   149  	if err := graph.Register(img, layerData); err != nil {
   150  		return nil, err
   151  	}
   152  	return img, nil
   153  }
   154  
   155  // Register imports a pre-existing image into the graph.
   156  func (graph *Graph) Register(img *image.Image, layerData archive.ArchiveReader) (err error) {
   157  	if err := image.ValidateID(img.ID); err != nil {
   158  		return err
   159  	}
   160  
   161  	// We need this entire operation to be atomic within the engine. Note that
   162  	// this doesn't mean Register is fully safe yet.
   163  	graph.imageMutex.Lock(img.ID)
   164  	defer graph.imageMutex.Unlock(img.ID)
   165  
   166  	defer func() {
   167  		// If any error occurs, remove the new dir from the driver.
   168  		// Don't check for errors since the dir might not have been created.
   169  		// FIXME: this leaves a possible race condition.
   170  		if err != nil {
   171  			graph.driver.Remove(img.ID)
   172  		}
   173  	}()
   174  
   175  	// (This is a convenience to save time. Race conditions are taken care of by os.Rename)
   176  	if graph.Exists(img.ID) {
   177  		return fmt.Errorf("Image %s already exists", img.ID)
   178  	}
   179  
   180  	// Ensure that the image root does not exist on the filesystem
   181  	// when it is not registered in the graph.
   182  	// This is common when you switch from one graph driver to another
   183  	if err := os.RemoveAll(graph.imageRoot(img.ID)); err != nil && !os.IsNotExist(err) {
   184  		return err
   185  	}
   186  
   187  	// If the driver has this ID but the graph doesn't, remove it from the driver to start fresh.
   188  	// (the graph is the source of truth).
   189  	// Ignore errors, since we don't know if the driver correctly returns ErrNotExist.
   190  	// (FIXME: make that mandatory for drivers).
   191  	graph.driver.Remove(img.ID)
   192  
   193  	tmp, err := graph.mktemp("")
   194  	defer os.RemoveAll(tmp)
   195  	if err != nil {
   196  		return fmt.Errorf("mktemp failed: %s", err)
   197  	}
   198  
   199  	// Create root filesystem in the driver
   200  	if err := graph.driver.Create(img.ID, img.Parent); err != nil {
   201  		return fmt.Errorf("Driver %s failed to create image rootfs %s: %s", graph.driver, img.ID, err)
   202  	}
   203  	// Apply the diff/layer
   204  	if err := graph.storeImage(img, layerData, tmp); err != nil {
   205  		return err
   206  	}
   207  	// Commit
   208  	if err := os.Rename(tmp, graph.imageRoot(img.ID)); err != nil {
   209  		return err
   210  	}
   211  	graph.idIndex.Add(img.ID)
   212  	return nil
   213  }
   214  
   215  // TempLayerArchive creates a temporary archive of the given image's filesystem layer.
   216  //   The archive is stored on disk and will be automatically deleted as soon as has been read.
   217  //   If output is not nil, a human-readable progress bar will be written to it.
   218  func (graph *Graph) TempLayerArchive(id string, sf *streamformatter.StreamFormatter, output io.Writer) (*archive.TempArchive, error) {
   219  	image, err := graph.Get(id)
   220  	if err != nil {
   221  		return nil, err
   222  	}
   223  	tmp, err := graph.mktemp("")
   224  	if err != nil {
   225  		return nil, err
   226  	}
   227  	a, err := graph.TarLayer(image)
   228  	if err != nil {
   229  		return nil, err
   230  	}
   231  	progressReader := progressreader.New(progressreader.Config{
   232  		In:        a,
   233  		Out:       output,
   234  		Formatter: sf,
   235  		Size:      0,
   236  		NewLines:  false,
   237  		ID:        stringid.TruncateID(id),
   238  		Action:    "Buffering to disk",
   239  	})
   240  	defer progressReader.Close()
   241  	return archive.NewTempArchive(progressReader, tmp)
   242  }
   243  
   244  // mktemp creates a temporary sub-directory inside the graph's filesystem.
   245  func (graph *Graph) mktemp(id string) (string, error) {
   246  	dir := filepath.Join(graph.root, "_tmp", stringid.GenerateRandomID())
   247  	if err := system.MkdirAll(dir, 0700); err != nil {
   248  		return "", err
   249  	}
   250  	return dir, nil
   251  }
   252  
   253  func (graph *Graph) newTempFile() (*os.File, error) {
   254  	tmp, err := graph.mktemp("")
   255  	if err != nil {
   256  		return nil, err
   257  	}
   258  	return ioutil.TempFile(tmp, "")
   259  }
   260  
   261  func bufferToFile(f *os.File, src io.Reader) (int64, digest.Digest, error) {
   262  	var (
   263  		h = sha256.New()
   264  		w = gzip.NewWriter(io.MultiWriter(f, h))
   265  	)
   266  	_, err := io.Copy(w, src)
   267  	w.Close()
   268  	if err != nil {
   269  		return 0, "", err
   270  	}
   271  	n, err := f.Seek(0, os.SEEK_CUR)
   272  	if err != nil {
   273  		return 0, "", err
   274  	}
   275  	if _, err := f.Seek(0, 0); err != nil {
   276  		return 0, "", err
   277  	}
   278  	return n, digest.NewDigest("sha256", h), nil
   279  }
   280  
   281  // Delete atomically removes an image from the graph.
   282  func (graph *Graph) Delete(name string) error {
   283  	id, err := graph.idIndex.Get(name)
   284  	if err != nil {
   285  		return err
   286  	}
   287  	tmp, err := graph.mktemp("")
   288  	graph.idIndex.Delete(id)
   289  	if err == nil {
   290  		if err := os.Rename(graph.imageRoot(id), tmp); err != nil {
   291  			// On err make tmp point to old dir and cleanup unused tmp dir
   292  			os.RemoveAll(tmp)
   293  			tmp = graph.imageRoot(id)
   294  		}
   295  	} else {
   296  		// On err make tmp point to old dir for cleanup
   297  		tmp = graph.imageRoot(id)
   298  	}
   299  	// Remove rootfs data from the driver
   300  	graph.driver.Remove(id)
   301  	// Remove the trashed image directory
   302  	return os.RemoveAll(tmp)
   303  }
   304  
   305  // Map returns a list of all images in the graph, addressable by ID.
   306  func (graph *Graph) Map() (map[string]*image.Image, error) {
   307  	images := make(map[string]*image.Image)
   308  	err := graph.walkAll(func(image *image.Image) {
   309  		images[image.ID] = image
   310  	})
   311  	if err != nil {
   312  		return nil, err
   313  	}
   314  	return images, nil
   315  }
   316  
   317  // walkAll iterates over each image in the graph, and passes it to a handler.
   318  // The walking order is undetermined.
   319  func (graph *Graph) walkAll(handler func(*image.Image)) error {
   320  	files, err := ioutil.ReadDir(graph.root)
   321  	if err != nil {
   322  		return err
   323  	}
   324  	for _, st := range files {
   325  		if img, err := graph.Get(st.Name()); err != nil {
   326  			// Skip image
   327  			continue
   328  		} else if handler != nil {
   329  			handler(img)
   330  		}
   331  	}
   332  	return nil
   333  }
   334  
   335  // ByParent returns a lookup table of images by their parent.
   336  // If an image of id ID has 3 children images, then the value for key ID
   337  // will be a list of 3 images.
   338  // If an image has no children, it will not have an entry in the table.
   339  func (graph *Graph) ByParent() (map[string][]*image.Image, error) {
   340  	byParent := make(map[string][]*image.Image)
   341  	err := graph.walkAll(func(img *image.Image) {
   342  		parent, err := graph.Get(img.Parent)
   343  		if err != nil {
   344  			return
   345  		}
   346  		if children, exists := byParent[parent.ID]; exists {
   347  			byParent[parent.ID] = append(children, img)
   348  		} else {
   349  			byParent[parent.ID] = []*image.Image{img}
   350  		}
   351  	})
   352  	return byParent, err
   353  }
   354  
   355  // Heads returns all heads in the graph, keyed by id.
   356  // A head is an image which is not the parent of another image in the graph.
   357  func (graph *Graph) Heads() (map[string]*image.Image, error) {
   358  	heads := make(map[string]*image.Image)
   359  	byParent, err := graph.ByParent()
   360  	if err != nil {
   361  		return nil, err
   362  	}
   363  	err = graph.walkAll(func(image *image.Image) {
   364  		// If it's not in the byParent lookup table, then
   365  		// it's not a parent -> so it's a head!
   366  		if _, exists := byParent[image.ID]; !exists {
   367  			heads[image.ID] = image
   368  		}
   369  	})
   370  	return heads, err
   371  }
   372  
   373  func (graph *Graph) imageRoot(id string) string {
   374  	return filepath.Join(graph.root, id)
   375  }
   376  
   377  // storeImage stores file system layer data for the given image to the
   378  // graph's storage driver. Image metadata is stored in a file
   379  // at the specified root directory.
   380  func (graph *Graph) storeImage(img *image.Image, layerData archive.ArchiveReader, root string) (err error) {
   381  	// Store the layer. If layerData is not nil, unpack it into the new layer
   382  	if layerData != nil {
   383  		if img.Size, err = graph.driver.ApplyDiff(img.ID, img.Parent, layerData); err != nil {
   384  			return err
   385  		}
   386  	}
   387  
   388  	if err := graph.saveSize(root, int(img.Size)); err != nil {
   389  		return err
   390  	}
   391  
   392  	f, err := os.OpenFile(jsonPath(root), os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.FileMode(0600))
   393  	if err != nil {
   394  		return err
   395  	}
   396  
   397  	defer f.Close()
   398  
   399  	return json.NewEncoder(f).Encode(img)
   400  }
   401  
   402  // loadImage fetches the image with the given id from the graph.
   403  func (graph *Graph) loadImage(id string) (*image.Image, error) {
   404  	root := graph.imageRoot(id)
   405  
   406  	// Open the JSON file to decode by streaming
   407  	jsonSource, err := os.Open(jsonPath(root))
   408  	if err != nil {
   409  		return nil, err
   410  	}
   411  	defer jsonSource.Close()
   412  
   413  	img := &image.Image{}
   414  	dec := json.NewDecoder(jsonSource)
   415  
   416  	// Decode the JSON data
   417  	if err := dec.Decode(img); err != nil {
   418  		return nil, err
   419  	}
   420  	if err := image.ValidateID(img.ID); err != nil {
   421  		return nil, err
   422  	}
   423  
   424  	if buf, err := ioutil.ReadFile(filepath.Join(root, "layersize")); err != nil {
   425  		if !os.IsNotExist(err) {
   426  			return nil, err
   427  		}
   428  		// If the layersize file does not exist then set the size to a negative number
   429  		// because a layer size of 0 (zero) is valid
   430  		img.Size = -1
   431  	} else {
   432  		// Using Atoi here instead would temporarily convert the size to a machine
   433  		// dependent integer type, which causes images larger than 2^31 bytes to
   434  		// display negative sizes on 32-bit machines:
   435  		size, err := strconv.ParseInt(string(buf), 10, 64)
   436  		if err != nil {
   437  			return nil, err
   438  		}
   439  		img.Size = int64(size)
   440  	}
   441  
   442  	return img, nil
   443  }
   444  
   445  // saveSize stores the `size` in the provided graph `img` directory `root`.
   446  func (graph *Graph) saveSize(root string, size int) error {
   447  	if err := ioutil.WriteFile(filepath.Join(root, "layersize"), []byte(strconv.Itoa(size)), 0600); err != nil {
   448  		return fmt.Errorf("Error storing image size in %s/layersize: %s", root, err)
   449  	}
   450  	return nil
   451  }
   452  
   453  // SetDigest sets the digest for the image layer to the provided value.
   454  func (graph *Graph) SetDigest(id string, dgst digest.Digest) error {
   455  	root := graph.imageRoot(id)
   456  	if err := ioutil.WriteFile(filepath.Join(root, "checksum"), []byte(dgst.String()), 0600); err != nil {
   457  		return fmt.Errorf("Error storing digest in %s/checksum: %s", root, err)
   458  	}
   459  	return nil
   460  }
   461  
   462  // GetDigest gets the digest for the provide image layer id.
   463  func (graph *Graph) GetDigest(id string) (digest.Digest, error) {
   464  	root := graph.imageRoot(id)
   465  	cs, err := ioutil.ReadFile(filepath.Join(root, "checksum"))
   466  	if err != nil {
   467  		if os.IsNotExist(err) {
   468  			return "", ErrDigestNotSet
   469  		}
   470  		return "", err
   471  	}
   472  	return digest.ParseDigest(string(cs))
   473  }
   474  
   475  // RawJSON returns the JSON representation for an image as a byte array.
   476  func (graph *Graph) RawJSON(id string) ([]byte, error) {
   477  	root := graph.imageRoot(id)
   478  
   479  	buf, err := ioutil.ReadFile(jsonPath(root))
   480  	if err != nil {
   481  		return nil, fmt.Errorf("Failed to read json for image %s: %s", id, err)
   482  	}
   483  
   484  	return buf, nil
   485  }
   486  
   487  func jsonPath(root string) string {
   488  	return filepath.Join(root, "json")
   489  }
   490  
   491  // TarLayer returns a tar archive of the image's filesystem layer.
   492  func (graph *Graph) TarLayer(img *image.Image) (arch archive.Archive, err error) {
   493  	return graph.driver.Diff(img.ID, img.Parent)
   494  }