Browse Source

Minor API modifications

* Modified NB API with self referential var-aarg for future proofing the APIs
* Modified Driver API's option parameter to be a Map of interface{}

Signed-off-by: Madhu Venugopal <madhu@docker.com>
Madhu Venugopal 10 years ago
parent
commit
cc4f27f6af

+ 40 - 25
libnetwork/README.md

@@ -21,31 +21,46 @@ There are many networking solutions available to suit a broad range of use-cases
 
 
 ```go
-    // Create a new controller instance
-    controller := libnetwork.New()
-
-    // This option is only needed for in-tree drivers. Plugins(in future) will get
-    // their options through plugin infrastructure.
-    option := options.Generic{}
-    err := controller.NewNetworkDriver("bridge", option)
-    if err != nil {
-        return
-    }
-
-    netOptions := options.Generic{}
-    // Create a network for containers to join.
-    network, err := controller.NewNetwork("bridge", "network1", netOptions)
-    if err != nil {
-    	return
-    }
-
-    // For each new container: allocate IP and interfaces. The returned network
-    // settings will be used for container infos (inspect and such), as well as
-    // iptables rules for port publishing.
-    ep, err := network.CreateEndpoint("Endpoint1", nil)
-    if err != nil {
-	    return
-    }
+        // Create a new controller instance
+        controller := libnetwork.New()
+
+        // Select and configure the network driver
+        networkType := "bridge"
+
+        driverOptions := options.Generic{}
+        genericOption := make(map[string]interface{})
+        genericOption[options.GenericData] = driverOptions
+        err := controller.ConfigureNetworkDriver(networkType, genericOption)
+        if err != nil {
+                return
+        }
+
+        // Create a network for containers to join.
+        // NewNetwork accepts Variadic optional arguments that libnetwork and Drivers can make of
+        network, err := controller.NewNetwork(networkType, "network1")
+        if err != nil {
+                return
+        }
+
+        // For each new container: allocate IP and interfaces. The returned network
+        // settings will be used for container infos (inspect and such), as well as
+        // iptables rules for port publishing. This info is contained or accessible
+        // from the returned endpoint.
+        ep, err := network.CreateEndpoint("Endpoint1")
+        if err != nil {
+                return
+        }
+
+        // A container can join the endpoint by providing the container ID to the join
+        // api which returns the sandbox key which can be used to access the sandbox
+        // created for the container during join.
+        // Join acceps Variadic arguments which will be made use of by libnetwork and Drivers
+        _, err = ep.Join("container1",
+                libnetwork.JoinOptionHostname("test"),
+                libnetwork.JoinOptionDomainname("docker.io"))
+        if err != nil {
+                return
+        }
 ```
 
 ## Future

+ 12 - 6
libnetwork/cmd/readme_test/readme.go

@@ -11,15 +11,18 @@ func main() {
 
 	// Select and configure the network driver
 	networkType := "bridge"
-	option := options.Generic{}
-	err := controller.ConfigureNetworkDriver(networkType, option)
+
+	driverOptions := options.Generic{}
+	genericOption := make(map[string]interface{})
+	genericOption[options.GenericData] = driverOptions
+	err := controller.ConfigureNetworkDriver(networkType, genericOption)
 	if err != nil {
 		return
 	}
 
-	netOptions := options.Generic{}
 	// Create a network for containers to join.
-	network, err := controller.NewNetwork(networkType, "network1", netOptions)
+	// NewNetwork accepts Variadic optional arguments that libnetwork and Drivers can make of
+	network, err := controller.NewNetwork(networkType, "network1")
 	if err != nil {
 		return
 	}
@@ -28,7 +31,7 @@ func main() {
 	// settings will be used for container infos (inspect and such), as well as
 	// iptables rules for port publishing. This info is contained or accessible
 	// from the returned endpoint.
-	ep, err := network.CreateEndpoint("Endpoint1", nil)
+	ep, err := network.CreateEndpoint("Endpoint1")
 	if err != nil {
 		return
 	}
@@ -36,7 +39,10 @@ func main() {
 	// A container can join the endpoint by providing the container ID to the join
 	// api which returns the sandbox key which can be used to access the sandbox
 	// created for the container during join.
-	_, err = ep.Join("container1")
+	// Join acceps Variadic arguments which will be made use of by libnetwork and Drivers
+	_, err = ep.Join("container1",
+		libnetwork.JoinOptionHostname("test"),
+		libnetwork.JoinOptionDomainname("docker.io"))
 	if err != nil {
 		return
 	}

+ 1 - 1
libnetwork/cmd/test/main.go

@@ -17,7 +17,7 @@ func main() {
 	controller := libnetwork.New()
 	netType := "bridge"
 	err := controller.ConfigureNetworkDriver(netType, options)
-	netw, err := controller.NewNetwork(netType, "dummy", "")
+	netw, err := controller.NewNetwork(netType, "dummy")
 	if err != nil {
 		log.Fatal(err)
 	}

+ 46 - 39
libnetwork/controller.go

@@ -2,40 +2,46 @@
 Package libnetwork provides the basic functionality and extension points to
 create network namespaces and allocate interfaces for containers to use.
 
-	// Create a new controller instance
-	controller := libnetwork.New()
-
-	// Select and configure the network driver
-	networkType := "bridge"
-	option := options.Generic{}
-	err := controller.ConfigureNetworkDriver(networkType, option)
-	if err != nil {
-		return
-	}
-
-	netOptions := options.Generic{}
-	// Create a network for containers to join.
-	network, err := controller.NewNetwork(networkType, "network1", netOptions)
-	if err != nil {
-		return
-	}
-
-	// For each new container: allocate IP and interfaces. The returned network
-	// settings will be used for container infos (inspect and such), as well as
-	// iptables rules for port publishing. This info is contained or accessible
-	// from the returned endpoint.
-	ep, err := network.CreateEndpoint("Endpoint1", nil)
-	if err != nil {
-		return
-	}
-
-	// A container can join the endpoint by providing the container ID to the join
-	// api which returns the sandbox key which can be used to access the sandbox
-	// created for the container during join.
-	_, err = ep.Join("container1")
-	if err != nil {
-		return
-	}
+        // Create a new controller instance
+        controller := libnetwork.New()
+
+        // Select and configure the network driver
+        networkType := "bridge"
+
+        driverOptions := options.Generic{}
+        genericOption := make(map[string]interface{})
+        genericOption[options.GenericData] = driverOptions
+        err := controller.ConfigureNetworkDriver(networkType, genericOption)
+        if err != nil {
+                return
+        }
+
+        // Create a network for containers to join.
+        // NewNetwork accepts Variadic optional arguments that libnetwork and Drivers can make of
+        network, err := controller.NewNetwork(networkType, "network1")
+        if err != nil {
+                return
+        }
+
+        // For each new container: allocate IP and interfaces. The returned network
+        // settings will be used for container infos (inspect and such), as well as
+        // iptables rules for port publishing. This info is contained or accessible
+        // from the returned endpoint.
+        ep, err := network.CreateEndpoint("Endpoint1")
+        if err != nil {
+                return
+        }
+
+        // A container can join the endpoint by providing the container ID to the join
+        // api which returns the sandbox key which can be used to access the sandbox
+        // created for the container during join.
+        // Join acceps Variadic arguments which will be made use of by libnetwork and Drivers
+        _, err = ep.Join("container1",
+                libnetwork.JoinOptionHostname("test"),
+                libnetwork.JoinOptionDomainname("docker.io"))
+        if err != nil {
+                return
+        }
 */
 package libnetwork
 
@@ -51,11 +57,11 @@ import (
 // networks.
 type NetworkController interface {
 	// ConfigureNetworkDriver applies the passed options to the driver instance for the specified network type
-	ConfigureNetworkDriver(networkType string, options interface{}) error
+	ConfigureNetworkDriver(networkType string, options map[string]interface{}) error
 
 	// Create a new network. The options parameter carries network specific options.
 	// Labels support will be added in the near future.
-	NewNetwork(networkType, name string, options interface{}) (Network, error)
+	NewNetwork(networkType, name string, options ...NetworkOption) (Network, error)
 
 	// Networks returns the list of Network(s) managed by this controller.
 	Networks() []Network
@@ -95,7 +101,7 @@ func New() NetworkController {
 	return &controller{networkTable{}, enumerateDrivers(), sandboxTable{}, sync.Mutex{}}
 }
 
-func (c *controller) ConfigureNetworkDriver(networkType string, options interface{}) error {
+func (c *controller) ConfigureNetworkDriver(networkType string, options map[string]interface{}) error {
 	d, ok := c.drivers[networkType]
 	if !ok {
 		return NetworkTypeError(networkType)
@@ -105,7 +111,7 @@ func (c *controller) ConfigureNetworkDriver(networkType string, options interfac
 
 // NewNetwork creates a new network of the specified network type. The options
 // are network specific and modeled in a generic way.
-func (c *controller) NewNetwork(networkType, name string, options interface{}) (Network, error) {
+func (c *controller) NewNetwork(networkType, name string, options ...NetworkOption) (Network, error) {
 	// Check if a driver for the specified network type is available
 	d, ok := c.drivers[networkType]
 	if !ok {
@@ -131,8 +137,9 @@ func (c *controller) NewNetwork(networkType, name string, options interface{}) (
 		endpoints: endpointTable{},
 	}
 
+	network.processOptions(options...)
 	// Create the network
-	if err := d.CreateNetwork(network.id, options); err != nil {
+	if err := d.CreateNetwork(network.id, network.generic); err != nil {
 		return nil, err
 	}
 

+ 3 - 3
libnetwork/driverapi/driverapi.go

@@ -19,12 +19,12 @@ var (
 // Driver is an interface that every plugin driver needs to implement.
 type Driver interface {
 	// Push driver specific config to the driver
-	Config(config interface{}) error
+	Config(options map[string]interface{}) error
 
 	// CreateNetwork invokes the driver method to create a network passing
 	// the network id and network specific config. The config mechanism will
 	// eventually be replaced with labels which are yet to be introduced.
-	CreateNetwork(nid types.UUID, config interface{}) error
+	CreateNetwork(nid types.UUID, options map[string]interface{}) error
 
 	// DeleteNetwork invokes the driver method to delete network passing
 	// the network id.
@@ -34,7 +34,7 @@ type Driver interface {
 	// passing the network id, endpoint id and driver
 	// specific config. The config mechanism will eventually be replaced
 	// with labels which are yet to be introduced.
-	CreateEndpoint(nid, eid types.UUID, config interface{}) (*sandbox.Info, error)
+	CreateEndpoint(nid, eid types.UUID, options map[string]interface{}) (*sandbox.Info, error)
 
 	// DeleteEndpoint invokes the driver method to delete an endpoint
 	// passing the network id and endpoint id.

+ 26 - 18
libnetwork/drivers/bridge/bridge.go

@@ -133,7 +133,7 @@ func (n *bridgeNetwork) getEndpoint(eid types.UUID) (*bridgeEndpoint, error) {
 	return nil, nil
 }
 
-func (d *driver) Config(option interface{}) error {
+func (d *driver) Config(option map[string]interface{}) error {
 	var config *Configuration
 
 	d.Lock()
@@ -143,28 +143,32 @@ func (d *driver) Config(option interface{}) error {
 		return ErrConfigExists
 	}
 
-	switch opt := option.(type) {
-	case options.Generic:
-		opaqueConfig, err := options.GenerateFromModel(opt, &Configuration{})
-		if err != nil {
-			return err
+	genericData := option[options.GenericData]
+	if genericData != nil {
+		switch opt := genericData.(type) {
+		case options.Generic:
+			opaqueConfig, err := options.GenerateFromModel(opt, &Configuration{})
+			if err != nil {
+				return err
+			}
+			config = opaqueConfig.(*Configuration)
+		case *Configuration:
+			config = opt
+		default:
+			return ErrInvalidDriverConfig
 		}
-		config = opaqueConfig.(*Configuration)
-	case *Configuration:
-		config = opt
-	}
 
-	if err := config.Validate(); err != nil {
-		return err
+		if err := config.Validate(); err != nil {
+			return err
+		}
+		d.config = config
 	}
 
-	d.config = config
-
 	return nil
 }
 
 // Create a new network using bridge plugin
-func (d *driver) CreateNetwork(id types.UUID, option interface{}) error {
+func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) error {
 	var err error
 
 	// Driver must be configured
@@ -297,7 +301,7 @@ func (d *driver) DeleteNetwork(nid types.UUID) error {
 	return err
 }
 
-func (d *driver) CreateEndpoint(nid, eid types.UUID, epOptions interface{}) (*sandbox.Info, error) {
+func (d *driver) CreateEndpoint(nid, eid types.UUID, epOptions map[string]interface{}) (*sandbox.Info, error) {
 	var (
 		ipv6Addr *net.IPNet
 		err      error
@@ -554,11 +558,15 @@ func (d *driver) Type() string {
 	return networkType
 }
 
-func parseEndpointOptions(epOptions interface{}) (*EndpointConfiguration, error) {
+func parseEndpointOptions(epOptions map[string]interface{}) (*EndpointConfiguration, error) {
 	if epOptions == nil {
 		return nil, nil
 	}
-	switch opt := epOptions.(type) {
+	genericData := epOptions[options.GenericData]
+	if genericData == nil {
+		return nil, nil
+	}
+	switch opt := genericData.(type) {
 	case options.Generic:
 		opaqueConfig, err := options.GenerateFromModel(opt, &EndpointConfiguration{})
 		if err != nil {

+ 27 - 10
libnetwork/drivers/bridge/bridge_test.go

@@ -6,6 +6,7 @@ import (
 	"testing"
 
 	"github.com/docker/libnetwork/netutils"
+	"github.com/docker/libnetwork/pkg/options"
 	"github.com/vishvananda/netlink"
 )
 
@@ -14,11 +15,14 @@ func TestCreate(t *testing.T) {
 	_, d := New()
 
 	config := &Configuration{BridgeName: DefaultBridgeName}
-	if err := d.Config(config); err != nil {
+	genericOption := make(map[string]interface{})
+	genericOption[options.GenericData] = config
+
+	if err := d.Config(genericOption); err != nil {
 		t.Fatalf("Failed to setup driver config: %v", err)
 	}
 
-	if err := d.CreateNetwork("dummy", ""); err != nil {
+	if err := d.CreateNetwork("dummy", nil); err != nil {
 		t.Fatalf("Failed to create bridge: %v", err)
 	}
 }
@@ -28,11 +32,14 @@ func TestCreateFail(t *testing.T) {
 	_, d := New()
 
 	config := &Configuration{BridgeName: "dummy0"}
-	if err := d.Config(config); err != nil {
+	genericOption := make(map[string]interface{})
+	genericOption[options.GenericData] = config
+
+	if err := d.Config(genericOption); err != nil {
 		t.Fatalf("Failed to setup driver config: %v", err)
 	}
 
-	if err := d.CreateNetwork("dummy", ""); err == nil {
+	if err := d.CreateNetwork("dummy", nil); err == nil {
 		t.Fatal("Bridge creation was expected to fail")
 	}
 }
@@ -49,11 +56,14 @@ func TestCreateFullOptions(t *testing.T) {
 		EnableIPForwarding: true,
 	}
 	_, config.FixedCIDRv6, _ = net.ParseCIDR("2001:db8::/48")
-	if err := d.Config(config); err != nil {
+	genericOption := make(map[string]interface{})
+	genericOption[options.GenericData] = config
+
+	if err := d.Config(genericOption); err != nil {
 		t.Fatalf("Failed to setup driver config: %v", err)
 	}
 
-	err := d.CreateNetwork("dummy", "")
+	err := d.CreateNetwork("dummy", nil)
 	if err != nil {
 		t.Fatalf("Failed to create bridge: %v", err)
 	}
@@ -64,19 +74,23 @@ func TestCreateLinkWithOptions(t *testing.T) {
 	_, d := New()
 
 	config := &Configuration{BridgeName: DefaultBridgeName}
-	if err := d.Config(config); err != nil {
+	genericOption := make(map[string]interface{})
+	genericOption[options.GenericData] = config
+
+	if err := d.Config(genericOption); err != nil {
 		t.Fatalf("Failed to setup driver config: %v", err)
 	}
 
-	err := d.CreateNetwork("net1", "")
+	err := d.CreateNetwork("net1", nil)
 	if err != nil {
 		t.Fatalf("Failed to create bridge: %v", err)
 	}
 
 	mac := net.HardwareAddr([]byte{0x1e, 0x67, 0x66, 0x44, 0x55, 0x66})
 	epConf := &EndpointConfiguration{MacAddress: mac}
+	genericOption[options.GenericData] = epConf
 
-	sinfo, err := d.CreateEndpoint("net1", "ep", epConf)
+	sinfo, err := d.CreateEndpoint("net1", "ep", genericOption)
 	if err != nil {
 		t.Fatalf("Failed to create a link: %s", err.Error())
 	}
@@ -198,7 +212,10 @@ func TestSetDefaultGw(t *testing.T) {
 		DefaultGatewayIPv6: gw6,
 	}
 
-	if err := d.Config(config); err != nil {
+	genericOption := make(map[string]interface{})
+	genericOption[options.GenericData] = config
+
+	if err := d.Config(genericOption); err != nil {
 		t.Fatalf("Failed to setup driver config: %v", err)
 	}
 

+ 3 - 0
libnetwork/drivers/bridge/error.go

@@ -10,6 +10,9 @@ var (
 	// ErrConfigExists error is returned when driver already has a config applied.
 	ErrConfigExists = errors.New("configuration already exists, bridge configuration can be applied only once")
 
+	// ErrInvalidDriverConfig error is returned when Bridge Driver is passed an invalid config
+	ErrInvalidDriverConfig = errors.New("Invalid configuration passed to Bridge Driver")
+
 	// ErrInvalidConfig error is returned when a network is created on a driver without valid config.
 	ErrInvalidConfig = errors.New("trying to create a network on a driver without valid config")
 

+ 19 - 8
libnetwork/drivers/bridge/network_test.go

@@ -5,6 +5,7 @@ import (
 
 	"github.com/docker/libnetwork/driverapi"
 	"github.com/docker/libnetwork/netutils"
+	"github.com/docker/libnetwork/pkg/options"
 	"github.com/vishvananda/netlink"
 )
 
@@ -19,11 +20,13 @@ func TestLinkCreate(t *testing.T) {
 		Mtu:        mtu,
 		EnableIPv6: true,
 	}
-	if err := d.Config(config); err != nil {
+	genericOption := make(map[string]interface{})
+	genericOption[options.GenericData] = config
+	if err := d.Config(genericOption); err != nil {
 		t.Fatalf("Failed to setup driver config: %v", err)
 	}
 
-	err := d.CreateNetwork("dummy", "")
+	err := d.CreateNetwork("dummy", nil)
 	if err != nil {
 		t.Fatalf("Failed to create bridge: %v", err)
 	}
@@ -102,11 +105,13 @@ func TestLinkCreateTwo(t *testing.T) {
 	config := &Configuration{
 		BridgeName: DefaultBridgeName,
 		EnableIPv6: true}
-	if err := d.Config(config); err != nil {
+	genericOption := make(map[string]interface{})
+	genericOption[options.GenericData] = config
+	if err := d.Config(genericOption); err != nil {
 		t.Fatalf("Failed to setup driver config: %v", err)
 	}
 
-	err := d.CreateNetwork("dummy", "")
+	err := d.CreateNetwork("dummy", nil)
 	if err != nil {
 		t.Fatalf("Failed to create bridge: %v", err)
 	}
@@ -132,11 +137,14 @@ func TestLinkCreateNoEnableIPv6(t *testing.T) {
 
 	config := &Configuration{
 		BridgeName: DefaultBridgeName}
-	if err := d.Config(config); err != nil {
+	genericOption := make(map[string]interface{})
+	genericOption[options.GenericData] = config
+
+	if err := d.Config(genericOption); err != nil {
 		t.Fatalf("Failed to setup driver config: %v", err)
 	}
 
-	err := d.CreateNetwork("dummy", "")
+	err := d.CreateNetwork("dummy", nil)
 	if err != nil {
 		t.Fatalf("Failed to create bridge: %v", err)
 	}
@@ -163,11 +171,14 @@ func TestLinkDelete(t *testing.T) {
 	config := &Configuration{
 		BridgeName: DefaultBridgeName,
 		EnableIPv6: true}
-	if err := d.Config(config); err != nil {
+	genericOption := make(map[string]interface{})
+	genericOption[options.GenericData] = config
+
+	if err := d.Config(genericOption); err != nil {
 		t.Fatalf("Failed to setup driver config: %v", err)
 	}
 
-	err := d.CreateNetwork("dummy", "")
+	err := d.CreateNetwork("dummy", nil)
 	if err != nil {
 		t.Fatalf("Failed to create bridge: %v", err)
 	}

+ 3 - 3
libnetwork/drivers/null/null.go

@@ -15,11 +15,11 @@ func New() (string, driverapi.Driver) {
 	return networkType, &driver{}
 }
 
-func (d *driver) Config(option interface{}) error {
+func (d *driver) Config(option map[string]interface{}) error {
 	return nil
 }
 
-func (d *driver) CreateNetwork(id types.UUID, option interface{}) error {
+func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) error {
 	return nil
 }
 
@@ -27,7 +27,7 @@ func (d *driver) DeleteNetwork(nid types.UUID) error {
 	return nil
 }
 
-func (d *driver) CreateEndpoint(nid, eid types.UUID, epOptions interface{}) (*sandbox.Info, error) {
+func (d *driver) CreateEndpoint(nid, eid types.UUID, epOptions map[string]interface{}) (*sandbox.Info, error) {
 	return nil, nil
 }
 

+ 28 - 5
libnetwork/endpoint.go

@@ -5,6 +5,7 @@ import (
 	"path/filepath"
 
 	"github.com/docker/docker/pkg/etchosts"
+	"github.com/docker/libnetwork/pkg/options"
 	"github.com/docker/libnetwork/sandbox"
 	"github.com/docker/libnetwork/types"
 )
@@ -65,6 +66,7 @@ type endpoint struct {
 	sandboxInfo *sandbox.Info
 	sandBox     sandbox.Sandbox
 	container   *containerInfo
+	generic     options.Generic
 }
 
 const prefix = "/var/lib/docker/network/files"
@@ -88,6 +90,27 @@ func (ep *endpoint) SandboxInfo() *sandbox.Info {
 	return ep.sandboxInfo.GetCopy()
 }
 
+// EndpointOption is a option setter function type used to pass various options to
+// CreateEndpoint method. The various setter functions of type EndpointOption are
+// provided by libnetwork, they look like EndpointOptionXXXX(...)
+type EndpointOption func(ep *endpoint)
+
+// EndpointOptionGeneric function returns an option setter for a Generic option defined
+// in a Dictionary of Key-Value pair
+func EndpointOptionGeneric(generic map[string]interface{}) EndpointOption {
+	return func(ep *endpoint) {
+		ep.generic = generic
+	}
+}
+
+func (ep *endpoint) processOptions(options ...EndpointOption) {
+	for _, opt := range options {
+		if opt != nil {
+			opt(ep)
+		}
+	}
+}
+
 func createBasePath(dir string) error {
 	err := os.MkdirAll(dir, 0644)
 	if err != nil && !os.IsExist(err) {
@@ -132,9 +155,7 @@ func (ep *endpoint) Join(containerID string, options ...JoinOption) (*ContainerD
 		}
 	}()
 
-	if options != nil {
-		ep.processOptions(options...)
-	}
+	ep.processJoinOptions(options...)
 
 	ep.container.Data.HostsPath = prefix + "/" + containerID + "/hosts"
 	err = createHostsFile(ep.container.Data.HostsPath)
@@ -255,8 +276,10 @@ func JoinOptionDomainname(name string) JoinOption {
 	}
 }
 
-func (ep *endpoint) processOptions(options ...JoinOption) {
+func (ep *endpoint) processJoinOptions(options ...JoinOption) {
 	for _, opt := range options {
-		opt(ep)
+		if opt != nil {
+			opt(ep)
+		}
 	}
 }

+ 40 - 33
libnetwork/libnetwork_test.go

@@ -17,13 +17,15 @@ const (
 
 func createTestNetwork(networkType, networkName string, option options.Generic) (libnetwork.Network, error) {
 	controller := libnetwork.New()
+	genericOption := make(map[string]interface{})
+	genericOption[options.GenericData] = option
 
-	err := controller.ConfigureNetworkDriver(networkType, option)
+	err := controller.ConfigureNetworkDriver(networkType, genericOption)
 	if err != nil {
 		return nil, err
 	}
 
-	network, err := controller.NewNetwork(networkType, networkName, "")
+	network, err := controller.NewNetwork(networkType, networkName)
 	if err != nil {
 		return nil, err
 	}
@@ -31,13 +33,19 @@ func createTestNetwork(networkType, networkName string, option options.Generic)
 	return network, nil
 }
 
+func getEmptyGenericOption() map[string]interface{} {
+	genericOption := make(map[string]interface{})
+	genericOption[options.GenericData] = options.Generic{}
+	return genericOption
+}
+
 func TestNull(t *testing.T) {
 	network, err := createTestNetwork("null", "testnetwork", options.Generic{})
 	if err != nil {
 		t.Fatal(err)
 	}
 
-	ep, err := network.CreateEndpoint("testep", nil)
+	ep, err := network.CreateEndpoint("testep")
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -101,7 +109,7 @@ func TestBridge(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	ep, err := network.CreateEndpoint("testep", nil)
+	ep, err := network.CreateEndpoint("testep")
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -131,8 +139,8 @@ func TestUnknownDriver(t *testing.T) {
 func TestNilDriver(t *testing.T) {
 	controller := libnetwork.New()
 
-	option := options.Generic{}
-	_, err := controller.NewNetwork("framerelay", "dummy", option)
+	_, err := controller.NewNetwork("framerelay", "dummy",
+		libnetwork.NetworkOptionGeneric(getEmptyGenericOption()))
 	if err == nil {
 		t.Fatal("Expected to fail. But instead succeeded")
 	}
@@ -145,8 +153,8 @@ func TestNilDriver(t *testing.T) {
 func TestNoInitDriver(t *testing.T) {
 	controller := libnetwork.New()
 
-	option := options.Generic{}
-	_, err := controller.NewNetwork("ppp", "dummy", option)
+	_, err := controller.NewNetwork("ppp", "dummy",
+		libnetwork.NetworkOptionGeneric(getEmptyGenericOption()))
 	if err == nil {
 		t.Fatal("Expected to fail. But instead succeeded")
 	}
@@ -160,18 +168,20 @@ func TestDuplicateNetwork(t *testing.T) {
 	defer netutils.SetupTestNetNS(t)()
 	controller := libnetwork.New()
 
-	option := options.Generic{}
-	err := controller.ConfigureNetworkDriver(netType, option)
+	genericOption := make(map[string]interface{})
+	genericOption[options.GenericData] = options.Generic{}
+
+	err := controller.ConfigureNetworkDriver(netType, genericOption)
 	if err != nil {
-		t.Fatal(err)
+		t.Fatal(err.Error())
 	}
 
-	_, err = controller.NewNetwork(netType, "testnetwork", "")
+	_, err = controller.NewNetwork(netType, "testnetwork", nil)
 	if err != nil {
-		t.Fatal(err)
+		t.Fatal("Expected to fail. But instead succeeded")
 	}
 
-	_, err = controller.NewNetwork(netType, "testnetwork", "")
+	_, err = controller.NewNetwork(netType, "testnetwork")
 	if err == nil {
 		t.Fatal("Expected to fail. But instead succeeded")
 	}
@@ -231,7 +241,7 @@ func TestDeleteNetworkWithActiveEndpoints(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	ep, err := network.CreateEndpoint("testep", nil)
+	ep, err := network.CreateEndpoint("testep")
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -299,7 +309,7 @@ func TestUnknownEndpoint(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	ep, err := network.CreateEndpoint("testep", nil)
+	ep, err := network.CreateEndpoint("testep")
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -329,22 +339,21 @@ func TestNetworkEndpointsWalkers(t *testing.T) {
 	controller := libnetwork.New()
 	netType := "bridge"
 
-	option := options.Generic{}
-	err := controller.ConfigureNetworkDriver(netType, option)
+	err := controller.ConfigureNetworkDriver(netType, getEmptyGenericOption())
 	if err != nil {
 		t.Fatal(err)
 	}
 
 	// Create network 1 and add 2 endpoint: ep11, ep12
-	net1, err := controller.NewNetwork(netType, "network1", "")
+	net1, err := controller.NewNetwork(netType, "network1")
 	if err != nil {
 		t.Fatal(err)
 	}
-	ep11, err := net1.CreateEndpoint("ep11", nil)
+	ep11, err := net1.CreateEndpoint("ep11")
 	if err != nil {
 		t.Fatal(err)
 	}
-	ep12, err := net1.CreateEndpoint("ep12", nil)
+	ep12, err := net1.CreateEndpoint("ep12")
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -409,14 +418,13 @@ func TestControllerQuery(t *testing.T) {
 	controller := libnetwork.New()
 	netType := "bridge"
 
-	option := options.Generic{}
-	err := controller.ConfigureNetworkDriver(netType, option)
+	err := controller.ConfigureNetworkDriver(netType, getEmptyGenericOption())
 	if err != nil {
 		t.Fatal(err)
 	}
 
 	// Create network 1
-	net1, err := controller.NewNetwork(netType, "network1", "")
+	net1, err := controller.NewNetwork(netType, "network1")
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -455,22 +463,21 @@ func TestNetworkQuery(t *testing.T) {
 	controller := libnetwork.New()
 	netType := "bridge"
 
-	option := options.Generic{}
-	err := controller.ConfigureNetworkDriver(netType, option)
+	err := controller.ConfigureNetworkDriver(netType, getEmptyGenericOption())
 	if err != nil {
 		t.Fatal(err)
 	}
 
 	// Create network 1 and add 2 endpoint: ep11, ep12
-	net1, err := controller.NewNetwork(netType, "network1", "")
+	net1, err := controller.NewNetwork(netType, "network1")
 	if err != nil {
 		t.Fatal(err)
 	}
-	ep11, err := net1.CreateEndpoint("ep11", nil)
+	ep11, err := net1.CreateEndpoint("ep11")
 	if err != nil {
 		t.Fatal(err)
 	}
-	ep12, err := net1.CreateEndpoint("ep12", nil)
+	ep12, err := net1.CreateEndpoint("ep12")
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -512,7 +519,7 @@ func TestEndpointJoin(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	ep, err := n.CreateEndpoint("ep1", nil)
+	ep, err := n.CreateEndpoint("ep1")
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -538,7 +545,7 @@ func TestEndpointJoinInvalidContainerId(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	ep, err := n.CreateEndpoint("ep1", nil)
+	ep, err := n.CreateEndpoint("ep1")
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -561,7 +568,7 @@ func TestEndpointMultipleJoins(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	ep, err := n.CreateEndpoint("ep1", nil)
+	ep, err := n.CreateEndpoint("ep1")
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -597,7 +604,7 @@ func TestEndpointInvalidLeave(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	ep, err := n.CreateEndpoint("ep1", nil)
+	ep, err := n.CreateEndpoint("ep1")
 	if err != nil {
 		t.Fatal(err)
 	}

+ 27 - 3
libnetwork/network.go

@@ -5,6 +5,7 @@ import (
 
 	"github.com/docker/docker/pkg/stringid"
 	"github.com/docker/libnetwork/driverapi"
+	"github.com/docker/libnetwork/pkg/options"
 	"github.com/docker/libnetwork/types"
 )
 
@@ -23,7 +24,7 @@ type Network interface {
 	// Create a new endpoint to this network symbolically identified by the
 	// specified unique name. The options parameter carry driver specific options.
 	// Labels support will be added in the near future.
-	CreateEndpoint(name string, options interface{}) (Endpoint, error)
+	CreateEndpoint(name string, options ...EndpointOption) (Endpoint, error)
 
 	// Delete the network.
 	Delete() error
@@ -52,6 +53,7 @@ type network struct {
 	id          types.UUID
 	driver      driverapi.Driver
 	endpoints   endpointTable
+	generic     options.Generic
 	sync.Mutex
 }
 
@@ -71,6 +73,27 @@ func (n *network) Type() string {
 	return n.driver.Type()
 }
 
+// NetworkOption is a option setter function type used to pass varios options to
+// NewNetwork method. The various setter functions of type NetworkOption are
+// provided by libnetwork, they look like NetworkOptionXXXX(...)
+type NetworkOption func(n *network)
+
+// NetworkOptionGeneric function returns an option setter for a Generic option defined
+// in a Dictionary of Key-Value pair
+func NetworkOptionGeneric(generic map[string]interface{}) NetworkOption {
+	return func(n *network) {
+		n.generic = generic
+	}
+}
+
+func (n *network) processOptions(options ...NetworkOption) {
+	for _, opt := range options {
+		if opt != nil {
+			opt(n)
+		}
+	}
+}
+
 func (n *network) Delete() error {
 	var err error
 
@@ -103,13 +126,14 @@ func (n *network) Delete() error {
 	return err
 }
 
-func (n *network) CreateEndpoint(name string, options interface{}) (Endpoint, error) {
+func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoint, error) {
 	ep := &endpoint{name: name}
 	ep.id = types.UUID(stringid.GenerateRandomID())
 	ep.network = n
+	ep.processOptions(options...)
 
 	d := n.driver
-	sinfo, err := d.CreateEndpoint(n.id, ep.id, options)
+	sinfo, err := d.CreateEndpoint(n.id, ep.id, ep.generic)
 	if err != nil {
 		return nil, err
 	}

+ 9 - 0
libnetwork/pkg/options/options.go

@@ -7,6 +7,15 @@ import (
 	"reflect"
 )
 
+const (
+	// GenericData constant that helps to identify an option as a Generic constant
+	GenericData = "io.docker.network.generic"
+	// PortMap constant represents Port Mapping
+	PortMap = "io.docker.network.endpoint.portmap"
+	// MacAddress constant represents Mac Address config of a Container
+	MacAddress = "io.docker.network.endpoint.macaddress"
+)
+
 // NoSuchFieldError is the error returned when the generic parameters hold a
 // value for a field absent from the destination structure.
 type NoSuchFieldError struct {