github.com/dlintw/docker@v1.5.0-rc4/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  	fh, err := os.Open(jsonPath(root))
   144  	if err != nil {
   145  		return nil, fmt.Errorf("Failed to open json for image %s: %s", img.ID, err)
   146  	}
   147  	buf, err := ioutil.ReadAll(fh)
   148  	if err != nil {
   149  		return nil, fmt.Errorf("Failed to read json for image %s: %s", img.ID, err)
   150  	}
   151  	return buf, nil
   152  }
   153  
   154  // TarLayer returns a tar archive of the image's filesystem layer.
   155  func (img *Image) TarLayer() (arch archive.Archive, err error) {
   156  	if img.graph == nil {
   157  		return nil, fmt.Errorf("Can't load storage driver for unregistered image %s", img.ID)
   158  	}
   159  
   160  	driver := img.graph.Driver()
   161  
   162  	return driver.Diff(img.ID, img.Parent)
   163  }
   164  
   165  // Image includes convenience proxy functions to its graph
   166  // These functions will return an error if the image is not registered
   167  // (ie. if image.graph == nil)
   168  func (img *Image) History() ([]*Image, error) {
   169  	var parents []*Image
   170  	if err := img.WalkHistory(
   171  		func(img *Image) error {
   172  			parents = append(parents, img)
   173  			return nil
   174  		},
   175  	); err != nil {
   176  		return nil, err
   177  	}
   178  	return parents, nil
   179  }
   180  
   181  func (img *Image) WalkHistory(handler func(*Image) error) (err error) {
   182  	currentImg := img
   183  	for currentImg != nil {
   184  		if handler != nil {
   185  			if err := handler(currentImg); err != nil {
   186  				return err
   187  			}
   188  		}
   189  		currentImg, err = currentImg.GetParent()
   190  		if err != nil {
   191  			return fmt.Errorf("Error while getting parent image: %v", err)
   192  		}
   193  	}
   194  	return nil
   195  }
   196  
   197  func (img *Image) GetParent() (*Image, error) {
   198  	if img.Parent == "" {
   199  		return nil, nil
   200  	}
   201  	if img.graph == nil {
   202  		return nil, fmt.Errorf("Can't lookup parent of unregistered image")
   203  	}
   204  	return img.graph.Get(img.Parent)
   205  }
   206  
   207  func (img *Image) root() (string, error) {
   208  	if img.graph == nil {
   209  		return "", fmt.Errorf("Can't lookup root of unregistered image")
   210  	}
   211  	return img.graph.ImageRoot(img.ID), nil
   212  }
   213  
   214  func (img *Image) GetParentsSize(size int64) int64 {
   215  	parentImage, err := img.GetParent()
   216  	if err != nil || parentImage == nil {
   217  		return size
   218  	}
   219  	size += parentImage.Size
   220  	return parentImage.GetParentsSize(size)
   221  }
   222  
   223  // Depth returns the number of parents for a
   224  // current image
   225  func (img *Image) Depth() (int, error) {
   226  	var (
   227  		count  = 0
   228  		parent = img
   229  		err    error
   230  	)
   231  
   232  	for parent != nil {
   233  		count++
   234  		parent, err = parent.GetParent()
   235  		if err != nil {
   236  			return -1, err
   237  		}
   238  	}
   239  	return count, nil
   240  }
   241  
   242  // CheckDepth returns an error if the depth of an image, as returned
   243  // by ImageDepth, is too large to support creating a container from it
   244  // on this daemon.
   245  func (img *Image) CheckDepth() error {
   246  	// We add 2 layers to the depth because the container's rw and
   247  	// init layer add to the restriction
   248  	depth, err := img.Depth()
   249  	if err != nil {
   250  		return err
   251  	}
   252  	if depth+2 >= MaxImageDepth {
   253  		return fmt.Errorf("Cannot create container with more than %d parents", MaxImageDepth)
   254  	}
   255  	return nil
   256  }
   257  
   258  // Build an Image object from raw json data
   259  func NewImgJSON(src []byte) (*Image, error) {
   260  	ret := &Image{}
   261  
   262  	// FIXME: Is there a cleaner way to "purify" the input json?
   263  	if err := json.Unmarshal(src, ret); err != nil {
   264  		return nil, err
   265  	}
   266  	return ret, nil
   267  }