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:
parent
cb8bbd3ded
commit
80ca3c2330
4 changed files with 141 additions and 23 deletions
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue