github.com/resin-io/docker@v1.13.1/image/store.go (about)

     1  package image
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"fmt"
     7  	"sync"
     8  
     9  	"github.com/Sirupsen/logrus"
    10  	"github.com/docker/distribution/digest"
    11  	"github.com/docker/docker/layer"
    12  )
    13  
    14  // Store is an interface for creating and accessing images
    15  type Store interface {
    16  	Create(config []byte) (ID, error)
    17  	Get(id ID) (*Image, error)
    18  	Delete(id ID) ([]layer.Metadata, error)
    19  	Search(partialID string) (ID, error)
    20  	SetParent(id ID, parent ID) error
    21  	GetParent(id ID) (ID, error)
    22  	Children(id ID) []ID
    23  	Map() map[ID]*Image
    24  	Heads() map[ID]*Image
    25  }
    26  
    27  // LayerGetReleaser is a minimal interface for getting and releasing images.
    28  type LayerGetReleaser interface {
    29  	Get(layer.ChainID) (layer.Layer, error)
    30  	Release(layer.Layer) ([]layer.Metadata, error)
    31  }
    32  
    33  type imageMeta struct {
    34  	layer    layer.Layer
    35  	children map[ID]struct{}
    36  }
    37  
    38  type store struct {
    39  	sync.Mutex
    40  	ls        LayerGetReleaser
    41  	images    map[ID]*imageMeta
    42  	fs        StoreBackend
    43  	digestSet *digest.Set
    44  }
    45  
    46  // NewImageStore returns new store object for given layer store
    47  func NewImageStore(fs StoreBackend, ls LayerGetReleaser) (Store, error) {
    48  	is := &store{
    49  		ls:        ls,
    50  		images:    make(map[ID]*imageMeta),
    51  		fs:        fs,
    52  		digestSet: digest.NewSet(),
    53  	}
    54  
    55  	// load all current images and retain layers
    56  	if err := is.restore(); err != nil {
    57  		return nil, err
    58  	}
    59  
    60  	return is, nil
    61  }
    62  
    63  func (is *store) restore() error {
    64  	err := is.fs.Walk(func(dgst digest.Digest) error {
    65  		img, err := is.Get(IDFromDigest(dgst))
    66  		if err != nil {
    67  			logrus.Errorf("invalid image %v, %v", dgst, err)
    68  			return nil
    69  		}
    70  		var l layer.Layer
    71  		if chainID := img.RootFS.ChainID(); chainID != "" {
    72  			l, err = is.ls.Get(chainID)
    73  			if err != nil {
    74  				return err
    75  			}
    76  		}
    77  		if err := is.digestSet.Add(dgst); err != nil {
    78  			return err
    79  		}
    80  
    81  		imageMeta := &imageMeta{
    82  			layer:    l,
    83  			children: make(map[ID]struct{}),
    84  		}
    85  
    86  		is.images[IDFromDigest(dgst)] = imageMeta
    87  
    88  		return nil
    89  	})
    90  	if err != nil {
    91  		return err
    92  	}
    93  
    94  	// Second pass to fill in children maps
    95  	for id := range is.images {
    96  		if parent, err := is.GetParent(id); err == nil {
    97  			if parentMeta := is.images[parent]; parentMeta != nil {
    98  				parentMeta.children[id] = struct{}{}
    99  			}
   100  		}
   101  	}
   102  
   103  	return nil
   104  }
   105  
   106  func (is *store) Create(config []byte) (ID, error) {
   107  	var img Image
   108  	err := json.Unmarshal(config, &img)
   109  	if err != nil {
   110  		return "", err
   111  	}
   112  
   113  	// Must reject any config that references diffIDs from the history
   114  	// which aren't among the rootfs layers.
   115  	rootFSLayers := make(map[layer.DiffID]struct{})
   116  	for _, diffID := range img.RootFS.DiffIDs {
   117  		rootFSLayers[diffID] = struct{}{}
   118  	}
   119  
   120  	layerCounter := 0
   121  	for _, h := range img.History {
   122  		if !h.EmptyLayer {
   123  			layerCounter++
   124  		}
   125  	}
   126  	if layerCounter > len(img.RootFS.DiffIDs) {
   127  		return "", errors.New("too many non-empty layers in History section")
   128  	}
   129  
   130  	dgst, err := is.fs.Set(config)
   131  	if err != nil {
   132  		return "", err
   133  	}
   134  	imageID := IDFromDigest(dgst)
   135  
   136  	is.Lock()
   137  	defer is.Unlock()
   138  
   139  	if _, exists := is.images[imageID]; exists {
   140  		return imageID, nil
   141  	}
   142  
   143  	layerID := img.RootFS.ChainID()
   144  
   145  	var l layer.Layer
   146  	if layerID != "" {
   147  		l, err = is.ls.Get(layerID)
   148  		if err != nil {
   149  			return "", err
   150  		}
   151  	}
   152  
   153  	imageMeta := &imageMeta{
   154  		layer:    l,
   155  		children: make(map[ID]struct{}),
   156  	}
   157  
   158  	is.images[imageID] = imageMeta
   159  	if err := is.digestSet.Add(imageID.Digest()); err != nil {
   160  		delete(is.images, imageID)
   161  		return "", err
   162  	}
   163  
   164  	return imageID, nil
   165  }
   166  
   167  func (is *store) Search(term string) (ID, error) {
   168  	is.Lock()
   169  	defer is.Unlock()
   170  
   171  	dgst, err := is.digestSet.Lookup(term)
   172  	if err != nil {
   173  		if err == digest.ErrDigestNotFound {
   174  			err = fmt.Errorf("No such image: %s", term)
   175  		}
   176  		return "", err
   177  	}
   178  	return IDFromDigest(dgst), nil
   179  }
   180  
   181  func (is *store) Get(id ID) (*Image, error) {
   182  	// todo: Check if image is in images
   183  	// todo: Detect manual insertions and start using them
   184  	config, err := is.fs.Get(id.Digest())
   185  	if err != nil {
   186  		return nil, err
   187  	}
   188  
   189  	img, err := NewFromJSON(config)
   190  	if err != nil {
   191  		return nil, err
   192  	}
   193  	img.computedID = id
   194  
   195  	img.Parent, err = is.GetParent(id)
   196  	if err != nil {
   197  		img.Parent = ""
   198  	}
   199  
   200  	return img, nil
   201  }
   202  
   203  func (is *store) Delete(id ID) ([]layer.Metadata, error) {
   204  	is.Lock()
   205  	defer is.Unlock()
   206  
   207  	imageMeta := is.images[id]
   208  	if imageMeta == nil {
   209  		return nil, fmt.Errorf("unrecognized image ID %s", id.String())
   210  	}
   211  	for id := range imageMeta.children {
   212  		is.fs.DeleteMetadata(id.Digest(), "parent")
   213  	}
   214  	if parent, err := is.GetParent(id); err == nil && is.images[parent] != nil {
   215  		delete(is.images[parent].children, id)
   216  	}
   217  
   218  	if err := is.digestSet.Remove(id.Digest()); err != nil {
   219  		logrus.Errorf("error removing %s from digest set: %q", id, err)
   220  	}
   221  	delete(is.images, id)
   222  	is.fs.Delete(id.Digest())
   223  
   224  	if imageMeta.layer != nil {
   225  		return is.ls.Release(imageMeta.layer)
   226  	}
   227  	return nil, nil
   228  }
   229  
   230  func (is *store) SetParent(id, parent ID) error {
   231  	is.Lock()
   232  	defer is.Unlock()
   233  	parentMeta := is.images[parent]
   234  	if parentMeta == nil {
   235  		return fmt.Errorf("unknown parent image ID %s", parent.String())
   236  	}
   237  	if parent, err := is.GetParent(id); err == nil && is.images[parent] != nil {
   238  		delete(is.images[parent].children, id)
   239  	}
   240  	parentMeta.children[id] = struct{}{}
   241  	return is.fs.SetMetadata(id.Digest(), "parent", []byte(parent))
   242  }
   243  
   244  func (is *store) GetParent(id ID) (ID, error) {
   245  	d, err := is.fs.GetMetadata(id.Digest(), "parent")
   246  	if err != nil {
   247  		return "", err
   248  	}
   249  	return ID(d), nil // todo: validate?
   250  }
   251  
   252  func (is *store) Children(id ID) []ID {
   253  	is.Lock()
   254  	defer is.Unlock()
   255  
   256  	return is.children(id)
   257  }
   258  
   259  func (is *store) children(id ID) []ID {
   260  	var ids []ID
   261  	if is.images[id] != nil {
   262  		for id := range is.images[id].children {
   263  			ids = append(ids, id)
   264  		}
   265  	}
   266  	return ids
   267  }
   268  
   269  func (is *store) Heads() map[ID]*Image {
   270  	return is.imagesMap(false)
   271  }
   272  
   273  func (is *store) Map() map[ID]*Image {
   274  	return is.imagesMap(true)
   275  }
   276  
   277  func (is *store) imagesMap(all bool) map[ID]*Image {
   278  	is.Lock()
   279  	defer is.Unlock()
   280  
   281  	images := make(map[ID]*Image)
   282  
   283  	for id := range is.images {
   284  		if !all && len(is.children(id)) > 0 {
   285  			continue
   286  		}
   287  		img, err := is.Get(id)
   288  		if err != nil {
   289  			logrus.Errorf("invalid image access: %q, error: %q", id, err)
   290  			continue
   291  		}
   292  		images[id] = img
   293  	}
   294  	return images
   295  }