diff --git a/storagedriver/factory/factory.go b/storagedriver/factory/factory.go index c13c6c1e..0b85f372 100644 --- a/storagedriver/factory/factory.go +++ b/storagedriver/factory/factory.go @@ -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 } diff --git a/storagedriver/filesystem/filesystem.go b/storagedriver/filesystem/filesystem.go index 27ffcf7a..4f100dd3 100644 --- a/storagedriver/filesystem/filesystem.go +++ b/storagedriver/filesystem/filesystem.go @@ -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) } diff --git a/storagedriver/inmemory/inmemory.go b/storagedriver/inmemory/inmemory.go index 2cf1b9f4..d7d4ccea 100644 --- a/storagedriver/inmemory/inmemory.go +++ b/storagedriver/inmemory/inmemory.go @@ -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() diff --git a/storagedriver/ipc/client.go b/storagedriver/ipc/client.go index 6327b156..cdac8b11 100644 --- a/storagedriver/ipc/client.go +++ b/storagedriver/ipc/client.go @@ -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() diff --git a/storagedriver/ipc/ipc.go b/storagedriver/ipc/ipc.go index 4e7e65c7..30f63393 100644 --- a/storagedriver/ipc/ipc.go +++ b/storagedriver/ipc/ipc.go @@ -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 } diff --git a/storagedriver/ipc/server.go b/storagedriver/ipc/server.go index 0af41d0a..81432cc3 100644 --- a/storagedriver/ipc/server.go +++ b/storagedriver/ipc/server.go @@ -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 { diff --git a/storagedriver/s3/s3.go b/storagedriver/s3/s3.go index 0c301126..5338a276 100644 --- a/storagedriver/s3/s3.go +++ b/storagedriver/s3/s3.go @@ -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) } diff --git a/storagedriver/storagedriver.go b/storagedriver/storagedriver.go index 55596cd6..d03fec0c 100644 --- a/storagedriver/storagedriver.go +++ b/storagedriver/storagedriver.go @@ -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 diff --git a/storagedriver/testsuites/testsuites.go b/storagedriver/testsuites/testsuites.go index 45c621d3..94d85461 100644 --- a/storagedriver/testsuites/testsuites.go +++ b/storagedriver/testsuites/testsuites.go @@ -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)