Browse Source

Merge pull request #19 from mrjana/master

Refactor the drivers interface to get rid of reflect way
Arnaud Porterie 10 years ago
parent
commit
5345da32c6

+ 16 - 59
libnetwork/drivers.go

@@ -2,7 +2,6 @@ package libnetwork
 
 import (
 	"fmt"
-	"reflect"
 
 	"github.com/docker/libnetwork/pkg/options"
 )
@@ -10,8 +9,13 @@ import (
 // DriverParams are a generic structure to hold driver specific settings.
 type DriverParams options.Generic
 
+// DriverInterface is an interface that every plugin driver needs to implement.
+type DriverInterface interface {
+	CreateNetwork(string, interface{}) (Network, error)
+}
+
 var drivers = map[string]struct {
-	creatorFn  interface{}
+	creatorFn  DriverInterface
 	creatorArg interface{}
 }{}
 
@@ -19,35 +23,30 @@ var drivers = map[string]struct {
 // new network. It is called by the various network implementations, and used
 // upon invokation of the libnetwork.NetNetwork function.
 //
-// creatorFn must be of type func (creatorArgType) (Network, error), where
-// createArgType is the type of the creatorArg argument.
+// creatorFn must implement DriverInterface
 //
 // For example:
 //
-//    func CreateTestNetwork(name string, config *TestNetworkConfig()) (Network, error) {
+//    type driver struct{}
+//
+//    func (d *driver) CreateNetwork(name string, config *TestNetworkConfig) (Network, error) {
 //    }
 //
 //    func init() {
-//        RegisterNetworkType("test", CreateTestNetwork, &TestNetworkConfig{})
+//        RegisterNetworkType("test", &driver{}, &TestNetworkConfig{})
 //    }
 //
-func RegisterNetworkType(name string, creatorFn interface{}, creatorArg interface{}) error {
-	// Validate the creator function signature.
-	ctorArg := []reflect.Type{reflect.TypeOf((*string)(nil)), reflect.TypeOf(creatorArg)}
-	ctorRet := []reflect.Type{reflect.TypeOf((*Network)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}
-	if err := validateFunctionSignature(creatorFn, ctorArg, ctorRet); err != nil {
-		sig := fmt.Sprintf("func (%s) (Network, error)", ctorArg[0].Name())
-		return fmt.Errorf("invalid signature for %q creator function (expected %s)", name, sig)
-	}
-
+func RegisterNetworkType(name string, creatorFn DriverInterface, creatorArg interface{}) error {
 	// Store the new driver information to invoke at creation time.
 	if _, ok := drivers[name]; ok {
 		return fmt.Errorf("a driver for network type %q is already registed", name)
 	}
+
 	drivers[name] = struct {
-		creatorFn  interface{}
+		creatorFn  DriverInterface
 		creatorArg interface{}
 	}{creatorFn, creatorArg}
+
 	return nil
 }
 
@@ -62,47 +61,5 @@ func createNetwork(networkType, name string, generic DriverParams) (Network, err
 		return nil, fmt.Errorf("failed to generate driver config: %v", err)
 	}
 
-	arg := []reflect.Value{reflect.ValueOf(name), reflect.ValueOf(config)}
-	res := reflect.ValueOf(d.creatorFn).Call(arg)
-	return makeCreateResult(res)
-}
-
-func makeCreateResult(res []reflect.Value) (net Network, err error) {
-	if !res[0].IsNil() {
-		net = res[0].Interface().(Network)
-	}
-	if !res[1].IsNil() {
-		err = res[1].Interface().(error)
-	}
-	return
-}
-
-func validateFunctionSignature(fn interface{}, params []reflect.Type, returns []reflect.Type) error {
-	// Valid that argument is a function.
-	fnType := reflect.TypeOf(fn)
-	if fnType.Kind() != reflect.Func {
-		return fmt.Errorf("argument is %s, not function", fnType.Name())
-	}
-
-	// Vaidate arguments numbers and types.
-	if fnType.NumIn() != len(params) {
-		return fmt.Errorf("expected function with %d arguments, got %d", len(params), fnType.NumIn())
-	}
-	for i, argType := range params {
-		if argType != fnType.In(i) {
-			return fmt.Errorf("argument %d type should be %s, got %s", i, argType.Name(), fnType.In(i).Name())
-		}
-	}
-
-	// Validate return values numbers and types.
-	if fnType.NumOut() != len(returns) {
-		return fmt.Errorf("expected function with %d return values, got %d", len(params), fnType.NumIn())
-	}
-	for i, retType := range returns {
-		if retType != fnType.Out(i) {
-			return fmt.Errorf("return value %d type should be %s, got %s", i, retType.Name(), fnType.Out(i).Name())
-		}
-	}
-
-	return nil
+	return d.creatorFn.CreateNetwork(name, config)
 }

+ 6 - 3
libnetwork/drivers/bridge/bridge.go

@@ -22,12 +22,15 @@ type Configuration struct {
 	EnableIPForwarding bool
 }
 
+type driver struct{}
+
 func init() {
-	libnetwork.RegisterNetworkType(networkType, Create, &Configuration{})
+	libnetwork.RegisterNetworkType(networkType, &driver{}, &Configuration{})
 }
 
-// Create a new Network managed by the "simplebridge" driver.
-func Create(name string, config *Configuration) (libnetwork.Network, error) {
+// Create a new network using simplebridge plugin
+func (d *driver) CreateNetwork(name string, opaqueConfig interface{}) (libnetwork.Network, error) {
+	config := opaqueConfig.(*Configuration)
 	bridgeIntfc := newInterface(config)
 	bridgeSetup := newBridgeSetup(bridgeIntfc)
 

+ 6 - 3
libnetwork/drivers/bridge/bridge_test.go

@@ -9,9 +9,10 @@ import (
 
 func TestCreate(t *testing.T) {
 	defer libnetwork.SetupTestNetNS(t)()
+	d := &driver{}
 
 	config := &Configuration{BridgeName: DefaultBridgeName}
-	netw, err := Create("dummy", config)
+	netw, err := d.CreateNetwork("dummy", config)
 	if err != nil {
 		t.Fatalf("Failed to create bridge: %v", err)
 	}
@@ -23,15 +24,17 @@ func TestCreate(t *testing.T) {
 
 func TestCreateFail(t *testing.T) {
 	defer libnetwork.SetupTestNetNS(t)()
+	d := &driver{}
 
 	config := &Configuration{BridgeName: "dummy0"}
-	if _, err := Create("dummy", config); err == nil {
+	if _, err := d.CreateNetwork("dummy", config); err == nil {
 		t.Fatal("Bridge creation was expected to fail")
 	}
 }
 
 func TestCreateFullOptions(t *testing.T) {
 	defer libnetwork.SetupTestNetNS(t)()
+	d := &driver{}
 
 	config := &Configuration{
 		BridgeName:         DefaultBridgeName,
@@ -42,7 +45,7 @@ func TestCreateFullOptions(t *testing.T) {
 	}
 	_, config.FixedCIDRv6, _ = net.ParseCIDR("2001:db8::/48")
 
-	netw, err := Create("dummy", config)
+	netw, err := d.CreateNetwork("dummy", config)
 	if err != nil {
 		t.Fatalf("Failed to create bridge: %v", err)
 	}