1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Remote Driver integration with Plugin Framework

This commit brings in Remote driver integrated with the newly introduced
Plugin framework as a Docker Package.

The Plugin framework is designed as a Package and has no runtime
dependancy on Docker platform. It stands on its own and is a good
candidate for getting the remote drivers hooked to libnetwork

Signed-off-by: Madhu Venugopal <madhu@docker.com>
This commit is contained in:
Madhu Venugopal 2015-05-15 18:14:36 -07:00
parent cb8bbd3ded
commit 80ca3c2330
4 changed files with 141 additions and 23 deletions

View file

@ -48,6 +48,7 @@ package libnetwork
import (
"sync"
"github.com/docker/docker/pkg/plugins"
"github.com/docker/docker/pkg/stringid"
"github.com/docker/libnetwork/driverapi"
"github.com/docker/libnetwork/sandbox"
@ -140,7 +141,11 @@ func (c *controller) NewNetwork(networkType, name string, options ...NetworkOpti
d, ok := c.drivers[networkType]
c.Unlock()
if !ok {
return nil, ErrInvalidNetworkDriver
var err error
d, err = c.loadDriver(networkType)
if err != nil {
return nil, err
}
}
// Check if a network already exists with the specified network name
@ -275,3 +280,19 @@ func (c *controller) sandboxGet(key string) sandbox.Sandbox {
return sData.sandbox
}
func (c *controller) loadDriver(networkType string) (driverapi.Driver, error) {
// Plugins pkg performs lazy loading of plugins that acts as remote drivers.
// As per the design, this Get call will result in remote driver discovery if there is a corresponding plugin available.
_, err := plugins.Get(networkType, driverapi.NetworkPluginEndpointType)
if err != nil {
return nil, err
}
c.Lock()
defer c.Unlock()
d, ok := c.drivers[networkType]
if !ok {
return nil, ErrInvalidNetworkDriver
}
return d, nil
}

View file

@ -19,6 +19,9 @@ var (
ErrNotImplemented = errors.New("The API is not implemented yet")
)
// NetworkPluginEndpointType represents the Endpoint Type used by Plugin system
const NetworkPluginEndpointType = "NetworkDriver"
// Driver is an interface that every plugin driver needs to implement.
type Driver interface {
// Push driver specific config to the driver

View file

@ -3,6 +3,8 @@ package remote
import (
"errors"
log "github.com/Sirupsen/logrus"
"github.com/docker/docker/pkg/plugins"
"github.com/docker/libnetwork/driverapi"
"github.com/docker/libnetwork/sandbox"
"github.com/docker/libnetwork/types"
@ -10,13 +12,22 @@ import (
var errNoCallback = errors.New("No Callback handler registered with Driver")
const remoteNetworkType = "remote"
type driver struct {
endpoint *plugins.Client
networkType string
}
// Init does the necessary work to register remote drivers
func Init(dc driverapi.DriverCallback) error {
plugins.Handle(driverapi.NetworkPluginEndpointType, func(name string, client *plugins.Client) {
// TODO : Handhake with the Remote Plugin goes here
newDriver := &driver{networkType: name, endpoint: client}
if err := dc.RegisterDriver(name, newDriver); err != nil {
log.Errorf("Error registering Driver for %s due to %v", name, err)
}
})
return nil
}
@ -55,5 +66,5 @@ func (d *driver) Leave(nid, eid types.UUID, options map[string]interface{}) erro
}
func (d *driver) Type() string {
return remoteNetworkType
return d.networkType
}

View file

@ -6,6 +6,8 @@ import (
"fmt"
"io/ioutil"
"net"
"net/http"
"net/http/httptest"
"os"
"runtime"
"strconv"
@ -13,8 +15,10 @@ import (
"testing"
log "github.com/Sirupsen/logrus"
"github.com/docker/docker/pkg/plugins"
"github.com/docker/docker/pkg/reexec"
"github.com/docker/libnetwork"
"github.com/docker/libnetwork/driverapi"
"github.com/docker/libnetwork/netlabel"
"github.com/docker/libnetwork/netutils"
"github.com/docker/libnetwork/options"
@ -226,7 +230,7 @@ func TestUnknownDriver(t *testing.T) {
}
}
func TestNilDriver(t *testing.T) {
func TestNilRemoteDriver(t *testing.T) {
controller, err := libnetwork.New()
if err != nil {
t.Fatal(err)
@ -238,24 +242,7 @@ func TestNilDriver(t *testing.T) {
t.Fatal("Expected to fail. But instead succeeded")
}
if err != libnetwork.ErrInvalidNetworkDriver {
t.Fatalf("Did not fail with expected error. Actual error: %v", err)
}
}
func TestNoInitDriver(t *testing.T) {
controller, err := libnetwork.New()
if err != nil {
t.Fatal(err)
}
_, err = controller.NewNetwork("ppp", "dummy",
libnetwork.NetworkOptionGeneric(getEmptyGenericOption()))
if err == nil {
t.Fatal("Expected to fail. But instead succeeded")
}
if err != libnetwork.ErrInvalidNetworkDriver {
if err != plugins.ErrNotFound {
t.Fatalf("Did not fail with expected error. Actual error: %v", err)
}
}
@ -1134,6 +1121,102 @@ func TestResolvConf(t *testing.T) {
}
}
func TestInvalidRemoteDriver(t *testing.T) {
if !netutils.IsRunningInContainer() {
t.Skip("Skipping test when not running inside a Container")
}
mux := http.NewServeMux()
server := httptest.NewServer(mux)
if server == nil {
t.Fatal("Failed to start a HTTP Server")
}
defer server.Close()
type pluginRequest struct {
name string
}
mux.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
fmt.Fprintln(w, `{"Implements": ["InvalidDriver"]}`)
})
if err := os.MkdirAll("/usr/share/docker/plugins", 0755); err != nil {
t.Fatal(err)
}
defer func() {
if err := os.RemoveAll("/usr/share/docker/plugins"); err != nil {
t.Fatal(err)
}
}()
if err := ioutil.WriteFile("/usr/share/docker/plugins/invalid-network-driver.spec", []byte(server.URL), 0644); err != nil {
t.Fatal(err)
}
controller, err := libnetwork.New()
if err != nil {
t.Fatal(err)
}
_, err = controller.NewNetwork("invalid-network-driver", "dummy",
libnetwork.NetworkOptionGeneric(getEmptyGenericOption()))
if err == nil {
t.Fatal("Expected to fail. But instead succeeded")
}
if err != plugins.ErrNotImplements {
t.Fatalf("Did not fail with expected error. Actual error: %v", err)
}
}
func TestValidRemoteDriver(t *testing.T) {
if !netutils.IsRunningInContainer() {
t.Skip("Skipping test when not running inside a Container")
}
mux := http.NewServeMux()
server := httptest.NewServer(mux)
if server == nil {
t.Fatal("Failed to start a HTTP Server")
}
defer server.Close()
type pluginRequest struct {
name string
}
mux.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
fmt.Fprintf(w, `{"Implements": ["%s"]}`, driverapi.NetworkPluginEndpointType)
})
if err := os.MkdirAll("/usr/share/docker/plugins", 0755); err != nil {
t.Fatal(err)
}
defer func() {
if err := os.RemoveAll("/usr/share/docker/plugins"); err != nil {
t.Fatal(err)
}
}()
if err := ioutil.WriteFile("/usr/share/docker/plugins/valid-network-driver.spec", []byte(server.URL), 0644); err != nil {
t.Fatal(err)
}
controller, err := libnetwork.New()
if err != nil {
t.Fatal(err)
}
_, err = controller.NewNetwork("valid-network-driver", "dummy",
libnetwork.NetworkOptionGeneric(getEmptyGenericOption()))
if err != nil && err != driverapi.ErrNotImplemented {
t.Fatal(err)
}
}
var (
once sync.Once
ctrlr libnetwork.NetworkController