Updates documentation to follow godoc conventions

This commit is contained in:
Brian Bland 2014-10-29 12:14:19 -07:00
parent ca0084fad1
commit 0e5d41ff9b
9 changed files with 84 additions and 64 deletions

View file

@ -7,13 +7,14 @@ import (
"github.com/docker/docker-registry/storagedriver/ipc" "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) 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 // Storage drivers should call Register() with a factory to make the driver available by name
type StorageDriverFactory interface { 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 // Parameters will vary by driver and may be ignored
// Each parameter key must only consist of lowercase letters and numbers // Each parameter key must only consist of lowercase letters and numbers
Create(parameters map[string]string) (storagedriver.StorageDriver, error) 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) 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 { type InvalidStorageDriverError struct {
Name string Name string
} }

View file

@ -18,20 +18,20 @@ func init() {
factory.Register(DriverName, &filesystemDriverFactory{}) factory.Register(DriverName, &filesystemDriverFactory{})
} }
// Implements the factory.StorageDriverFactory interface // filesystemDriverFactory implements the factory.StorageDriverFactory interface
type filesystemDriverFactory struct{} type filesystemDriverFactory struct{}
func (factory *filesystemDriverFactory) Create(parameters map[string]string) (storagedriver.StorageDriver, error) { func (factory *filesystemDriverFactory) Create(parameters map[string]string) (storagedriver.StorageDriver, error) {
return FromParameters(parameters), nil 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 // All provided paths will be subpaths of the RootDirectory
type FilesystemDriver struct { type FilesystemDriver struct {
rootDirectory string rootDirectory string
} }
// Constructs a new FilesystemDriver with a given parameters map // FromParameters constructs a new FilesystemDriver with a given parameters map
// Optional Parameters: // Optional Parameters:
// - rootdirectory // - rootdirectory
func FromParameters(parameters map[string]string) *FilesystemDriver { func FromParameters(parameters map[string]string) *FilesystemDriver {
@ -45,11 +45,12 @@ func FromParameters(parameters map[string]string) *FilesystemDriver {
return New(rootDirectory) 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 { func New(rootDirectory string) *FilesystemDriver {
return &FilesystemDriver{rootDirectory} return &FilesystemDriver{rootDirectory}
} }
// subPath returns the absolute path of a key within the FilesystemDriver's storage
func (d *FilesystemDriver) subPath(subPath string) string { func (d *FilesystemDriver) subPath(subPath string) string {
return path.Join(d.rootDirectory, subPath) return path.Join(d.rootDirectory, subPath)
} }

View file

@ -19,25 +19,27 @@ func init() {
factory.Register(DriverName, &inMemoryDriverFactory{}) factory.Register(DriverName, &inMemoryDriverFactory{})
} }
// Implements the factory.StorageDriverFactory interface // inMemoryDriverFacotry implements the factory.StorageDriverFactory interface
type inMemoryDriverFactory struct{} type inMemoryDriverFactory struct{}
func (factory *inMemoryDriverFactory) Create(parameters map[string]string) (storagedriver.StorageDriver, error) { func (factory *inMemoryDriverFactory) Create(parameters map[string]string) (storagedriver.StorageDriver, error) {
return New(), nil 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 // Intended solely for example and testing purposes
type InMemoryDriver struct { type InMemoryDriver struct {
storage map[string][]byte storage map[string][]byte
mutex sync.RWMutex mutex sync.RWMutex
} }
// Constructs a new InMemoryDriver // New constructs a new InMemoryDriver
func New() *InMemoryDriver { func New() *InMemoryDriver {
return &InMemoryDriver{storage: make(map[string][]byte)} return &InMemoryDriver{storage: make(map[string][]byte)}
} }
// Implement the storagedriver.StorageDriver interface
func (d *InMemoryDriver) GetContent(path string) ([]byte, error) { func (d *InMemoryDriver) GetContent(path string) ([]byte, error) {
d.mutex.RLock() d.mutex.RLock()
defer d.mutex.RUnlock() defer d.mutex.RUnlock()

View file

@ -15,7 +15,8 @@ import (
"github.com/docker/libchan/spdy" "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 { type StorageDriverClient struct {
subprocess *exec.Cmd subprocess *exec.Cmd
socket *os.File socket *os.File
@ -23,8 +24,9 @@ type StorageDriverClient struct {
sender libchan.Sender sender libchan.Sender
} }
// Constructs a new out-of-process storage driver using the driver name and configuration parameters // NewDriverClient constructs a new out-of-process storage driver using the driver name and
// Must call Start() on this driver client before remote method calls can be made // 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: // Looks for drivers in the following locations in order:
// - Storage drivers directory (to be determined, yet not implemented) // - Storage drivers directory (to be determined, yet not implemented)
@ -54,7 +56,8 @@ func NewDriverClient(name string, parameters map[string]string) (*StorageDriverC
}, nil }, 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 { func (driver *StorageDriverClient) Start() error {
fileDescriptors, err := syscall.Socketpair(syscall.AF_LOCAL, syscall.SOCK_STREAM, 0) fileDescriptors, err := syscall.Socketpair(syscall.AF_LOCAL, syscall.SOCK_STREAM, 0)
if err != nil { if err != nil {
@ -102,8 +105,8 @@ func (driver *StorageDriverClient) Start() error {
return nil return nil
} }
// Stops the child process storage driver // Stop stops the child process storage driver
// storagedriver.StorageDriver methods called after Stop() will fail // storagedriver.StorageDriver methods called after Stop will fail
func (driver *StorageDriverClient) Stop() error { func (driver *StorageDriverClient) Stop() error {
closeSenderErr := driver.sender.Close() closeSenderErr := driver.sender.Close()
closeTransportErr := driver.transport.Close() closeTransportErr := driver.transport.Close()

View file

@ -10,7 +10,7 @@ import (
"github.com/docker/libchan" "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 // A return value struct is to be sent over the ResponseChannel
type Request struct { type Request struct {
Type string Type string
@ -18,8 +18,9 @@ type Request struct {
ResponseChannel libchan.Sender ResponseChannel libchan.Sender
} }
// A simple wrapper around an io.ReadCloser that implements the io.ReadWriteCloser interface // noWriteReadWriteCloser is a simple wrapper around an io.ReadCloser that implements the
// Writes are disallowed and will return an error if ever called // io.ReadWriteCloser interface
// Calls to Write are disallowed and will return an error
type noWriteReadWriteCloser struct { type noWriteReadWriteCloser struct {
io.ReadCloser io.ReadCloser
} }
@ -28,7 +29,7 @@ func (r noWriteReadWriteCloser) Write(p []byte) (n int, err error) {
return 0, errors.New("Write unsupported") 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 // Has no effect when an io.ReadWriteCloser is passed in
func WrapReader(reader io.Reader) io.ReadWriteCloser { func WrapReader(reader io.Reader) io.ReadWriteCloser {
if readWriteCloser, ok := reader.(io.ReadWriteCloser); ok { if readWriteCloser, ok := reader.(io.ReadWriteCloser); ok {
@ -45,7 +46,7 @@ type responseError struct {
Message string 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 { func ResponseError(err error) *responseError {
if err == nil { if err == nil {
return nil return nil
@ -62,35 +63,35 @@ func (err *responseError) Error() string {
// IPC method call response object definitions // IPC method call response object definitions
// Response for a ReadStream request // ReadStreamResponse is a response for a ReadStream request
type ReadStreamResponse struct { type ReadStreamResponse struct {
Reader io.ReadWriteCloser Reader io.ReadWriteCloser
Error *responseError Error *responseError
} }
// Response for a WriteStream request // WriteStreamResponse is a response for a WriteStream request
type WriteStreamResponse struct { type WriteStreamResponse struct {
Error *responseError Error *responseError
} }
// Response for a ResumeWritePosition request // ResumeWritePositionResponse is a response for a ResumeWritePosition request
type ResumeWritePositionResponse struct { type ResumeWritePositionResponse struct {
Position uint64 Position uint64
Error *responseError Error *responseError
} }
// Response for a List request // ListResponse is a response for a List request
type ListResponse struct { type ListResponse struct {
Keys []string Keys []string
Error *responseError Error *responseError
} }
// Response for a Move request // MoveResponse is a response for a Move request
type MoveResponse struct { type MoveResponse struct {
Error *responseError Error *responseError
} }
// Response for a Delete request // DeleteResponse is a response for a Delete request
type DeleteResponse struct { type DeleteResponse struct {
Error *responseError Error *responseError
} }

View file

@ -13,10 +13,13 @@ import (
"github.com/docker/libchan/spdy" "github.com/docker/libchan/spdy"
) )
// Construct a new IPC server handling requests for the given storagedriver.StorageDriver // StorageDriverServer runs a new IPC server handling requests for the given
// This explicitly uses file descriptor 3 for IPC communication, as storage drivers are spawned in client.go // 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 { func StorageDriverServer(driver storagedriver.StorageDriver) error {
childSocket := os.NewFile(3, "childSocket") childSocket := os.NewFile(3, "childSocket")
defer childSocket.Close() 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 // 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 // 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) { func receive(driver storagedriver.StorageDriver, receiver libchan.Receiver) {
for { for {
var request Request 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 // Responds to requests using the Request.ResponseChannel
func handleRequest(driver storagedriver.StorageDriver, request Request) { func handleRequest(driver storagedriver.StorageDriver, request Request) {
switch request.Type { switch request.Type {

View file

@ -15,24 +15,25 @@ import (
const DriverName = "s3" 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) 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 const listPartsMax = 1000
func init() { func init() {
factory.Register(DriverName, &s3DriverFactory{}) factory.Register(DriverName, &s3DriverFactory{})
} }
// Implements the factory.StorageDriverFactory interface // s3DriverFactory implements the factory.StorageDriverFactory interface
type s3DriverFactory struct{} type s3DriverFactory struct{}
func (factory *s3DriverFactory) Create(parameters map[string]string) (storagedriver.StorageDriver, error) { func (factory *s3DriverFactory) Create(parameters map[string]string) (storagedriver.StorageDriver, error) {
return FromParameters(parameters) 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 // Objects are stored at absolute keys in the provided bucket
type S3Driver struct { type S3Driver struct {
S3 *s3.S3 S3 *s3.S3
@ -40,7 +41,7 @@ type S3Driver struct {
Encrypt bool Encrypt bool
} }
// Constructs a new S3Driver with a given parameters map // FromParameters constructs a new S3Driver with a given parameters map
// Required parameters: // Required parameters:
// - accesskey // - accesskey
// - secretkey // - secretkey
@ -84,7 +85,8 @@ func FromParameters(parameters map[string]string) (*S3Driver, error) {
return New(accessKey, secretKey, region, encryptBool, bucket) 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) { func New(accessKey string, secretKey string, region aws.Region, encrypt bool, bucketName string) (*S3Driver, error) {
auth := aws.Auth{AccessKey: accessKey, SecretKey: secretKey} auth := aws.Auth{AccessKey: accessKey, SecretKey: secretKey}
s3obj := s3.New(auth, region) 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 return &S3Driver{s3obj, bucket, encrypt}, nil
} }
// Implement the storagedriver.StorageDriver interface
func (d *S3Driver) GetContent(path string) ([]byte, error) { func (d *S3Driver) GetContent(path string) ([]byte, error) {
return d.Bucket.Get(path) return d.Bucket.Get(path)
} }

View file

@ -5,41 +5,45 @@ import (
"io" "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 { 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 // Should primarily be used for small objects
GetContent(path string) ([]byte, error) 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 // Should primarily be used for small objects
PutContent(path string, content []byte) error 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 // May be used to resume reading a stream by providing a nonzero offset
ReadStream(path string, offset uint64) (io.ReadCloser, error) 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 // 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 // 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 // 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 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) 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) 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 // Note: This may be no more efficient than a copy followed by a delete for many implementations
Move(sourcePath string, destPath string) error 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 Delete(path string) error
} }
// Error returned when operating on a nonexistent path // PathNotFoundError is returned when operating on a nonexistent path
type PathNotFoundError struct { type PathNotFoundError struct {
Path string Path string
} }
@ -48,7 +52,7 @@ func (err PathNotFoundError) Error() string {
return fmt.Sprintf("Path not found: %s", err.Path) 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 { type InvalidOffsetError struct {
Path string Path string
Offset uint64 Offset uint64

View file

@ -17,9 +17,7 @@ import (
// Hook up gocheck into the "go test" runner // Hook up gocheck into the "go test" runner
func Test(t *testing.T) { TestingT(t) } func Test(t *testing.T) { TestingT(t) }
// Registers an in-process storage driver test suite with the go test runner // RegisterInProcessSuite 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
func RegisterInProcessSuite(driverConstructor DriverConstructor, skipCheck SkipCheck) { func RegisterInProcessSuite(driverConstructor DriverConstructor, skipCheck SkipCheck) {
Suite(&DriverSuite{ Suite(&DriverSuite{
Constructor: driverConstructor, 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 // RegisterIPCSuite 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
func RegisterIPCSuite(driverName string, ipcParams map[string]string, skipCheck SkipCheck) { func RegisterIPCSuite(driverName string, ipcParams map[string]string, skipCheck SkipCheck) {
suite := &DriverSuite{ suite := &DriverSuite{
Constructor: func() (storagedriver.StorageDriver, error) { Constructor: func() (storagedriver.StorageDriver, error) {
@ -56,13 +53,21 @@ func RegisterIPCSuite(driverName string, ipcParams map[string]string, skipCheck
Suite(suite) 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) 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) type DriverConstructor func() (storagedriver.StorageDriver, error)
// DriverTeardown is a function which cleans up a suite's storagedriver.StorageDriver
type DriverTeardown func() error 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 { type DriverSuite struct {
Constructor DriverConstructor Constructor DriverConstructor
Teardown DriverTeardown Teardown DriverTeardown
@ -70,11 +75,6 @@ type DriverSuite struct {
storagedriver.StorageDriver storagedriver.StorageDriver
} }
type TestDriverConfig struct {
name string
params map[string]string
}
func (suite *DriverSuite) SetUpSuite(c *C) { func (suite *DriverSuite) SetUpSuite(c *C) {
if reason := suite.SkipCheck(); reason != "" { if reason := suite.SkipCheck(); reason != "" {
c.Skip(reason) c.Skip(reason)