From cc4f27f6aff54ee53815b15722a02c37a6728449 Mon Sep 17 00:00:00 2001 From: Madhu Venugopal Date: Thu, 30 Apr 2015 17:57:06 -0700 Subject: [PATCH] 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 --- libnetwork/README.md | 59 ++++++++++------- libnetwork/cmd/readme_test/readme.go | 18 ++++-- libnetwork/cmd/test/main.go | 2 +- libnetwork/controller.go | 77 ++++++++++++----------- libnetwork/driverapi/driverapi.go | 6 +- libnetwork/drivers/bridge/bridge.go | 44 +++++++------ libnetwork/drivers/bridge/bridge_test.go | 37 ++++++++--- libnetwork/drivers/bridge/error.go | 3 + libnetwork/drivers/bridge/network_test.go | 27 +++++--- libnetwork/drivers/null/null.go | 6 +- libnetwork/endpoint.go | 33 ++++++++-- libnetwork/libnetwork_test.go | 73 +++++++++++---------- libnetwork/network.go | 30 ++++++++- libnetwork/pkg/options/options.go | 9 +++ 14 files changed, 277 insertions(+), 147 deletions(-) diff --git a/libnetwork/README.md b/libnetwork/README.md index dec947dc0d..3e4ebf5d10 100644 --- a/libnetwork/README.md +++ b/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() + // 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 - } + // Select and configure the network driver + networkType := "bridge" - netOptions := options.Generic{} - // Create a network for containers to join. - network, err := controller.NewNetwork("bridge", "network1", netOptions) - if err != nil { - return - } + driverOptions := options.Generic{} + genericOption := make(map[string]interface{}) + genericOption[options.GenericData] = driverOptions + err := controller.ConfigureNetworkDriver(networkType, genericOption) + 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 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 diff --git a/libnetwork/cmd/readme_test/readme.go b/libnetwork/cmd/readme_test/readme.go index 30f9af557f..ad57757a45 100644 --- a/libnetwork/cmd/readme_test/readme.go +++ b/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 } diff --git a/libnetwork/cmd/test/main.go b/libnetwork/cmd/test/main.go index 4786d9aa19..07ae996327 100644 --- a/libnetwork/cmd/test/main.go +++ b/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) } diff --git a/libnetwork/controller.go b/libnetwork/controller.go index bd70ecf398..e25a620a15 100644 --- a/libnetwork/controller.go +++ b/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() + // 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 - } + // Select and configure the network driver + networkType := "bridge" - netOptions := options.Generic{} - // Create a network for containers to join. - network, err := controller.NewNetwork(networkType, "network1", netOptions) - if err != nil { - return - } + driverOptions := options.Generic{} + genericOption := make(map[string]interface{}) + genericOption[options.GenericData] = driverOptions + err := controller.ConfigureNetworkDriver(networkType, genericOption) + 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 - } + // 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 + } - // 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 - } + // 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 } diff --git a/libnetwork/driverapi/driverapi.go b/libnetwork/driverapi/driverapi.go index 184528137a..fc91f1d78c 100644 --- a/libnetwork/driverapi/driverapi.go +++ b/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. diff --git a/libnetwork/drivers/bridge/bridge.go b/libnetwork/drivers/bridge/bridge.go index 115197dddd..099e176d6e 100644 --- a/libnetwork/drivers/bridge/bridge.go +++ b/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 { + 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 + } + + if err := config.Validate(); err != nil { return err } - config = opaqueConfig.(*Configuration) - case *Configuration: - config = opt + d.config = config } - if err := config.Validate(); err != nil { - return err - } - - 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 { diff --git a/libnetwork/drivers/bridge/bridge_test.go b/libnetwork/drivers/bridge/bridge_test.go index 26ee5b482b..68f2f29136 100644 --- a/libnetwork/drivers/bridge/bridge_test.go +++ b/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) } diff --git a/libnetwork/drivers/bridge/error.go b/libnetwork/drivers/bridge/error.go index 5c074e3c43..a16f3dc3a1 100644 --- a/libnetwork/drivers/bridge/error.go +++ b/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") diff --git a/libnetwork/drivers/bridge/network_test.go b/libnetwork/drivers/bridge/network_test.go index a195013906..aa1cbb85d6 100644 --- a/libnetwork/drivers/bridge/network_test.go +++ b/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) } diff --git a/libnetwork/drivers/null/null.go b/libnetwork/drivers/null/null.go index aa09a06ea4..c3dd6a3b50 100644 --- a/libnetwork/drivers/null/null.go +++ b/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 } diff --git a/libnetwork/endpoint.go b/libnetwork/endpoint.go index 9989961859..9fa2c8586e 100644 --- a/libnetwork/endpoint.go +++ b/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) + } } } diff --git a/libnetwork/libnetwork_test.go b/libnetwork/libnetwork_test.go index 4582f23d6e..e4676fe247 100644 --- a/libnetwork/libnetwork_test.go +++ b/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) } diff --git a/libnetwork/network.go b/libnetwork/network.go index a4a1f53b09..66c7420ff2 100644 --- a/libnetwork/network.go +++ b/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 } diff --git a/libnetwork/pkg/options/options.go b/libnetwork/pkg/options/options.go index e0e93ff9b7..846d1ea5a1 100644 --- a/libnetwork/pkg/options/options.go +++ b/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 {