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