Adds versioning for out-of-process storage driver

The registry currently only accepts storage driver versions with the
same major version and an equal or lower minor version as its own
current storage driver api version, but this may be changed in the
future if we decide to implement specific version cross-compatibility.
This commit is contained in:
Brian Bland 2014-11-06 12:16:14 -08:00
parent f02cfee950
commit 1ae5485998
5 changed files with 106 additions and 17 deletions

View file

@ -11,6 +11,7 @@ import (
"path"
"syscall"
"github.com/docker/docker-registry/storagedriver"
"github.com/docker/libchan"
"github.com/docker/libchan/spdy"
)
@ -22,6 +23,7 @@ type StorageDriverClient struct {
socket *os.File
transport *spdy.Transport
sender libchan.Sender
version storagedriver.Version
}
// NewDriverClient constructs a new out-of-process storage driver using the driver name and
@ -65,42 +67,62 @@ func (driver *StorageDriverClient) Start() error {
}
childSocket := os.NewFile(uintptr(fileDescriptors[0]), "childSocket")
parentSocket := os.NewFile(uintptr(fileDescriptors[1]), "parentSocket")
driver.socket = os.NewFile(uintptr(fileDescriptors[1]), "parentSocket")
driver.subprocess.Stdout = os.Stdout
driver.subprocess.Stderr = os.Stderr
driver.subprocess.ExtraFiles = []*os.File{childSocket}
if err = driver.subprocess.Start(); err != nil {
parentSocket.Close()
driver.Stop()
return err
}
if err = childSocket.Close(); err != nil {
parentSocket.Close()
driver.Stop()
return err
}
connection, err := net.FileConn(parentSocket)
connection, err := net.FileConn(driver.socket)
if err != nil {
parentSocket.Close()
driver.Stop()
return err
}
transport, err := spdy.NewClientTransport(connection)
driver.transport, err = spdy.NewClientTransport(connection)
if err != nil {
parentSocket.Close()
driver.Stop()
return err
}
sender, err := transport.NewSendChannel()
driver.sender, err = driver.transport.NewSendChannel()
if err != nil {
transport.Close()
parentSocket.Close()
driver.Stop()
return err
}
driver.socket = parentSocket
driver.transport = transport
driver.sender = sender
// Check the driver's version to determine compatibility
receiver, remoteSender := libchan.Pipe()
err = driver.sender.Send(&Request{Type: "Version", ResponseChannel: remoteSender})
if err != nil {
driver.Stop()
return err
}
var response VersionResponse
err = receiver.Receive(&response)
if err != nil {
driver.Stop()
return err
}
if response.Error != nil {
return response.Error
}
driver.version = response.Version
if driver.version.Major() != storagedriver.CurrentVersion.Major() || driver.version.Minor() > storagedriver.CurrentVersion.Minor() {
return IncompatibleVersionError{driver.version}
}
return nil
}
@ -108,10 +130,20 @@ func (driver *StorageDriverClient) Start() error {
// 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()
closeSocketErr := driver.socket.Close()
killErr := driver.subprocess.Process.Kill()
var closeSenderErr, closeTransportErr, closeSocketErr, killErr error
if driver.sender != nil {
closeSenderErr = driver.sender.Close()
}
if driver.transport != nil {
closeTransportErr = driver.transport.Close()
}
if driver.socket != nil {
closeSocketErr = driver.socket.Close()
}
if driver.subprocess != nil {
killErr = driver.subprocess.Process.Kill()
}
if closeSenderErr != nil {
return closeSenderErr