github.com/rhatdan/docker@v0.7.7-0.20180119204836-47a0dcbcd20a/image/store.go (about)

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