github.com/jandre/docker@v1.7.0/image/image.go (about)

     1  package image
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"os"
     8  	"path/filepath"
     9  	"regexp"
    10  	"strconv"
    11  	"time"
    12  
    13  	"github.com/docker/docker/pkg/archive"
    14  	"github.com/docker/docker/runconfig"
    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  var validHex = regexp.MustCompile(`^([a-f0-9]{64})$`)
    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  	Size            int64
    37  
    38  	graph Graph
    39  }
    40  
    41  func LoadImage(root string) (*Image, error) {
    42  	// Open the JSON file to decode by streaming
    43  	jsonSource, err := os.Open(jsonPath(root))
    44  	if err != nil {
    45  		return nil, err
    46  	}
    47  	defer jsonSource.Close()
    48  
    49  	img := &Image{}
    50  	dec := json.NewDecoder(jsonSource)
    51  
    52  	// Decode the JSON data
    53  	if err := dec.Decode(img); err != nil {
    54  		return nil, err
    55  	}
    56  	if err := ValidateID(img.ID); err != nil {
    57  		return nil, err
    58  	}
    59  
    60  	if buf, err := ioutil.ReadFile(filepath.Join(root, "layersize")); err != nil {
    61  		if !os.IsNotExist(err) {
    62  			return nil, err
    63  		}
    64  		// If the layersize file does not exist then set the size to a negative number
    65  		// because a layer size of 0 (zero) is valid
    66  		img.Size = -1
    67  	} else {
    68  		// Using Atoi here instead would temporarily convert the size to a machine
    69  		// dependent integer type, which causes images larger than 2^31 bytes to
    70  		// display negative sizes on 32-bit machines:
    71  		size, err := strconv.ParseInt(string(buf), 10, 64)
    72  		if err != nil {
    73  			return nil, err
    74  		}
    75  		img.Size = int64(size)
    76  	}
    77  
    78  	return img, nil
    79  }
    80  
    81  // StoreImage stores file system layer data for the given image to the
    82  // image's registered storage driver. Image metadata is stored in a file
    83  // at the specified root directory.
    84  func StoreImage(img *Image, layerData archive.ArchiveReader, root string) (err error) {
    85  	// Store the layer. If layerData is not nil, unpack it into the new layer
    86  	if layerData != nil {
    87  		if img.Size, err = img.graph.Driver().ApplyDiff(img.ID, img.Parent, layerData); err != nil {
    88  			return err
    89  		}
    90  	}
    91  
    92  	if err := img.SaveSize(root); err != nil {
    93  		return err
    94  	}
    95  
    96  	f, err := os.OpenFile(jsonPath(root), os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.FileMode(0600))
    97  	if err != nil {
    98  		return err
    99  	}
   100  
   101  	defer f.Close()
   102  
   103  	return json.NewEncoder(f).Encode(img)
   104  }
   105  
   106  func (img *Image) SetGraph(graph Graph) {
   107  	img.graph = graph
   108  }
   109  
   110  // SaveSize stores the current `size` value of `img` in the directory `root`.
   111  func (img *Image) SaveSize(root string) error {
   112  	if err := ioutil.WriteFile(filepath.Join(root, "layersize"), []byte(strconv.Itoa(int(img.Size))), 0600); err != nil {
   113  		return fmt.Errorf("Error storing image size in %s/layersize: %s", root, err)
   114  	}
   115  	return nil
   116  }
   117  
   118  func (img *Image) SaveCheckSum(root, checksum string) error {
   119  	if err := ioutil.WriteFile(filepath.Join(root, "checksum"), []byte(checksum), 0600); err != nil {
   120  		return fmt.Errorf("Error storing checksum in %s/checksum: %s", root, err)
   121  	}
   122  	return nil
   123  }
   124  
   125  func (img *Image) GetCheckSum(root string) (string, error) {
   126  	cs, err := ioutil.ReadFile(filepath.Join(root, "checksum"))
   127  	if err != nil {
   128  		if os.IsNotExist(err) {
   129  			return "", nil
   130  		}
   131  		return "", err
   132  	}
   133  	return string(cs), err
   134  }
   135  
   136  func jsonPath(root string) string {
   137  	return filepath.Join(root, "json")
   138  }
   139  
   140  func (img *Image) RawJson() ([]byte, error) {
   141  	root, err := img.root()
   142  	if err != nil {
   143  		return nil, fmt.Errorf("Failed to get root for image %s: %s", img.ID, err)
   144  	}
   145  
   146  	buf, err := ioutil.ReadFile(jsonPath(root))
   147  	if err != nil {
   148  		return nil, fmt.Errorf("Failed to read json for image %s: %s", img.ID, err)
   149  	}
   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  }
   268  
   269  // Check wheather id is a valid image ID or not
   270  func ValidateID(id string) error {
   271  	if ok := validHex.MatchString(id); !ok {
   272  		return fmt.Errorf("image ID '%s' is invalid", id)
   273  	}
   274  	return nil
   275  }