diff --git a/bridge/bridge.go b/bridge/bridge.go index 2afe066..16fbe9a 100644 --- a/bridge/bridge.go +++ b/bridge/bridge.go @@ -13,7 +13,7 @@ type bridgeConfiguration struct { } func init() { - libnetwork.RegisterNetworkType(networkType, Create, bridgeConfiguration{}) + libnetwork.RegisterNetworkType(networkType, Create, &bridgeConfiguration{}) } func Create(config *bridgeConfiguration) (libnetwork.Network, error) { diff --git a/drivers.go b/drivers.go index a079c75..5b7af74 100644 --- a/drivers.go +++ b/drivers.go @@ -10,21 +10,43 @@ import ( type DriverParams options.Generic var drivers = map[string]struct { - ctor interface{} - config interface{} + creatorFn interface{} + creatorArg interface{} }{} // RegisterNetworkType associates a textual identifier with a way to create a // new network. It is called by the various network implementations, and used // upon invokation of the libnetwork.NetNetwork function. -func RegisterNetworkType(name string, ctor interface{}, config interface{}) error { +// +// creatorFn must be of type func (creatorArgType) (Network, error), where +// createArgType is the type of the creatorArg argument. +// +// For example: +// +// func CreateTestNetwork(config *TestNetworkConfig()) (Network, error) { +// } +// +// func init() { +// RegisterNetworkType("test", CreateTestNetwork, &TestNetworkConfig{}) +// } +// +func RegisterNetworkType(name string, creatorFn interface{}, creatorArg interface{}) error { + // Validate the creator function signature. + ctorArg := []reflect.Type{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) + } + + // 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 { - ctor interface{} - config interface{} - }{ctor, config} + creatorFn interface{} + creatorArg interface{} + }{creatorFn, creatorArg} return nil } @@ -34,13 +56,13 @@ func createNetwork(name string, generic DriverParams) (Network, error) { return nil, fmt.Errorf("unknown driver %q", name) } - config, err := options.GenerateFromModel(options.Generic(generic), d.config) + config, err := options.GenerateFromModel(options.Generic(generic), d.creatorArg) if err != nil { return nil, fmt.Errorf("failed to generate driver config: %v", err) } arg := []reflect.Value{reflect.ValueOf(config)} - res := reflect.ValueOf(d.ctor).Call(arg) + res := reflect.ValueOf(d.creatorFn).Call(arg) return makeCreateResult(res) } @@ -53,3 +75,33 @@ func makeCreateResult(res []reflect.Value) (net Network, err 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 +} diff --git a/pkg/options/options.go b/pkg/options/options.go index 09966e6..d5bc063 100644 --- a/pkg/options/options.go +++ b/pkg/options/options.go @@ -32,7 +32,16 @@ func NewGeneric() Generic { } func GenerateFromModel(options Generic, model interface{}) (interface{}, error) { - res := reflect.New(reflect.TypeOf(model)) + modType := reflect.TypeOf(model) + + // If the model is of pointer type, we need to dereference for New. + resType := reflect.TypeOf(model) + if modType.Kind() == reflect.Ptr { + resType = resType.Elem() + } + + // Populate the result structure with the generic layout content. + res := reflect.New(resType) for name, value := range options { field := res.Elem().FieldByName(name) if !field.IsValid() { @@ -43,5 +52,10 @@ func GenerateFromModel(options Generic, model interface{}) (interface{}, error) } field.Set(reflect.ValueOf(value)) } - return res.Interface(), nil + + // If the model is not of pointer type, return content of the result. + if modType.Kind() == reflect.Ptr { + return res.Interface(), nil + } + return res.Elem().Interface(), nil }