Updates documentation to follow godoc conventions
							parent
							
								
									ca0084fad1
								
							
						
					
					
						commit
						0e5d41ff9b
					
				|  | @ -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 New Issue