forked from TrueCloudLab/distribution
Updates documentation to follow godoc conventions
This commit is contained in:
parent
ca0084fad1
commit
0e5d41ff9b
9 changed files with 84 additions and 64 deletions
|
@ -7,13 +7,14 @@ import (
|
|||
"github.com/docker/docker-registry/storagedriver/ipc"
|
||||
)
|
||||
|
||||
// Internal mapping between storage driver names and their respective factories
|
||||
// driverFactories stores an internal mapping between storage driver names and their respective
|
||||
// factories
|
||||
var driverFactories = make(map[string]StorageDriverFactory)
|
||||
|
||||
// Factory interface for the storagedriver.StorageDriver interface
|
||||
// StorageDriverFactory is a factory interface for creating storagedriver.StorageDriver interfaces
|
||||
// Storage drivers should call Register() with a factory to make the driver available by name
|
||||
type StorageDriverFactory interface {
|
||||
// Creates and returns a new storagedriver.StorageDriver with the given parameters
|
||||
// Create returns a new storagedriver.StorageDriver with the given parameters
|
||||
// Parameters will vary by driver and may be ignored
|
||||
// Each parameter key must only consist of lowercase letters and numbers
|
||||
Create(parameters map[string]string) (storagedriver.StorageDriver, error)
|
||||
|
@ -54,7 +55,7 @@ func Create(name string, parameters map[string]string) (storagedriver.StorageDri
|
|||
return driverFactory.Create(parameters)
|
||||
}
|
||||
|
||||
// Error returned when attempting to construct an unregistered storage driver
|
||||
// InvalidStorageDriverError records an attempt to construct an unregistered storage driver
|
||||
type InvalidStorageDriverError struct {
|
||||
Name string
|
||||
}
|
||||
|
|
|
@ -18,20 +18,20 @@ func init() {
|
|||
factory.Register(DriverName, &filesystemDriverFactory{})
|
||||
}
|
||||
|
||||
// Implements the factory.StorageDriverFactory interface
|
||||
// filesystemDriverFactory implements the factory.StorageDriverFactory interface
|
||||
type filesystemDriverFactory struct{}
|
||||
|
||||
func (factory *filesystemDriverFactory) Create(parameters map[string]string) (storagedriver.StorageDriver, error) {
|
||||
return FromParameters(parameters), nil
|
||||
}
|
||||
|
||||
// Storage Driver backed by a local filesystem
|
||||
// FilesystemDriver is a storagedriver.StorageDriver implementation backed by a local filesystem
|
||||
// All provided paths will be subpaths of the RootDirectory
|
||||
type FilesystemDriver struct {
|
||||
rootDirectory string
|
||||
}
|
||||
|
||||
// Constructs a new FilesystemDriver with a given parameters map
|
||||
// FromParameters constructs a new FilesystemDriver with a given parameters map
|
||||
// Optional Parameters:
|
||||
// - rootdirectory
|
||||
func FromParameters(parameters map[string]string) *FilesystemDriver {
|
||||
|
@ -45,11 +45,12 @@ func FromParameters(parameters map[string]string) *FilesystemDriver {
|
|||
return New(rootDirectory)
|
||||
}
|
||||
|
||||
// Constructs a new FilesystemDriver with a given rootDirectory
|
||||
// New constructs a new FilesystemDriver with a given rootDirectory
|
||||
func New(rootDirectory string) *FilesystemDriver {
|
||||
return &FilesystemDriver{rootDirectory}
|
||||
}
|
||||
|
||||
// subPath returns the absolute path of a key within the FilesystemDriver's storage
|
||||
func (d *FilesystemDriver) subPath(subPath string) string {
|
||||
return path.Join(d.rootDirectory, subPath)
|
||||
}
|
||||
|
|
|
@ -19,25 +19,27 @@ func init() {
|
|||
factory.Register(DriverName, &inMemoryDriverFactory{})
|
||||
}
|
||||
|
||||
// Implements the factory.StorageDriverFactory interface
|
||||
// inMemoryDriverFacotry implements the factory.StorageDriverFactory interface
|
||||
type inMemoryDriverFactory struct{}
|
||||
|
||||
func (factory *inMemoryDriverFactory) Create(parameters map[string]string) (storagedriver.StorageDriver, error) {
|
||||
return New(), nil
|
||||
}
|
||||
|
||||
// InMemory Storage Driver backed by a map
|
||||
// InMemoryDriver is a storagedriver.StorageDriver implementation backed by a local map
|
||||
// Intended solely for example and testing purposes
|
||||
type InMemoryDriver struct {
|
||||
storage map[string][]byte
|
||||
mutex sync.RWMutex
|
||||
}
|
||||
|
||||
// Constructs a new InMemoryDriver
|
||||
// New constructs a new InMemoryDriver
|
||||
func New() *InMemoryDriver {
|
||||
return &InMemoryDriver{storage: make(map[string][]byte)}
|
||||
}
|
||||
|
||||
// Implement the storagedriver.StorageDriver interface
|
||||
|
||||
func (d *InMemoryDriver) GetContent(path string) ([]byte, error) {
|
||||
d.mutex.RLock()
|
||||
defer d.mutex.RUnlock()
|
||||
|
|
|
@ -15,7 +15,8 @@ import (
|
|||
"github.com/docker/libchan/spdy"
|
||||
)
|
||||
|
||||
// Storage Driver implementation using a managed child process communicating over IPC
|
||||
// StorageDriverClient is a storagedriver.StorageDriver implementation using a managed child process
|
||||
// communicating over IPC using libchan with a unix domain socket
|
||||
type StorageDriverClient struct {
|
||||
subprocess *exec.Cmd
|
||||
socket *os.File
|
||||
|
@ -23,8 +24,9 @@ type StorageDriverClient struct {
|
|||
sender libchan.Sender
|
||||
}
|
||||
|
||||
// Constructs a new out-of-process storage driver using the driver name and configuration parameters
|
||||
// Must call Start() on this driver client before remote method calls can be made
|
||||
// NewDriverClient constructs a new out-of-process storage driver using the driver name and
|
||||
// configuration parameters
|
||||
// A user must call Start on this driver client before remote method calls can be made
|
||||
//
|
||||
// Looks for drivers in the following locations in order:
|
||||
// - Storage drivers directory (to be determined, yet not implemented)
|
||||
|
@ -54,7 +56,8 @@ func NewDriverClient(name string, parameters map[string]string) (*StorageDriverC
|
|||
}, nil
|
||||
}
|
||||
|
||||
// Starts the designated child process storage driver and binds a socket to this process for IPC
|
||||
// Start starts the designated child process storage driver and binds a socket to this process for
|
||||
// IPC method calls
|
||||
func (driver *StorageDriverClient) Start() error {
|
||||
fileDescriptors, err := syscall.Socketpair(syscall.AF_LOCAL, syscall.SOCK_STREAM, 0)
|
||||
if err != nil {
|
||||
|
@ -102,8 +105,8 @@ func (driver *StorageDriverClient) Start() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Stops the child process storage driver
|
||||
// storagedriver.StorageDriver methods called after Stop() will fail
|
||||
// Stop stops the child process storage driver
|
||||
// storagedriver.StorageDriver methods called after Stop will fail
|
||||
func (driver *StorageDriverClient) Stop() error {
|
||||
closeSenderErr := driver.sender.Close()
|
||||
closeTransportErr := driver.transport.Close()
|
||||
|
|
|
@ -10,7 +10,7 @@ import (
|
|||
"github.com/docker/libchan"
|
||||
)
|
||||
|
||||
// Defines a remote method call request
|
||||
// Request defines a remote method call request
|
||||
// A return value struct is to be sent over the ResponseChannel
|
||||
type Request struct {
|
||||
Type string
|
||||
|
@ -18,8 +18,9 @@ type Request struct {
|
|||
ResponseChannel libchan.Sender
|
||||
}
|
||||
|
||||
// A simple wrapper around an io.ReadCloser that implements the io.ReadWriteCloser interface
|
||||
// Writes are disallowed and will return an error if ever called
|
||||
// noWriteReadWriteCloser is a simple wrapper around an io.ReadCloser that implements the
|
||||
// io.ReadWriteCloser interface
|
||||
// Calls to Write are disallowed and will return an error
|
||||
type noWriteReadWriteCloser struct {
|
||||
io.ReadCloser
|
||||
}
|
||||
|
@ -28,7 +29,7 @@ func (r noWriteReadWriteCloser) Write(p []byte) (n int, err error) {
|
|||
return 0, errors.New("Write unsupported")
|
||||
}
|
||||
|
||||
// Wraps an io.Reader as an io.ReadWriteCloser with a nop Close and unsupported Write method
|
||||
// WrapReader wraps an io.Reader as an io.ReadWriteCloser with a nop Close and unsupported Write
|
||||
// Has no effect when an io.ReadWriteCloser is passed in
|
||||
func WrapReader(reader io.Reader) io.ReadWriteCloser {
|
||||
if readWriteCloser, ok := reader.(io.ReadWriteCloser); ok {
|
||||
|
@ -45,7 +46,7 @@ type responseError struct {
|
|||
Message string
|
||||
}
|
||||
|
||||
// Wraps an error in a serializable struct containing the error's type and message
|
||||
// ResponseError wraps an error in a serializable struct containing the error's type and message
|
||||
func ResponseError(err error) *responseError {
|
||||
if err == nil {
|
||||
return nil
|
||||
|
@ -62,35 +63,35 @@ func (err *responseError) Error() string {
|
|||
|
||||
// IPC method call response object definitions
|
||||
|
||||
// Response for a ReadStream request
|
||||
// ReadStreamResponse is a response for a ReadStream request
|
||||
type ReadStreamResponse struct {
|
||||
Reader io.ReadWriteCloser
|
||||
Error *responseError
|
||||
}
|
||||
|
||||
// Response for a WriteStream request
|
||||
// WriteStreamResponse is a response for a WriteStream request
|
||||
type WriteStreamResponse struct {
|
||||
Error *responseError
|
||||
}
|
||||
|
||||
// Response for a ResumeWritePosition request
|
||||
// ResumeWritePositionResponse is a response for a ResumeWritePosition request
|
||||
type ResumeWritePositionResponse struct {
|
||||
Position uint64
|
||||
Error *responseError
|
||||
}
|
||||
|
||||
// Response for a List request
|
||||
// ListResponse is a response for a List request
|
||||
type ListResponse struct {
|
||||
Keys []string
|
||||
Error *responseError
|
||||
}
|
||||
|
||||
// Response for a Move request
|
||||
// MoveResponse is a response for a Move request
|
||||
type MoveResponse struct {
|
||||
Error *responseError
|
||||
}
|
||||
|
||||
// Response for a Delete request
|
||||
// DeleteResponse is a response for a Delete request
|
||||
type DeleteResponse struct {
|
||||
Error *responseError
|
||||
}
|
||||
|
|
|
@ -13,10 +13,13 @@ import (
|
|||
"github.com/docker/libchan/spdy"
|
||||
)
|
||||
|
||||
// Construct a new IPC server handling requests for the given storagedriver.StorageDriver
|
||||
// This explicitly uses file descriptor 3 for IPC communication, as storage drivers are spawned in client.go
|
||||
// StorageDriverServer runs a new IPC server handling requests for the given
|
||||
// storagedriver.StorageDriver
|
||||
// This explicitly uses file descriptor 3 for IPC communication, as storage drivers are spawned in
|
||||
// client.go
|
||||
//
|
||||
// To create a new out-of-process driver, create a main package which calls StorageDriverServer with a storagedriver.StorageDriver
|
||||
// To create a new out-of-process driver, create a main package which calls StorageDriverServer with
|
||||
// a storagedriver.StorageDriver
|
||||
func StorageDriverServer(driver storagedriver.StorageDriver) error {
|
||||
childSocket := os.NewFile(3, "childSocket")
|
||||
defer childSocket.Close()
|
||||
|
@ -39,9 +42,10 @@ func StorageDriverServer(driver storagedriver.StorageDriver) error {
|
|||
}
|
||||
}
|
||||
|
||||
// Receives new storagedriver.StorageDriver method requests and creates a new goroutine to handle each request
|
||||
//
|
||||
// Requests are expected to be of type ipc.Request as the parameters are unknown until the request type is deserialized
|
||||
// receive receives new storagedriver.StorageDriver method requests and creates a new goroutine to
|
||||
// handle each request
|
||||
// Requests are expected to be of type ipc.Request as the parameters are unknown until the request
|
||||
// type is deserialized
|
||||
func receive(driver storagedriver.StorageDriver, receiver libchan.Receiver) {
|
||||
for {
|
||||
var request Request
|
||||
|
@ -53,7 +57,7 @@ func receive(driver storagedriver.StorageDriver, receiver libchan.Receiver) {
|
|||
}
|
||||
}
|
||||
|
||||
// Handles storagedriver.StorageDriver method requests as defined in client.go
|
||||
// handleRequest handles storagedriver.StorageDriver method requests as defined in client.go
|
||||
// Responds to requests using the Request.ResponseChannel
|
||||
func handleRequest(driver storagedriver.StorageDriver, request Request) {
|
||||
switch request.Type {
|
||||
|
|
|
@ -15,24 +15,25 @@ import (
|
|||
|
||||
const DriverName = "s3"
|
||||
|
||||
// Chunks need to be at least 5MB to store with a multipart upload on S3
|
||||
// minChunkSize defines the minimum multipart upload chunk size
|
||||
// S3 API requires multipart upload chunks to be at least 5MB
|
||||
const minChunkSize = uint64(5 * 1024 * 1024)
|
||||
|
||||
// The largest amount of parts you can request from S3
|
||||
// listPartsMax is the largest amount of parts you can request from S3
|
||||
const listPartsMax = 1000
|
||||
|
||||
func init() {
|
||||
factory.Register(DriverName, &s3DriverFactory{})
|
||||
}
|
||||
|
||||
// Implements the factory.StorageDriverFactory interface
|
||||
// s3DriverFactory implements the factory.StorageDriverFactory interface
|
||||
type s3DriverFactory struct{}
|
||||
|
||||
func (factory *s3DriverFactory) Create(parameters map[string]string) (storagedriver.StorageDriver, error) {
|
||||
return FromParameters(parameters)
|
||||
}
|
||||
|
||||
// Storage Driver backed by Amazon S3
|
||||
// S3Driver is a storagedriver.StorageDriver implementation backed by Amazon S3
|
||||
// Objects are stored at absolute keys in the provided bucket
|
||||
type S3Driver struct {
|
||||
S3 *s3.S3
|
||||
|
@ -40,7 +41,7 @@ type S3Driver struct {
|
|||
Encrypt bool
|
||||
}
|
||||
|
||||
// Constructs a new S3Driver with a given parameters map
|
||||
// FromParameters constructs a new S3Driver with a given parameters map
|
||||
// Required parameters:
|
||||
// - accesskey
|
||||
// - secretkey
|
||||
|
@ -84,7 +85,8 @@ func FromParameters(parameters map[string]string) (*S3Driver, error) {
|
|||
return New(accessKey, secretKey, region, encryptBool, bucket)
|
||||
}
|
||||
|
||||
// Constructs a new S3Driver with the given AWS credentials, region, encryption flag, and bucketName
|
||||
// New constructs a new S3Driver with the given AWS credentials, region, encryption flag, and
|
||||
// bucketName
|
||||
func New(accessKey string, secretKey string, region aws.Region, encrypt bool, bucketName string) (*S3Driver, error) {
|
||||
auth := aws.Auth{AccessKey: accessKey, SecretKey: secretKey}
|
||||
s3obj := s3.New(auth, region)
|
||||
|
@ -100,6 +102,8 @@ func New(accessKey string, secretKey string, region aws.Region, encrypt bool, bu
|
|||
return &S3Driver{s3obj, bucket, encrypt}, nil
|
||||
}
|
||||
|
||||
// Implement the storagedriver.StorageDriver interface
|
||||
|
||||
func (d *S3Driver) GetContent(path string) ([]byte, error) {
|
||||
return d.Bucket.Get(path)
|
||||
}
|
||||
|
|
|
@ -5,41 +5,45 @@ import (
|
|||
"io"
|
||||
)
|
||||
|
||||
// Defines methods that a Storage Driver must implement for a filesystem-like key/value object storage
|
||||
// StorageDriver defines methods that a Storage Driver must implement for a filesystem-like
|
||||
// key/value object storage
|
||||
type StorageDriver interface {
|
||||
// Retrieve the content stored at "path" as a []byte
|
||||
// GetContent retrieves the content stored at "path" as a []byte
|
||||
// Should primarily be used for small objects
|
||||
GetContent(path string) ([]byte, error)
|
||||
|
||||
// Store the []byte content at a location designated by "path"
|
||||
// PutContent stores the []byte content at a location designated by "path"
|
||||
// Should primarily be used for small objects
|
||||
PutContent(path string, content []byte) error
|
||||
|
||||
// Retrieve an io.ReadCloser for the content stored at "path" with a given byte offset
|
||||
// ReadStream retrieves an io.ReadCloser for the content stored at "path" with a given byte
|
||||
// offset
|
||||
// May be used to resume reading a stream by providing a nonzero offset
|
||||
ReadStream(path string, offset uint64) (io.ReadCloser, error)
|
||||
|
||||
// Store the contents of the provided io.ReadCloser at a location designated by "path"
|
||||
// WriteStream stores the contents of the provided io.ReadCloser at a location designated by
|
||||
// the given path
|
||||
// The driver will know it has received the full contents when it has read "size" bytes
|
||||
// May be used to resume writing a stream by providing a nonzero offset
|
||||
// The offset must be no larger than the number of bytes already written to this path
|
||||
WriteStream(path string, offset, size uint64, readCloser io.ReadCloser) error
|
||||
|
||||
// Retrieve the byte offset at which it is safe to continue writing at "path"
|
||||
// ResumeWritePosition retrieves the byte offset at which it is safe to continue writing at the
|
||||
// given path
|
||||
ResumeWritePosition(path string) (uint64, error)
|
||||
|
||||
// Recursively lists the objects stored at a subpath of the given prefix
|
||||
// List recursively lists the objects stored at a subpath of the given prefix
|
||||
List(prefix string) ([]string, error)
|
||||
|
||||
// Moves an object stored at sourcePath to destPath, removing the original object
|
||||
// Move moves an object stored at sourcePath to destPath, removing the original object
|
||||
// Note: This may be no more efficient than a copy followed by a delete for many implementations
|
||||
Move(sourcePath string, destPath string) error
|
||||
|
||||
// Recursively deletes all objects stored at "path" and its subpaths
|
||||
// Delete recursively deletes all objects stored at "path" and its subpaths
|
||||
Delete(path string) error
|
||||
}
|
||||
|
||||
// Error returned when operating on a nonexistent path
|
||||
// PathNotFoundError is returned when operating on a nonexistent path
|
||||
type PathNotFoundError struct {
|
||||
Path string
|
||||
}
|
||||
|
@ -48,7 +52,7 @@ func (err PathNotFoundError) Error() string {
|
|||
return fmt.Sprintf("Path not found: %s", err.Path)
|
||||
}
|
||||
|
||||
// Error returned when attempting to read or write from an invalid offset
|
||||
// InvalidOffsetError is returned when attempting to read or write from an invalid offset
|
||||
type InvalidOffsetError struct {
|
||||
Path string
|
||||
Offset uint64
|
||||
|
|
|
@ -17,9 +17,7 @@ import (
|
|||
// Hook up gocheck into the "go test" runner
|
||||
func Test(t *testing.T) { TestingT(t) }
|
||||
|
||||
// Registers an in-process storage driver test suite with the go test runner
|
||||
//
|
||||
// If skipCheck returns a non-empty skip reason, the suite is skipped with the given reason
|
||||
// RegisterInProcessSuite registers an in-process storage driver test suite with the go test runner
|
||||
func RegisterInProcessSuite(driverConstructor DriverConstructor, skipCheck SkipCheck) {
|
||||
Suite(&DriverSuite{
|
||||
Constructor: driverConstructor,
|
||||
|
@ -27,9 +25,8 @@ func RegisterInProcessSuite(driverConstructor DriverConstructor, skipCheck SkipC
|
|||
})
|
||||
}
|
||||
|
||||
// Registers a storage driver test suite which runs the named driver as a child process with the given parameters
|
||||
//
|
||||
// If skipCheck returns a non-empty skip reason, the suite is skipped with the given reason
|
||||
// RegisterIPCSuite registers a storage driver test suite which runs the named driver as a child
|
||||
// process with the given parameters
|
||||
func RegisterIPCSuite(driverName string, ipcParams map[string]string, skipCheck SkipCheck) {
|
||||
suite := &DriverSuite{
|
||||
Constructor: func() (storagedriver.StorageDriver, error) {
|
||||
|
@ -56,13 +53,21 @@ func RegisterIPCSuite(driverName string, ipcParams map[string]string, skipCheck
|
|||
Suite(suite)
|
||||
}
|
||||
|
||||
// SkipCheck is a function used to determine if a test suite should be skipped
|
||||
// If a SkipCheck returns a non-empty skip reason, the suite is skipped with the given reason
|
||||
type SkipCheck func() (reason string)
|
||||
|
||||
var NeverSkip = func() string { return "" }
|
||||
// NeverSkip is a default SkipCheck which never skips the suite
|
||||
var NeverSkip SkipCheck = func() string { return "" }
|
||||
|
||||
// DriverConstructor is a function which returns a new storagedriver.StorageDriver
|
||||
type DriverConstructor func() (storagedriver.StorageDriver, error)
|
||||
|
||||
// DriverTeardown is a function which cleans up a suite's storagedriver.StorageDriver
|
||||
type DriverTeardown func() error
|
||||
|
||||
// DriverSuite is a gocheck test suite designed to test a storagedriver.StorageDriver
|
||||
// The intended way to create a DriverSuite is with RegisterInProcessSuite or RegisterIPCSuite
|
||||
type DriverSuite struct {
|
||||
Constructor DriverConstructor
|
||||
Teardown DriverTeardown
|
||||
|
@ -70,11 +75,6 @@ type DriverSuite struct {
|
|||
storagedriver.StorageDriver
|
||||
}
|
||||
|
||||
type TestDriverConfig struct {
|
||||
name string
|
||||
params map[string]string
|
||||
}
|
||||
|
||||
func (suite *DriverSuite) SetUpSuite(c *C) {
|
||||
if reason := suite.SkipCheck(); reason != "" {
|
||||
c.Skip(reason)
|
||||
|
|
Loading…
Reference in a new issue