github.com/pritambaral/docker@v1.4.2-0.20150120174542-b2fe1b3dd952/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  		// If the image doesn't have a checksum, we should add it. The layer
    98  		// checksums are verified when they are pulled from a remote, but when
    99  		// a container is committed it should be added here.
   100  		if img.Checksum == "" {
   101  			layerDataDecompressed, err := archive.DecompressStream(layerData)
   102  			if err != nil {
   103  				return err
   104  			}
   105  			defer layerDataDecompressed.Close()
   106  
   107  			if layerTarSum, err = tarsum.NewTarSum(layerDataDecompressed, true, tarsum.VersionDev); err != nil {
   108  				return err
   109  			}
   110  
   111  			if size, err = driver.ApplyDiff(img.ID, img.Parent, layerTarSum); err != nil {
   112  				return err
   113  			}
   114  
   115  			img.Checksum = layerTarSum.Sum(nil)
   116  		} else if size, err = driver.ApplyDiff(img.ID, img.Parent, layerData); err != nil {
   117  			return err
   118  		}
   119  
   120  	}
   121  
   122  	img.Size = size
   123  	if err := img.SaveSize(root); err != nil {
   124  		return err
   125  	}
   126  
   127  	f, err := os.OpenFile(jsonPath(root), os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.FileMode(0600))
   128  	if err != nil {
   129  		return err
   130  	}
   131  
   132  	defer f.Close()
   133  
   134  	return json.NewEncoder(f).Encode(img)
   135  }
   136  
   137  func (img *Image) SetGraph(graph Graph) {
   138  	img.graph = graph
   139  }
   140  
   141  // SaveSize stores the current `size` value of `img` in the directory `root`.
   142  func (img *Image) SaveSize(root string) error {
   143  	if err := ioutil.WriteFile(path.Join(root, "layersize"), []byte(strconv.Itoa(int(img.Size))), 0600); err != nil {
   144  		return fmt.Errorf("Error storing image size in %s/layersize: %s", root, err)
   145  	}
   146  	return nil
   147  }
   148  
   149  func jsonPath(root string) string {
   150  	return path.Join(root, "json")
   151  }
   152  
   153  func (img *Image) RawJson() ([]byte, error) {
   154  	root, err := img.root()
   155  	if err != nil {
   156  		return nil, fmt.Errorf("Failed to get root for image %s: %s", img.ID, err)
   157  	}
   158  	fh, err := os.Open(jsonPath(root))
   159  	if err != nil {
   160  		return nil, fmt.Errorf("Failed to open json for image %s: %s", img.ID, err)
   161  	}
   162  	buf, err := ioutil.ReadAll(fh)
   163  	if err != nil {
   164  		return nil, fmt.Errorf("Failed to read json for image %s: %s", img.ID, err)
   165  	}
   166  	return buf, nil
   167  }
   168  
   169  // TarLayer returns a tar archive of the image's filesystem layer.
   170  func (img *Image) TarLayer() (arch archive.Archive, err error) {
   171  	if img.graph == nil {
   172  		return nil, fmt.Errorf("Can't load storage driver for unregistered image %s", img.ID)
   173  	}
   174  
   175  	driver := img.graph.Driver()
   176  
   177  	return driver.Diff(img.ID, img.Parent)
   178  }
   179  
   180  // Image includes convenience proxy functions to its graph
   181  // These functions will return an error if the image is not registered
   182  // (ie. if image.graph == nil)
   183  func (img *Image) History() ([]*Image, error) {
   184  	var parents []*Image
   185  	if err := img.WalkHistory(
   186  		func(img *Image) error {
   187  			parents = append(parents, img)
   188  			return nil
   189  		},
   190  	); err != nil {
   191  		return nil, err
   192  	}
   193  	return parents, nil
   194  }
   195  
   196  func (img *Image) WalkHistory(handler func(*Image) error) (err error) {
   197  	currentImg := img
   198  	for currentImg != nil {
   199  		if handler != nil {
   200  			if err := handler(currentImg); err != nil {
   201  				return err
   202  			}
   203  		}
   204  		currentImg, err = currentImg.GetParent()
   205  		if err != nil {
   206  			return fmt.Errorf("Error while getting parent image: %v", err)
   207  		}
   208  	}
   209  	return nil
   210  }
   211  
   212  func (img *Image) GetParent() (*Image, error) {
   213  	if img.Parent == "" {
   214  		return nil, nil
   215  	}
   216  	if img.graph == nil {
   217  		return nil, fmt.Errorf("Can't lookup parent of unregistered image")
   218  	}
   219  	return img.graph.Get(img.Parent)
   220  }
   221  
   222  func (img *Image) root() (string, error) {
   223  	if img.graph == nil {
   224  		return "", fmt.Errorf("Can't lookup root of unregistered image")
   225  	}
   226  	return img.graph.ImageRoot(img.ID), nil
   227  }
   228  
   229  func (img *Image) GetParentsSize(size int64) int64 {
   230  	parentImage, err := img.GetParent()
   231  	if err != nil || parentImage == nil {
   232  		return size
   233  	}
   234  	size += parentImage.Size
   235  	return parentImage.GetParentsSize(size)
   236  }
   237  
   238  // Depth returns the number of parents for a
   239  // current image
   240  func (img *Image) Depth() (int, error) {
   241  	var (
   242  		count  = 0
   243  		parent = img
   244  		err    error
   245  	)
   246  
   247  	for parent != nil {
   248  		count++
   249  		parent, err = parent.GetParent()
   250  		if err != nil {
   251  			return -1, err
   252  		}
   253  	}
   254  	return count, nil
   255  }
   256  
   257  // CheckDepth returns an error if the depth of an image, as returned
   258  // by ImageDepth, is too large to support creating a container from it
   259  // on this daemon.
   260  func (img *Image) CheckDepth() error {
   261  	// We add 2 layers to the depth because the container's rw and
   262  	// init layer add to the restriction
   263  	depth, err := img.Depth()
   264  	if err != nil {
   265  		return err
   266  	}
   267  	if depth+2 >= MaxImageDepth {
   268  		return fmt.Errorf("Cannot create container with more than %d parents", MaxImageDepth)
   269  	}
   270  	return nil
   271  }
   272  
   273  // Build an Image object from raw json data
   274  func NewImgJSON(src []byte) (*Image, error) {
   275  	ret := &Image{}
   276  
   277  	log.Debugf("Json string: {%s}", src)
   278  	// FIXME: Is there a cleaner way to "purify" the input json?
   279  	if err := json.Unmarshal(src, ret); err != nil {
   280  		return nil, err
   281  	}
   282  	return ret, nil
   283  }