distribution/client/objectstore.go
Stephen J Day eaadb82e1e Move Manifest type into storage package
This changeset move the Manifest type into the storage package to make the type
accessible to client and registry without import cycles. The structure of the
manifest was also changed to accuratle reflect the stages of the signing
process. A straw man Manifest.Sign method has been added to start testing this
concept out but will probably be accompanied by the more import
SignedManifest.Verify method as the security model develops.

This is probably the start of a concerted effort to consolidate types across
the client and server portions of the code base but we may want to see how such
a handy type, like the Manifest and SignedManifest, would work in docker core.
2014-11-21 19:37:44 -08:00

159 lines
3.9 KiB
Go

package client
import (
"bytes"
"errors"
"fmt"
"io"
"io/ioutil"
"sync"
"github.com/docker/docker-registry/digest"
"github.com/docker/docker-registry/storage"
)
var (
// ErrLayerAlreadyExists is returned when attempting to create a layer with
// a tarsum that is already in use.
ErrLayerAlreadyExists = errors.New("Layer already exists")
// ErrLayerLocked is returned when attempting to write to a layer which is
// currently being written to.
ErrLayerLocked = errors.New("Layer locked")
)
// ObjectStore is an interface which is designed to approximate the docker
// engine storage. This interface is subject to change to conform to the
// future requirements of the engine.
type ObjectStore interface {
// Manifest retrieves the image manifest stored at the given repository name
// and tag
Manifest(name, tag string) (*storage.SignedManifest, error)
// WriteManifest stores an image manifest at the given repository name and
// tag
WriteManifest(name, tag string, manifest *storage.SignedManifest) error
// Layer returns a handle to a layer for reading and writing
Layer(dgst digest.Digest) (Layer, error)
}
// Layer is a generic image layer interface.
// A Layer may only be written to once
type Layer interface {
// Reader returns an io.ReadCloser which reads the contents of the layer
Reader() (io.ReadCloser, error)
// Writer returns an io.WriteCloser which may write the contents of the
// layer. This method may only be called once per Layer, and the contents
// are made available on Close
Writer() (io.WriteCloser, error)
// Wait blocks until the Layer can be read from
Wait() error
}
// memoryObjectStore is an in-memory implementation of the ObjectStore interface
type memoryObjectStore struct {
mutex *sync.Mutex
manifestStorage map[string]*storage.SignedManifest
layerStorage map[digest.Digest]Layer
}
func (objStore *memoryObjectStore) Manifest(name, tag string) (*storage.SignedManifest, error) {
objStore.mutex.Lock()
defer objStore.mutex.Unlock()
manifest, ok := objStore.manifestStorage[name+":"+tag]
if !ok {
return nil, fmt.Errorf("No manifest found with Name: %q, Tag: %q", name, tag)
}
return manifest, nil
}
func (objStore *memoryObjectStore) WriteManifest(name, tag string, manifest *storage.SignedManifest) error {
objStore.mutex.Lock()
defer objStore.mutex.Unlock()
objStore.manifestStorage[name+":"+tag] = manifest
return nil
}
func (objStore *memoryObjectStore) Layer(dgst digest.Digest) (Layer, error) {
objStore.mutex.Lock()
defer objStore.mutex.Unlock()
layer, ok := objStore.layerStorage[dgst]
if !ok {
layer = &memoryLayer{cond: sync.NewCond(new(sync.Mutex))}
objStore.layerStorage[dgst] = layer
}
return layer, nil
}
type memoryLayer struct {
cond *sync.Cond
buffer *bytes.Buffer
written bool
}
func (ml *memoryLayer) Writer() (io.WriteCloser, error) {
ml.cond.L.Lock()
defer ml.cond.L.Unlock()
if ml.buffer != nil {
if !ml.written {
return nil, ErrLayerLocked
}
return nil, ErrLayerAlreadyExists
}
ml.buffer = new(bytes.Buffer)
return &memoryLayerWriter{cond: ml.cond, buffer: ml.buffer, done: &ml.written}, nil
}
func (ml *memoryLayer) Reader() (io.ReadCloser, error) {
ml.cond.L.Lock()
defer ml.cond.L.Unlock()
if ml.buffer == nil {
return nil, fmt.Errorf("Layer has not been written to yet")
}
if !ml.written {
return nil, ErrLayerLocked
}
return ioutil.NopCloser(bytes.NewReader(ml.buffer.Bytes())), nil
}
func (ml *memoryLayer) Wait() error {
ml.cond.L.Lock()
defer ml.cond.L.Unlock()
if ml.buffer == nil {
return fmt.Errorf("No writer to wait on")
}
for !ml.written {
ml.cond.Wait()
}
return nil
}
type memoryLayerWriter struct {
cond *sync.Cond
buffer *bytes.Buffer
done *bool
}
func (mlw *memoryLayerWriter) Write(p []byte) (int, error) {
return mlw.buffer.Write(p)
}
func (mlw *memoryLayerWriter) Close() error {
*mlw.done = true
mlw.cond.Broadcast()
return nil
}