github.com/adxhyt/docker@v1.4.2-0.20150117221845-467b7c821390/image/image.go (about)

     1  package image
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"os"
     8  	"path"
     9  	"strconv"
    10  	"time"
    11  
    12  	log "github.com/Sirupsen/logrus"
    13  	"github.com/docker/docker/pkg/archive"
    14  	"github.com/docker/docker/pkg/tarsum"
    15  	"github.com/docker/docker/runconfig"
    16  	"github.com/docker/docker/utils"
    17  )
    18  
    19  // Set the max depth to the aufs default that most
    20  // kernels are compiled with
    21  // For more information see: http://sourceforge.net/p/aufs/aufs3-standalone/ci/aufs3.12/tree/config.mk
    22  const MaxImageDepth = 127
    23  
    24  type Image struct {
    25  	ID              string            `json:"id"`
    26  	Parent          string            `json:"parent,omitempty"`
    27  	Comment         string            `json:"comment,omitempty"`
    28  	Created         time.Time         `json:"created"`
    29  	Container       string            `json:"container,omitempty"`
    30  	ContainerConfig runconfig.Config  `json:"container_config,omitempty"`
    31  	DockerVersion   string            `json:"docker_version,omitempty"`
    32  	Author          string            `json:"author,omitempty"`
    33  	Config          *runconfig.Config `json:"config,omitempty"`
    34  	Architecture    string            `json:"architecture,omitempty"`
    35  	OS              string            `json:"os,omitempty"`
    36  	Checksum        string            `json:"checksum"`
    37  	Size            int64
    38  
    39  	graph Graph
    40  }
    41  
    42  func LoadImage(root string) (*Image, error) {
    43  	// Open the JSON file to decode by streaming
    44  	jsonSource, err := os.Open(jsonPath(root))
    45  	if err != nil {
    46  		return nil, err
    47  	}
    48  	defer jsonSource.Close()
    49  
    50  	img := &Image{}
    51  	dec := json.NewDecoder(jsonSource)
    52  
    53  	// Decode the JSON data
    54  	if err := dec.Decode(img); err != nil {
    55  		return nil, err
    56  	}
    57  	if err := utils.ValidateID(img.ID); err != nil {
    58  		return nil, err
    59  	}
    60  
    61  	if buf, err := ioutil.ReadFile(path.Join(root, "layersize")); err != nil {
    62  		if !os.IsNotExist(err) {
    63  			return nil, err
    64  		}
    65  		// If the layersize file does not exist then set the size to a negative number
    66  		// because a layer size of 0 (zero) is valid
    67  		img.Size = -1
    68  	} else {
    69  		// Using Atoi here instead would temporarily convert the size to a machine
    70  		// dependent integer type, which causes images larger than 2^31 bytes to
    71  		// display negative sizes on 32-bit machines:
    72  		size, err := strconv.ParseInt(string(buf), 10, 64)
    73  		if err != nil {
    74  			return nil, err
    75  		}
    76  		img.Size = int64(size)
    77  	}
    78  
    79  	return img, nil
    80  }
    81  
    82  // StoreImage stores file system layer data for the given image to the
    83  // image's registered storage driver. Image metadata is stored in a file
    84  // at the specified root directory. This function also computes the TarSum
    85  // of `layerData` (currently using tarsum.dev).
    86  func StoreImage(img *Image, layerData archive.ArchiveReader, root string) error {
    87  	// Store the layer
    88  	var (
    89  		size        int64
    90  		err         error
    91  		driver      = img.graph.Driver()
    92  		layerTarSum tarsum.TarSum
    93  	)
    94  
    95  	// If layerData is not nil, unpack it into the new layer
    96  	if layerData != nil {
    97  		layerDataDecompressed, err := archive.DecompressStream(layerData)
    98  		if err != nil {
    99  			return err
   100  		}
   101  
   102  		defer layerDataDecompressed.Close()
   103  
   104  		if layerTarSum, err = tarsum.NewTarSum(layerDataDecompressed, true, tarsum.VersionDev); err != nil {
   105  			return err
   106  		}
   107  
   108  		if size, err = driver.ApplyDiff(img.ID, img.Parent, layerTarSum); err != nil {
   109  			return err
   110  		}
   111  
   112  		checksum := layerTarSum.Sum(nil)
   113  
   114  		if img.Checksum != "" && img.Checksum != checksum {
   115  			log.Warnf("image layer checksum mismatch: computed %q, expected %q", checksum, img.Checksum)
   116  		}
   117  
   118  		img.Checksum = checksum
   119  	}
   120  
   121  	img.Size = size
   122  	if err := img.SaveSize(root); err != nil {
   123  		return err
   124  	}
   125  
   126  	f, err := os.OpenFile(jsonPath(root), os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.FileMode(0600))
   127  	if err != nil {
   128  		return err
   129  	}
   130  
   131  	defer f.Close()
   132  
   133  	return json.NewEncoder(f).Encode(img)
   134  }
   135  
   136  func (img *Image) SetGraph(graph Graph) {
   137  	img.graph = graph
   138  }
   139  
   140  // SaveSize stores the current `size` value of `img` in the directory `root`.
   141  func (img *Image) SaveSize(root string) error {
   142  	if err := ioutil.WriteFile(path.Join(root, "layersize"), []byte(strconv.Itoa(int(img.Size))), 0600); err != nil {
   143  		return fmt.Errorf("Error storing image size in %s/layersize: %s", root, err)
   144  	}
   145  	return nil
   146  }
   147  
   148  func jsonPath(root string) string {
   149  	return path.Join(root, "json")
   150  }
   151  
   152  func (img *Image) RawJson() ([]byte, error) {
   153  	root, err := img.root()
   154  	if err != nil {
   155  		return nil, fmt.Errorf("Failed to get root for image %s: %s", img.ID, err)
   156  	}
   157  	fh, err := os.Open(jsonPath(root))
   158  	if err != nil {
   159  		return nil, fmt.Errorf("Failed to open json for image %s: %s", img.ID, err)
   160  	}
   161  	buf, err := ioutil.ReadAll(fh)
   162  	if err != nil {
   163  		return nil, fmt.Errorf("Failed to read json for image %s: %s", img.ID, err)
   164  	}
   165  	return buf, nil
   166  }
   167  
   168  // TarLayer returns a tar archive of the image's filesystem layer.
   169  func (img *Image) TarLayer() (arch archive.Archive, err error) {
   170  	if img.graph == nil {
   171  		return nil, fmt.Errorf("Can't load storage driver for unregistered image %s", img.ID)
   172  	}
   173  
   174  	driver := img.graph.Driver()
   175  
   176  	return driver.Diff(img.ID, img.Parent)
   177  }
   178  
   179  // Image includes convenience proxy functions to its graph
   180  // These functions will return an error if the image is not registered
   181  // (ie. if image.graph == nil)
   182  func (img *Image) History() ([]*Image, error) {
   183  	var parents []*Image
   184  	if err := img.WalkHistory(
   185  		func(img *Image) error {
   186  			parents = append(parents, img)
   187  			return nil
   188  		},
   189  	); err != nil {
   190  		return nil, err
   191  	}
   192  	return parents, nil
   193  }
   194  
   195  func (img *Image) WalkHistory(handler func(*Image) error) (err error) {
   196  	currentImg := img
   197  	for currentImg != nil {
   198  		if handler != nil {
   199  			if err := handler(currentImg); err != nil {
   200  				return err
   201  			}
   202  		}
   203  		currentImg, err = currentImg.GetParent()
   204  		if err != nil {
   205  			return fmt.Errorf("Error while getting parent image: %v", err)
   206  		}
   207  	}
   208  	return nil
   209  }
   210  
   211  func (img *Image) GetParent() (*Image, error) {
   212  	if img.Parent == "" {
   213  		return nil, nil
   214  	}
   215  	if img.graph == nil {
   216  		return nil, fmt.Errorf("Can't lookup parent of unregistered image")
   217  	}
   218  	return img.graph.Get(img.Parent)
   219  }
   220  
   221  func (img *Image) root() (string, error) {
   222  	if img.graph == nil {
   223  		return "", fmt.Errorf("Can't lookup root of unregistered image")
   224  	}
   225  	return img.graph.ImageRoot(img.ID), nil
   226  }
   227  
   228  func (img *Image) GetParentsSize(size int64) int64 {
   229  	parentImage, err := img.GetParent()
   230  	if err != nil || parentImage == nil {
   231  		return size
   232  	}
   233  	size += parentImage.Size
   234  	return parentImage.GetParentsSize(size)
   235  }
   236  
   237  // Depth returns the number of parents for a
   238  // current image
   239  func (img *Image) Depth() (int, error) {
   240  	var (
   241  		count  = 0
   242  		parent = img
   243  		err    error
   244  	)
   245  
   246  	for parent != nil {
   247  		count++
   248  		parent, err = parent.GetParent()
   249  		if err != nil {
   250  			return -1, err
   251  		}
   252  	}
   253  	return count, nil
   254  }
   255  
   256  // CheckDepth returns an error if the depth of an image, as returned
   257  // by ImageDepth, is too large to support creating a container from it
   258  // on this daemon.
   259  func (img *Image) CheckDepth() error {
   260  	// We add 2 layers to the depth because the container's rw and
   261  	// init layer add to the restriction
   262  	depth, err := img.Depth()
   263  	if err != nil {
   264  		return err
   265  	}
   266  	if depth+2 >= MaxImageDepth {
   267  		return fmt.Errorf("Cannot create container with more than %d parents", MaxImageDepth)
   268  	}
   269  	return nil
   270  }
   271  
   272  // Build an Image object from raw json data
   273  func NewImgJSON(src []byte) (*Image, error) {
   274  	ret := &Image{}
   275  
   276  	log.Debugf("Json string: {%s}", src)
   277  	// FIXME: Is there a cleaner way to "purify" the input json?
   278  	if err := json.Unmarshal(src, ret); err != nil {
   279  		return nil, err
   280  	}
   281  	return ret, nil
   282  }