From 29f28ca9254e56663d95b2c0ff36a83d9678bff6 Mon Sep 17 00:00:00 2001 From: Jana Radhakrishnan Date: Wed, 15 Apr 2015 05:25:42 +0000 Subject: [PATCH] Added driver specific config support - Added api enhancement to pass driver specific config - Refactored simple bridge driver code for driver specific config - Added an undocumented option to add non-default bridges without manual pre-provisioning to help libnetwork testing - Reenabled libnetwork test to do api testing - Updated README.md Signed-off-by: Jana Radhakrishnan --- README.md | 14 +++- cmd/test/main.go | 3 +- driverapi/driverapi.go | 5 +- drivers.go | 3 +- drivers/bridge/bridge.go | 81 ++++++++++++++-------- drivers/bridge/bridge_test.go | 18 +++-- drivers/bridge/interface.go | 11 ++- drivers/bridge/interface_test.go | 5 +- drivers/bridge/network_test.go | 18 ++++- drivers/bridge/setup.go | 9 +-- drivers/bridge/setup_device.go | 12 ++-- drivers/bridge/setup_device_test.go | 32 ++++----- drivers/bridge/setup_fixedcidrv4.go | 8 +-- drivers/bridge/setup_fixedcidrv4_test.go | 40 +++++------ drivers/bridge/setup_fixedcidrv6.go | 8 +-- drivers/bridge/setup_fixedcidrv6_test.go | 15 ++-- drivers/bridge/setup_ip_forwarding.go | 4 +- drivers/bridge/setup_ip_forwarding_test.go | 24 +++---- drivers/bridge/setup_ip_tables.go | 14 ++-- drivers/bridge/setup_ip_tables_test.go | 46 ++++++------ drivers/bridge/setup_ipv4.go | 6 +- drivers/bridge/setup_ipv4_test.go | 29 ++++---- drivers/bridge/setup_ipv6.go | 4 +- drivers/bridge/setup_ipv6_test.go | 6 +- drivers/bridge/setup_verify.go | 8 +-- drivers/bridge/setup_verify_test.go | 43 +++++++----- libnetwork_test.go | 43 +++++++----- network.go | 78 +++++++++++++-------- 28 files changed, 333 insertions(+), 254 deletions(-) diff --git a/README.md b/README.md index 46b326b..acf601f 100644 --- a/README.md +++ b/README.md @@ -22,10 +22,18 @@ There are many networking solutions available to suit a broad range of use-cases ```go // Create a new controller instance controller := libnetwork.New() - - options := options.Generic{} + + // This option is only needed for in-tree drivers. Plugins(in future) will get + // their options through plugin infrastructure. + option := options.Generic{} + driver, err := controller.NewNetworkDriver("simplebridge", option) + if err != nil { + return + } + + netOptions := options.Generic{} // Create a network for containers to join. - network, err := controller.NewNetwork("simplebridge", "network1", options) + network, err := controller.NewNetwork(driver, "network1", netOptions) if err != nil { return } diff --git a/cmd/test/main.go b/cmd/test/main.go index afac59d..3dedce3 100644 --- a/cmd/test/main.go +++ b/cmd/test/main.go @@ -15,7 +15,8 @@ func main() { options := options.Generic{"AddressIPv4": net} controller := libnetwork.New() - netw, err := controller.NewNetwork("simplebridge", "dummy", options) + driver, _ := controller.NewNetworkDriver("simplebridge", options) + netw, err := controller.NewNetwork(driver, "dummy", "") if err != nil { log.Fatal(err) } diff --git a/driverapi/driverapi.go b/driverapi/driverapi.go index 5ae2dcb..267cd31 100644 --- a/driverapi/driverapi.go +++ b/driverapi/driverapi.go @@ -19,8 +19,11 @@ type UUID string // 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 + // CreateNetwork invokes the driver method to create a network passing - // the network id and driver specific config. The config mechanism will + // the network id and network specific config. The config mechanism will // eventually be replaced with labels which are yet to be introduced. CreateNetwork(nid UUID, config interface{}) error diff --git a/drivers.go b/drivers.go index 1980f93..8a8fdf2 100644 --- a/drivers.go +++ b/drivers.go @@ -8,7 +8,8 @@ import ( type driverTable map[string]driverapi.Driver func enumerateDrivers() driverTable { - var drivers driverTable + drivers := make(driverTable) + for _, fn := range [](func() (string, driverapi.Driver)){bridge.New} { name, driver := fn() drivers[name] = driver diff --git a/drivers/bridge/bridge.go b/drivers/bridge/bridge.go index 144cf87..c5d0b9a 100644 --- a/drivers/bridge/bridge.go +++ b/drivers/bridge/bridge.go @@ -36,15 +36,16 @@ func initPortMapper() { // Configuration info for the "simplebridge" driver. type Configuration struct { - BridgeName string - AddressIPv4 *net.IPNet - FixedCIDR *net.IPNet - FixedCIDRv6 *net.IPNet - EnableIPv6 bool - EnableIPTables bool - EnableIPMasquerade bool - EnableICC bool - EnableIPForwarding bool + BridgeName string + AddressIPv4 *net.IPNet + FixedCIDR *net.IPNet + FixedCIDRv6 *net.IPNet + EnableIPv6 bool + EnableIPTables bool + EnableIPMasquerade bool + EnableICC bool + EnableIPForwarding bool + AllowNonDefaultBridge bool } type bridgeEndpoint struct { @@ -62,6 +63,7 @@ type bridgeNetwork struct { } type driver struct { + config *Configuration network *bridgeNetwork sync.Mutex } @@ -76,15 +78,45 @@ func New() (string, driverapi.Driver) { return networkType, &driver{} } +func (d *driver) Config(option interface{}) error { + var config *Configuration + + d.Lock() + defer d.Unlock() + + if d.config != nil { + return fmt.Errorf("configuration already exists, simplebridge configuration can be applied only once") + } + + switch opt := option.(type) { + case options.Generic: + opaqueConfig, err := options.GenerateFromModel(opt, &Configuration{}) + if err != nil { + return fmt.Errorf("failed to generate driver config: %v", err) + } + config = opaqueConfig.(*Configuration) + case *Configuration: + config = opt + } + + d.config = config + return nil +} + // Create a new network using simplebridge plugin func (d *driver) CreateNetwork(id driverapi.UUID, option interface{}) error { var ( - config *Configuration - err error + err error ) d.Lock() + if d.config == nil { + d.Unlock() + return fmt.Errorf("trying to create a network on a driver without valid config") + } + config := d.config + if d.network != nil { d.Unlock() return fmt.Errorf("network already exists, simplebridge can only have one network") @@ -100,19 +132,8 @@ func (d *driver) CreateNetwork(id driverapi.UUID, option interface{}) error { } }() - switch opt := option.(type) { - case options.Generic: - opaqueConfig, err := options.GenerateFromModel(opt, &Configuration{}) - if err != nil { - return fmt.Errorf("failed to generate driver config: %v", err) - } - config = opaqueConfig.(*Configuration) - case *Configuration: - config = opt - } - bridgeIface := newInterface(config) - bridgeSetup := newBridgeSetup(bridgeIface) + bridgeSetup := newBridgeSetup(config, bridgeIface) // If the bridge interface doesn't exist, we need to start the setup steps // by creating a new device and assigning it an IPv4 address. @@ -199,7 +220,7 @@ func (d *driver) DeleteNetwork(nid driverapi.UUID) error { return err } -func (d *driver) CreateEndpoint(nid, eid driverapi.UUID, sboxKey string, config interface{}) (*driverapi.SandboxInfo, error) { +func (d *driver) CreateEndpoint(nid, eid driverapi.UUID, sboxKey string, epOption interface{}) (*driverapi.SandboxInfo, error) { var ( ipv6Addr net.IPNet err error @@ -207,6 +228,7 @@ func (d *driver) CreateEndpoint(nid, eid driverapi.UUID, sboxKey string, config d.Lock() n := d.network + config := d.config d.Unlock() if n == nil { return nil, driverapi.ErrNoNetwork @@ -271,7 +293,7 @@ func (d *driver) CreateEndpoint(nid, eid driverapi.UUID, sboxKey string, config }() if err = netlink.LinkSetMaster(host, - &netlink.Bridge{LinkAttrs: netlink.LinkAttrs{Name: n.bridge.Config.BridgeName}}); err != nil { + &netlink.Bridge{LinkAttrs: netlink.LinkAttrs{Name: config.BridgeName}}); err != nil { return nil, err } @@ -281,7 +303,7 @@ func (d *driver) CreateEndpoint(nid, eid driverapi.UUID, sboxKey string, config } ipv4Addr := net.IPNet{IP: ip4, Mask: n.bridge.bridgeIPv4.Mask} - if n.bridge.Config.EnableIPv6 { + if config.EnableIPv6 { ip6, err := ipAllocator.RequestIP(n.bridge.bridgeIPv6, nil) if err != nil { return nil, err @@ -297,7 +319,7 @@ func (d *driver) CreateEndpoint(nid, eid driverapi.UUID, sboxKey string, config intf.DstName = containerVeth intf.Address = ipv4Addr sinfo.Gateway = n.bridge.bridgeIPv4.IP - if n.bridge.Config.EnableIPv6 { + if config.EnableIPv6 { intf.AddressIPv6 = ipv6Addr sinfo.GatewayIPv6 = n.bridge.bridgeIPv6.IP } @@ -314,6 +336,7 @@ func (d *driver) DeleteEndpoint(nid, eid driverapi.UUID) error { d.Lock() n := d.network + config := d.config d.Unlock() if n == nil { return driverapi.ErrNoNetwork @@ -356,8 +379,8 @@ func (d *driver) DeleteEndpoint(nid, eid driverapi.UUID) error { return err } - if n.bridge.Config.EnableIPv6 { - err := ipAllocator.ReleaseIP(n.bridge.bridgeIPv6, n.endpoint.addressIPv6) + if config.EnableIPv6 { + err := ipAllocator.ReleaseIP(n.bridge.bridgeIPv6, ep.addressIPv6) if err != nil { return err } diff --git a/drivers/bridge/bridge_test.go b/drivers/bridge/bridge_test.go index eb1cfa2..a085209 100644 --- a/drivers/bridge/bridge_test.go +++ b/drivers/bridge/bridge_test.go @@ -12,8 +12,11 @@ func TestCreate(t *testing.T) { _, d := New() config := &Configuration{BridgeName: DefaultBridgeName} - err := d.CreateNetwork("dummy", config) - if err != nil { + if err := d.Config(config); err != nil { + t.Fatalf("Failed to setup driver config: %v", err) + } + + if err := d.CreateNetwork("dummy", ""); err != nil { t.Fatalf("Failed to create bridge: %v", err) } } @@ -23,7 +26,11 @@ func TestCreateFail(t *testing.T) { _, d := New() config := &Configuration{BridgeName: "dummy0"} - if err := d.CreateNetwork("dummy", config); err == nil { + if err := d.Config(config); err != nil { + t.Fatalf("Failed to setup driver config: %v", err) + } + + if err := d.CreateNetwork("dummy", ""); err == nil { t.Fatal("Bridge creation was expected to fail") } } @@ -40,8 +47,11 @@ func TestCreateFullOptions(t *testing.T) { EnableIPForwarding: true, } _, config.FixedCIDRv6, _ = net.ParseCIDR("2001:db8::/48") + if err := d.Config(config); err != nil { + t.Fatalf("Failed to setup driver config: %v", err) + } - err := d.CreateNetwork("dummy", config) + err := d.CreateNetwork("dummy", "") if err != nil { t.Fatalf("Failed to create bridge: %v", err) } diff --git a/drivers/bridge/interface.go b/drivers/bridge/interface.go index 372ebd8..fdc887f 100644 --- a/drivers/bridge/interface.go +++ b/drivers/bridge/interface.go @@ -14,7 +14,6 @@ const ( // Interface models the bridge network device. type bridgeInterface struct { - Config *Configuration Link netlink.Link bridgeIPv4 *net.IPNet bridgeIPv6 *net.IPNet @@ -25,17 +24,15 @@ type bridgeInterface struct { // or the default bridge name when unspecified), but doesn't attempt to create // on when missing func newInterface(config *Configuration) *bridgeInterface { - i := &bridgeInterface{ - Config: config, - } + i := &bridgeInterface{} // Initialize the bridge name to the default if unspecified. - if i.Config.BridgeName == "" { - i.Config.BridgeName = DefaultBridgeName + if config.BridgeName == "" { + config.BridgeName = DefaultBridgeName } // Attempt to find an existing bridge named with the specified name. - i.Link, _ = netlink.LinkByName(i.Config.BridgeName) + i.Link, _ = netlink.LinkByName(config.BridgeName) return i } diff --git a/drivers/bridge/interface_test.go b/drivers/bridge/interface_test.go index c67cb1a..70689c5 100644 --- a/drivers/bridge/interface_test.go +++ b/drivers/bridge/interface_test.go @@ -10,8 +10,9 @@ import ( func TestInterfaceDefaultName(t *testing.T) { defer netutils.SetupTestNetNS(t)() - if inf := newInterface(&Configuration{}); inf.Config.BridgeName != DefaultBridgeName { - t.Fatalf("Expected default interface name %q, got %q", DefaultBridgeName, inf.Config.BridgeName) + config := &Configuration{} + if _ = newInterface(config); config.BridgeName != DefaultBridgeName { + t.Fatalf("Expected default interface name %q, got %q", DefaultBridgeName, config.BridgeName) } } diff --git a/drivers/bridge/network_test.go b/drivers/bridge/network_test.go index 7a413f0..02258fa 100644 --- a/drivers/bridge/network_test.go +++ b/drivers/bridge/network_test.go @@ -16,7 +16,11 @@ func TestLinkCreate(t *testing.T) { config := &Configuration{ BridgeName: DefaultBridgeName, EnableIPv6: true} - err := d.CreateNetwork("dummy", config) + if err := d.Config(config); err != nil { + t.Fatalf("Failed to setup driver config: %v", err) + } + + err := d.CreateNetwork("dummy", "") if err != nil { t.Fatalf("Failed to create bridge: %v", err) } @@ -69,7 +73,11 @@ func TestLinkCreateTwo(t *testing.T) { config := &Configuration{ BridgeName: DefaultBridgeName, EnableIPv6: true} - err := d.CreateNetwork("dummy", config) + if err := d.Config(config); err != nil { + t.Fatalf("Failed to setup driver config: %v", err) + } + + err := d.CreateNetwork("dummy", "") if err != nil { t.Fatalf("Failed to create bridge: %v", err) } @@ -95,7 +103,11 @@ func TestLinkCreateNoEnableIPv6(t *testing.T) { config := &Configuration{ BridgeName: DefaultBridgeName} - err := d.CreateNetwork("dummy", config) + if err := d.Config(config); err != nil { + t.Fatalf("Failed to setup driver config: %v", err) + } + + err := d.CreateNetwork("dummy", "") if err != nil { t.Fatalf("Failed to create bridge: %v", err) } diff --git a/drivers/bridge/setup.go b/drivers/bridge/setup.go index 26a80aa..90930bf 100644 --- a/drivers/bridge/setup.go +++ b/drivers/bridge/setup.go @@ -1,19 +1,20 @@ package bridge -type setupStep func(*bridgeInterface) error +type setupStep func(*Configuration, *bridgeInterface) error type bridgeSetup struct { + config *Configuration bridge *bridgeInterface steps []setupStep } -func newBridgeSetup(i *bridgeInterface) *bridgeSetup { - return &bridgeSetup{bridge: i} +func newBridgeSetup(c *Configuration, i *bridgeInterface) *bridgeSetup { + return &bridgeSetup{config: c, bridge: i} } func (b *bridgeSetup) apply() error { for _, fn := range b.steps { - if err := fn(b.bridge); err != nil { + if err := fn(b.config, b.bridge); err != nil { return err } } diff --git a/drivers/bridge/setup_device.go b/drivers/bridge/setup_device.go index 6717d94..9df031c 100644 --- a/drivers/bridge/setup_device.go +++ b/drivers/bridge/setup_device.go @@ -10,17 +10,17 @@ import ( ) // SetupDevice create a new bridge interface/ -func setupDevice(i *bridgeInterface) error { +func setupDevice(config *Configuration, i *bridgeInterface) error { // We only attempt to create the bridge when the requested device name is // the default one. - if i.Config.BridgeName != DefaultBridgeName { - return fmt.Errorf("bridge device with non default name %q must be created manually", i.Config.BridgeName) + if config.BridgeName != DefaultBridgeName && !config.AllowNonDefaultBridge { + return fmt.Errorf("bridge device with non default name %q must be created manually", config.BridgeName) } // Set the bridgeInterface netlink.Bridge. i.Link = &netlink.Bridge{ LinkAttrs: netlink.LinkAttrs{ - Name: i.Config.BridgeName, + Name: config.BridgeName, }, } @@ -37,7 +37,7 @@ func setupDevice(i *bridgeInterface) error { } // SetupDeviceUp ups the given bridge interface. -func setupDeviceUp(i *bridgeInterface) error { +func setupDeviceUp(config *Configuration, i *bridgeInterface) error { err := netlink.LinkSetUp(i.Link) if err != nil { return err @@ -45,7 +45,7 @@ func setupDeviceUp(i *bridgeInterface) error { // Attempt to update the bridge interface to refresh the flags status, // ignoring any failure to do so. - if lnk, err := netlink.LinkByName(i.Config.BridgeName); err == nil { + if lnk, err := netlink.LinkByName(config.BridgeName); err == nil { i.Link = lnk } return nil diff --git a/drivers/bridge/setup_device_test.go b/drivers/bridge/setup_device_test.go index 2202973..956b83d 100644 --- a/drivers/bridge/setup_device_test.go +++ b/drivers/bridge/setup_device_test.go @@ -13,12 +13,10 @@ import ( func TestSetupNewBridge(t *testing.T) { defer netutils.SetupTestNetNS(t)() - br := &bridgeInterface{ - Config: &Configuration{ - BridgeName: DefaultBridgeName, - }, - } - if err := setupDevice(br); err != nil { + config := &Configuration{BridgeName: DefaultBridgeName} + br := &bridgeInterface{} + + if err := setupDevice(config, br); err != nil { t.Fatalf("Bridge creation failed: %v", err) } if br.Link == nil { @@ -35,12 +33,10 @@ func TestSetupNewBridge(t *testing.T) { func TestSetupNewNonDefaultBridge(t *testing.T) { defer netutils.SetupTestNetNS(t)() - br := &bridgeInterface{ - Config: &Configuration{ - BridgeName: "test0", - }, - } - if err := setupDevice(br); err == nil || !strings.Contains(err.Error(), "non default name") { + config := &Configuration{BridgeName: "test0"} + br := &bridgeInterface{} + + if err := setupDevice(config, br); err == nil || !strings.Contains(err.Error(), "non default name") { t.Fatalf("Expected bridge creation failure with \"non default name\", got: %v", err) } } @@ -48,15 +44,13 @@ func TestSetupNewNonDefaultBridge(t *testing.T) { func TestSetupDeviceUp(t *testing.T) { defer netutils.SetupTestNetNS(t)() - br := &bridgeInterface{ - Config: &Configuration{ - BridgeName: DefaultBridgeName, - }, - } - if err := setupDevice(br); err != nil { + config := &Configuration{BridgeName: DefaultBridgeName} + br := &bridgeInterface{} + + if err := setupDevice(config, br); err != nil { t.Fatalf("Bridge creation failed: %v", err) } - if err := setupDeviceUp(br); err != nil { + if err := setupDeviceUp(config, br); err != nil { t.Fatalf("Failed to up bridge device: %v", err) } diff --git a/drivers/bridge/setup_fixedcidrv4.go b/drivers/bridge/setup_fixedcidrv4.go index 4c2b9b9..5e7cd4a 100644 --- a/drivers/bridge/setup_fixedcidrv4.go +++ b/drivers/bridge/setup_fixedcidrv4.go @@ -6,15 +6,15 @@ import ( log "github.com/Sirupsen/logrus" ) -func setupFixedCIDRv4(i *bridgeInterface) error { +func setupFixedCIDRv4(config *Configuration, i *bridgeInterface) error { addrv4, _, err := i.addresses() if err != nil { return err } - log.Debugf("Using IPv4 subnet: %v", i.Config.FixedCIDR) - if err := ipAllocator.RegisterSubnet(addrv4.IPNet, i.Config.FixedCIDR); err != nil { - return fmt.Errorf("Setup FixedCIDRv4 failed for subnet %s in %s: %v", i.Config.FixedCIDR, addrv4.IPNet, err) + log.Debugf("Using IPv4 subnet: %v", config.FixedCIDR) + if err := ipAllocator.RegisterSubnet(addrv4.IPNet, config.FixedCIDR); err != nil { + return fmt.Errorf("Setup FixedCIDRv4 failed for subnet %s in %s: %v", config.FixedCIDR, addrv4.IPNet, err) } return nil diff --git a/drivers/bridge/setup_fixedcidrv4_test.go b/drivers/bridge/setup_fixedcidrv4_test.go index 4f87895..87350db 100644 --- a/drivers/bridge/setup_fixedcidrv4_test.go +++ b/drivers/bridge/setup_fixedcidrv4_test.go @@ -10,25 +10,24 @@ import ( func TestSetupFixedCIDRv4(t *testing.T) { defer netutils.SetupTestNetNS(t)() - br := &bridgeInterface{ - Config: &Configuration{ - BridgeName: DefaultBridgeName, - AddressIPv4: &net.IPNet{IP: net.ParseIP("192.168.1.1"), Mask: net.CIDRMask(16, 32)}, - FixedCIDR: &net.IPNet{IP: net.ParseIP("192.168.2.0"), Mask: net.CIDRMask(24, 32)}, - }, - } - if err := setupDevice(br); err != nil { + config := &Configuration{ + BridgeName: DefaultBridgeName, + AddressIPv4: &net.IPNet{IP: net.ParseIP("192.168.1.1"), Mask: net.CIDRMask(16, 32)}, + FixedCIDR: &net.IPNet{IP: net.ParseIP("192.168.2.0"), Mask: net.CIDRMask(24, 32)}} + br := &bridgeInterface{} + + if err := setupDevice(config, br); err != nil { t.Fatalf("Bridge creation failed: %v", err) } - if err := setupBridgeIPv4(br); err != nil { + if err := setupBridgeIPv4(config, br); err != nil { t.Fatalf("Assign IPv4 to bridge failed: %v", err) } - if err := setupFixedCIDRv4(br); err != nil { + if err := setupFixedCIDRv4(config, br); err != nil { t.Fatalf("Failed to setup bridge FixedCIDRv4: %v", err) } - if ip, err := ipAllocator.RequestIP(br.Config.FixedCIDR, nil); err != nil { + if ip, err := ipAllocator.RequestIP(config.FixedCIDR, nil); err != nil { t.Fatalf("Failed to request IP to allocator: %v", err) } else if expected := "192.168.2.1"; ip.String() != expected { t.Fatalf("Expected allocated IP %s, got %s", expected, ip) @@ -38,21 +37,20 @@ func TestSetupFixedCIDRv4(t *testing.T) { func TestSetupBadFixedCIDRv4(t *testing.T) { defer netutils.SetupTestNetNS(t)() - br := &bridgeInterface{ - Config: &Configuration{ - BridgeName: DefaultBridgeName, - AddressIPv4: &net.IPNet{IP: net.ParseIP("192.168.1.1"), Mask: net.CIDRMask(24, 32)}, - FixedCIDR: &net.IPNet{IP: net.ParseIP("192.168.2.0"), Mask: net.CIDRMask(24, 32)}, - }, - } - if err := setupDevice(br); err != nil { + config := &Configuration{ + BridgeName: DefaultBridgeName, + AddressIPv4: &net.IPNet{IP: net.ParseIP("192.168.1.1"), Mask: net.CIDRMask(24, 32)}, + FixedCIDR: &net.IPNet{IP: net.ParseIP("192.168.2.0"), Mask: net.CIDRMask(24, 32)}} + br := &bridgeInterface{} + + if err := setupDevice(config, br); err != nil { t.Fatalf("Bridge creation failed: %v", err) } - if err := setupBridgeIPv4(br); err != nil { + if err := setupBridgeIPv4(config, br); err != nil { t.Fatalf("Assign IPv4 to bridge failed: %v", err) } - if err := setupFixedCIDRv4(br); err == nil { + if err := setupFixedCIDRv4(config, br); err == nil { t.Fatal("Setup bridge FixedCIDRv4 should have failed") } } diff --git a/drivers/bridge/setup_fixedcidrv6.go b/drivers/bridge/setup_fixedcidrv6.go index 6aca274..e6af3aa 100644 --- a/drivers/bridge/setup_fixedcidrv6.go +++ b/drivers/bridge/setup_fixedcidrv6.go @@ -6,10 +6,10 @@ import ( log "github.com/Sirupsen/logrus" ) -func setupFixedCIDRv6(i *bridgeInterface) error { - log.Debugf("Using IPv6 subnet: %v", i.Config.FixedCIDRv6) - if err := ipAllocator.RegisterSubnet(i.Config.FixedCIDRv6, i.Config.FixedCIDRv6); err != nil { - return fmt.Errorf("Setup FixedCIDRv6 failed for subnet %s in %s: %v", i.Config.FixedCIDRv6, i.Config.FixedCIDRv6, err) +func setupFixedCIDRv6(config *Configuration, i *bridgeInterface) error { + log.Debugf("Using IPv6 subnet: %v", config.FixedCIDRv6) + if err := ipAllocator.RegisterSubnet(config.FixedCIDRv6, config.FixedCIDRv6); err != nil { + return fmt.Errorf("Setup FixedCIDRv6 failed for subnet %s in %s: %v", config.FixedCIDRv6, config.FixedCIDRv6, err) } return nil diff --git a/drivers/bridge/setup_fixedcidrv6_test.go b/drivers/bridge/setup_fixedcidrv6_test.go index f106919..897fc54 100644 --- a/drivers/bridge/setup_fixedcidrv6_test.go +++ b/drivers/bridge/setup_fixedcidrv6_test.go @@ -10,25 +10,26 @@ import ( func TestSetupFixedCIDRv6(t *testing.T) { defer netutils.SetupTestNetNS(t)() - br := newInterface(&Configuration{}) + config := &Configuration{} + br := newInterface(config) - _, br.Config.FixedCIDRv6, _ = net.ParseCIDR("2002:db8::/48") - if err := setupDevice(br); err != nil { + _, config.FixedCIDRv6, _ = net.ParseCIDR("2002:db8::/48") + if err := setupDevice(config, br); err != nil { t.Fatalf("Bridge creation failed: %v", err) } - if err := setupBridgeIPv4(br); err != nil { + if err := setupBridgeIPv4(config, br); err != nil { t.Fatalf("Assign IPv4 to bridge failed: %v", err) } - if err := setupBridgeIPv6(br); err != nil { + if err := setupBridgeIPv6(config, br); err != nil { t.Fatalf("Assign IPv4 to bridge failed: %v", err) } - if err := setupFixedCIDRv6(br); err != nil { + if err := setupFixedCIDRv6(config, br); err != nil { t.Fatalf("Failed to setup bridge FixedCIDRv6: %v", err) } - if ip, err := ipAllocator.RequestIP(br.Config.FixedCIDRv6, nil); err != nil { + if ip, err := ipAllocator.RequestIP(config.FixedCIDRv6, nil); err != nil { t.Fatalf("Failed to request IP to allocator: %v", err) } else if expected := "2002:db8::1"; ip.String() != expected { t.Fatalf("Expected allocated IP %s, got %s", expected, ip) diff --git a/drivers/bridge/setup_ip_forwarding.go b/drivers/bridge/setup_ip_forwarding.go index 73e0bd0..7070638 100644 --- a/drivers/bridge/setup_ip_forwarding.go +++ b/drivers/bridge/setup_ip_forwarding.go @@ -10,9 +10,9 @@ const ( ipv4ForwardConfPerm = 0644 ) -func setupIPForwarding(i *bridgeInterface) error { +func setupIPForwarding(config *Configuration, i *bridgeInterface) error { // Sanity Check - if i.Config.EnableIPForwarding == false { + if config.EnableIPForwarding == false { return fmt.Errorf("Unexpected request to enable IP Forwarding for: %v", *i) } diff --git a/drivers/bridge/setup_ip_forwarding_test.go b/drivers/bridge/setup_ip_forwarding_test.go index 17d92a7..95838ad 100644 --- a/drivers/bridge/setup_ip_forwarding_test.go +++ b/drivers/bridge/setup_ip_forwarding_test.go @@ -18,15 +18,13 @@ func TestSetupIPForwarding(t *testing.T) { } // Create test interface with ip forwarding setting enabled - br := &bridgeInterface{ - Config: &Configuration{ - BridgeName: DefaultBridgeName, - EnableIPForwarding: true, - }, - } + config := &Configuration{ + BridgeName: DefaultBridgeName, + EnableIPForwarding: true} + br := &bridgeInterface{} // Set IP Forwarding - if err := setupIPForwarding(br); err != nil { + if err := setupIPForwarding(config, br); err != nil { t.Fatalf("Failed to setup IP forwarding: %v", err) } @@ -43,15 +41,13 @@ func TestUnexpectedSetupIPForwarding(t *testing.T) { defer reconcileIPForwardingSetting(t, procSetting) // Create test interface without ip forwarding setting enabled - br := &bridgeInterface{ - Config: &Configuration{ - BridgeName: DefaultBridgeName, - EnableIPForwarding: false, - }, - } + config := &Configuration{ + BridgeName: DefaultBridgeName, + EnableIPForwarding: false} + br := &bridgeInterface{} // Attempt Set IP Forwarding - if err := setupIPForwarding(br); err == nil { + if err := setupIPForwarding(config, br); err == nil { t.Fatal("Setup IP forwarding was expected to fail") } else if !strings.Contains(err.Error(), "Unexpected request") { t.Fatalf("Setup IP forwarding failed with unexpected error: %v", err) diff --git a/drivers/bridge/setup_ip_tables.go b/drivers/bridge/setup_ip_tables.go index 16ad7ab..b9ac418 100644 --- a/drivers/bridge/setup_ip_tables.go +++ b/drivers/bridge/setup_ip_tables.go @@ -13,26 +13,26 @@ const ( DockerChain = "DOCKER" ) -func setupIPTables(i *bridgeInterface) error { +func setupIPTables(config *Configuration, i *bridgeInterface) error { // Sanity check. - if i.Config.EnableIPTables == false { - return fmt.Errorf("Unexpected request to set IP tables for interface: %s", i.Config.BridgeName) + if config.EnableIPTables == false { + return fmt.Errorf("Unexpected request to set IP tables for interface: %s", config.BridgeName) } - addrv4, _, err := netutils.GetIfaceAddr(i.Config.BridgeName) + addrv4, _, err := netutils.GetIfaceAddr(config.BridgeName) if err != nil { return fmt.Errorf("Failed to setup IP tables, cannot acquire Interface address: %s", err.Error()) } - if err = setupIPTablesInternal(i.Config.BridgeName, addrv4, i.Config.EnableICC, i.Config.EnableIPMasquerade, true); err != nil { + if err = setupIPTablesInternal(config.BridgeName, addrv4, config.EnableICC, config.EnableIPMasquerade, true); err != nil { return fmt.Errorf("Failed to Setup IP tables: %s", err.Error()) } - _, err = iptables.NewChain(DockerChain, i.Config.BridgeName, iptables.Nat) + _, err = iptables.NewChain(DockerChain, config.BridgeName, iptables.Nat) if err != nil { return fmt.Errorf("Failed to create NAT chain: %s", err.Error()) } - chain, err := iptables.NewChain(DockerChain, i.Config.BridgeName, iptables.Filter) + chain, err := iptables.NewChain(DockerChain, config.BridgeName, iptables.Filter) if err != nil { return fmt.Errorf("Failed to create FILTER chain: %s", err.Error()) } diff --git a/drivers/bridge/setup_ip_tables_test.go b/drivers/bridge/setup_ip_tables_test.go index 733de95..5f00b6f 100644 --- a/drivers/bridge/setup_ip_tables_test.go +++ b/drivers/bridge/setup_ip_tables_test.go @@ -15,7 +15,7 @@ const ( func TestProgramIPTable(t *testing.T) { // Create a test bridge with a basic bridge configuration (name + IPv4). defer netutils.SetupTestNetNS(t)() - createTestBridge(getBasicTestConfig(), t) + createTestBridge(getBasicTestConfig(), &bridgeInterface{}, t) // Store various iptables chain rules we care for. rules := []struct { @@ -39,37 +39,37 @@ func TestProgramIPTable(t *testing.T) { func TestSetupIPTables(t *testing.T) { // Create a test bridge with a basic bridge configuration (name + IPv4). defer netutils.SetupTestNetNS(t)() - br := getBasicTestConfig() - createTestBridge(br, t) + config := getBasicTestConfig() + br := &bridgeInterface{} + + createTestBridge(config, br, t) // Modify iptables params in base configuration and apply them. - br.Config.EnableIPTables = true - assertBridgeConfig(br, t) + config.EnableIPTables = true + assertBridgeConfig(config, br, t) - br.Config.EnableIPMasquerade = true - assertBridgeConfig(br, t) + config.EnableIPMasquerade = true + assertBridgeConfig(config, br, t) - br.Config.EnableICC = true - assertBridgeConfig(br, t) + config.EnableICC = true + assertBridgeConfig(config, br, t) - br.Config.EnableIPMasquerade = false - assertBridgeConfig(br, t) + config.EnableIPMasquerade = false + assertBridgeConfig(config, br, t) } -func getBasicTestConfig() *bridgeInterface { - return &bridgeInterface{ - Config: &Configuration{ - BridgeName: DefaultBridgeName, - AddressIPv4: &net.IPNet{IP: net.ParseIP(iptablesTestBridgeIP), Mask: net.CIDRMask(16, 32)}, - }, - } +func getBasicTestConfig() *Configuration { + config := &Configuration{ + BridgeName: DefaultBridgeName, + AddressIPv4: &net.IPNet{IP: net.ParseIP(iptablesTestBridgeIP), Mask: net.CIDRMask(16, 32)}} + return config } -func createTestBridge(br *bridgeInterface, t *testing.T) { - if err := setupDevice(br); err != nil { +func createTestBridge(config *Configuration, br *bridgeInterface, t *testing.T) { + if err := setupDevice(config, br); err != nil { t.Fatalf("Failed to create the testing Bridge: %s", err.Error()) } - if err := setupBridgeIPv4(br); err != nil { + if err := setupBridgeIPv4(config, br); err != nil { t.Fatalf("Failed to bring up the testing Bridge: %s", err.Error()) } } @@ -94,9 +94,9 @@ func assertIPTableChainProgramming(rule iptRule, descr string, t *testing.T) { } // Assert function which pushes chains based on bridge config parameters. -func assertBridgeConfig(br *bridgeInterface, t *testing.T) { +func assertBridgeConfig(config *Configuration, br *bridgeInterface, t *testing.T) { // Attempt programming of ip tables. - err := setupIPTables(br) + err := setupIPTables(config, br) if err != nil { t.Fatalf("%v", err) } diff --git a/drivers/bridge/setup_ipv4.go b/drivers/bridge/setup_ipv4.go index 9ecf4cb..5f97bbb 100644 --- a/drivers/bridge/setup_ipv4.go +++ b/drivers/bridge/setup_ipv4.go @@ -41,13 +41,13 @@ func init() { } } -func setupBridgeIPv4(i *bridgeInterface) error { - bridgeIPv4, err := electBridgeIPv4(i.Config) +func setupBridgeIPv4(config *Configuration, i *bridgeInterface) error { + bridgeIPv4, err := electBridgeIPv4(config) if err != nil { return err } - log.Debugf("Creating bridge interface %q with network %s", i.Config.BridgeName, bridgeIPv4) + log.Debugf("Creating bridge interface %q with network %s", config.BridgeName, bridgeIPv4) if err := netlink.AddrAdd(i.Link, &netlink.Addr{IPNet: bridgeIPv4}); err != nil { return fmt.Errorf("Failed to add IPv4 address %s to bridge: %v", bridgeIPv4, err) } diff --git a/drivers/bridge/setup_ipv4_test.go b/drivers/bridge/setup_ipv4_test.go index 2e148f5..67f44af 100644 --- a/drivers/bridge/setup_ipv4_test.go +++ b/drivers/bridge/setup_ipv4_test.go @@ -8,16 +8,15 @@ import ( "github.com/vishvananda/netlink" ) -func setupTestInterface(t *testing.T) *bridgeInterface { - br := &bridgeInterface{ - Config: &Configuration{ - BridgeName: DefaultBridgeName, - }, - } - if err := setupDevice(br); err != nil { +func setupTestInterface(t *testing.T) (*Configuration, *bridgeInterface) { + config := &Configuration{ + BridgeName: DefaultBridgeName} + br := &bridgeInterface{} + + if err := setupDevice(config, br); err != nil { t.Fatalf("Bridge creation failed: %v", err) } - return br + return config, br } func TestSetupBridgeIPv4Fixed(t *testing.T) { @@ -28,9 +27,9 @@ func TestSetupBridgeIPv4Fixed(t *testing.T) { t.Fatalf("Failed to parse bridge IPv4: %v", err) } - br := setupTestInterface(t) - br.Config.AddressIPv4 = &net.IPNet{IP: ip, Mask: netw.Mask} - if err := setupBridgeIPv4(br); err != nil { + config, br := setupTestInterface(t) + config.AddressIPv4 = &net.IPNet{IP: ip, Mask: netw.Mask} + if err := setupBridgeIPv4(config, br); err != nil { t.Fatalf("Failed to setup bridge IPv4: %v", err) } @@ -41,22 +40,22 @@ func TestSetupBridgeIPv4Fixed(t *testing.T) { var found bool for _, addr := range addrsv4 { - if br.Config.AddressIPv4.String() == addr.IPNet.String() { + if config.AddressIPv4.String() == addr.IPNet.String() { found = true break } } if !found { - t.Fatalf("Bridge device does not have requested IPv4 address %v", br.Config.AddressIPv4) + t.Fatalf("Bridge device does not have requested IPv4 address %v", config.AddressIPv4) } } func TestSetupBridgeIPv4Auto(t *testing.T) { defer netutils.SetupTestNetNS(t)() - br := setupTestInterface(t) - if err := setupBridgeIPv4(br); err != nil { + config, br := setupTestInterface(t) + if err := setupBridgeIPv4(config, br); err != nil { t.Fatalf("Failed to setup bridge IPv4: %v", err) } diff --git a/drivers/bridge/setup_ipv6.go b/drivers/bridge/setup_ipv6.go index bb61387..0d6033f 100644 --- a/drivers/bridge/setup_ipv6.go +++ b/drivers/bridge/setup_ipv6.go @@ -22,9 +22,9 @@ func init() { } } -func setupBridgeIPv6(i *bridgeInterface) error { +func setupBridgeIPv6(config *Configuration, i *bridgeInterface) error { // Enable IPv6 on the bridge - procFile := "/proc/sys/net/ipv6/conf/" + i.Config.BridgeName + "/disable_ipv6" + procFile := "/proc/sys/net/ipv6/conf/" + config.BridgeName + "/disable_ipv6" if err := ioutil.WriteFile(procFile, []byte{'0', '\n'}, 0644); err != nil { return fmt.Errorf("Unable to enable IPv6 addresses on bridge: %v", err) } diff --git a/drivers/bridge/setup_ipv6_test.go b/drivers/bridge/setup_ipv6_test.go index 24edcd3..a13c5c0 100644 --- a/drivers/bridge/setup_ipv6_test.go +++ b/drivers/bridge/setup_ipv6_test.go @@ -13,12 +13,12 @@ import ( func TestSetupIPv6(t *testing.T) { defer netutils.SetupTestNetNS(t)() - br := setupTestInterface(t) - if err := setupBridgeIPv6(br); err != nil { + config, br := setupTestInterface(t) + if err := setupBridgeIPv6(config, br); err != nil { t.Fatalf("Failed to setup bridge IPv6: %v", err) } - procSetting, err := ioutil.ReadFile(fmt.Sprintf("/proc/sys/net/ipv6/conf/%s/disable_ipv6", br.Config.BridgeName)) + procSetting, err := ioutil.ReadFile(fmt.Sprintf("/proc/sys/net/ipv6/conf/%s/disable_ipv6", config.BridgeName)) if err != nil { t.Fatalf("Failed to read disable_ipv6 kernel setting: %v", err) } diff --git a/drivers/bridge/setup_verify.go b/drivers/bridge/setup_verify.go index 892a155..0c995c3 100644 --- a/drivers/bridge/setup_verify.go +++ b/drivers/bridge/setup_verify.go @@ -6,7 +6,7 @@ import ( "github.com/vishvananda/netlink" ) -func setupVerifyConfiguredAddresses(i *bridgeInterface) error { +func setupVerifyConfiguredAddresses(config *Configuration, i *bridgeInterface) error { // Fetch a single IPv4 and a slice of IPv6 addresses from the bridge. addrv4, addrsv6, err := i.addresses() if err != nil { @@ -19,13 +19,13 @@ func setupVerifyConfiguredAddresses(i *bridgeInterface) error { } // Verify that the bridge IPv4 address matches the requested configuration. - if i.Config.AddressIPv4 != nil && !addrv4.IP.Equal(i.Config.AddressIPv4.IP) { - return fmt.Errorf("Bridge IPv4 (%s) does not match requested configuration %s", addrv4.IP, i.Config.AddressIPv4.IP) + if config.AddressIPv4 != nil && !addrv4.IP.Equal(config.AddressIPv4.IP) { + return fmt.Errorf("Bridge IPv4 (%s) does not match requested configuration %s", addrv4.IP, config.AddressIPv4.IP) } // Verify that one of the bridge IPv6 addresses matches the requested // configuration. - if i.Config.EnableIPv6 && !findIPv6Address(netlink.Addr{IPNet: bridgeIPv6}, addrsv6) { + if config.EnableIPv6 && !findIPv6Address(netlink.Addr{IPNet: bridgeIPv6}, addrsv6) { return fmt.Errorf("Bridge IPv6 addresses do not match the expected bridge configuration %s", bridgeIPv6) } diff --git a/drivers/bridge/setup_verify_test.go b/drivers/bridge/setup_verify_test.go index 3555c31..6559860 100644 --- a/drivers/bridge/setup_verify_test.go +++ b/drivers/bridge/setup_verify_test.go @@ -9,7 +9,7 @@ import ( ) func setupVerifyTest(t *testing.T) *bridgeInterface { - inf := &bridgeInterface{Config: &Configuration{}} + inf := &bridgeInterface{} br := netlink.Bridge{} br.LinkAttrs.Name = "default0" @@ -27,13 +27,14 @@ func TestSetupVerify(t *testing.T) { addrv4 := net.IPv4(192, 168, 1, 1) inf := setupVerifyTest(t) - inf.Config.AddressIPv4 = &net.IPNet{IP: addrv4, Mask: addrv4.DefaultMask()} + config := &Configuration{} + config.AddressIPv4 = &net.IPNet{IP: addrv4, Mask: addrv4.DefaultMask()} - if err := netlink.AddrAdd(inf.Link, &netlink.Addr{IPNet: inf.Config.AddressIPv4}); err != nil { - t.Fatalf("Failed to assign IPv4 %s to interface: %v", inf.Config.AddressIPv4, err) + if err := netlink.AddrAdd(inf.Link, &netlink.Addr{IPNet: config.AddressIPv4}); err != nil { + t.Fatalf("Failed to assign IPv4 %s to interface: %v", config.AddressIPv4, err) } - if err := setupVerifyConfiguredAddresses(inf); err != nil { + if err := setupVerifyConfiguredAddresses(config, inf); err != nil { t.Fatalf("Address verification failed: %v", err) } } @@ -43,14 +44,15 @@ func TestSetupVerifyBad(t *testing.T) { addrv4 := net.IPv4(192, 168, 1, 1) inf := setupVerifyTest(t) - inf.Config.AddressIPv4 = &net.IPNet{IP: addrv4, Mask: addrv4.DefaultMask()} + config := &Configuration{} + config.AddressIPv4 = &net.IPNet{IP: addrv4, Mask: addrv4.DefaultMask()} ipnet := &net.IPNet{IP: net.IPv4(192, 168, 1, 2), Mask: addrv4.DefaultMask()} if err := netlink.AddrAdd(inf.Link, &netlink.Addr{IPNet: ipnet}); err != nil { t.Fatalf("Failed to assign IPv4 %s to interface: %v", ipnet, err) } - if err := setupVerifyConfiguredAddresses(inf); err == nil { + if err := setupVerifyConfiguredAddresses(config, inf); err == nil { t.Fatal("Address verification was expected to fail") } } @@ -60,9 +62,10 @@ func TestSetupVerifyMissing(t *testing.T) { addrv4 := net.IPv4(192, 168, 1, 1) inf := setupVerifyTest(t) - inf.Config.AddressIPv4 = &net.IPNet{IP: addrv4, Mask: addrv4.DefaultMask()} + config := &Configuration{} + config.AddressIPv4 = &net.IPNet{IP: addrv4, Mask: addrv4.DefaultMask()} - if err := setupVerifyConfiguredAddresses(inf); err == nil { + if err := setupVerifyConfiguredAddresses(config, inf); err == nil { t.Fatal("Address verification was expected to fail") } } @@ -72,17 +75,18 @@ func TestSetupVerifyIPv6(t *testing.T) { addrv4 := net.IPv4(192, 168, 1, 1) inf := setupVerifyTest(t) - inf.Config.AddressIPv4 = &net.IPNet{IP: addrv4, Mask: addrv4.DefaultMask()} - inf.Config.EnableIPv6 = true + config := &Configuration{} + config.AddressIPv4 = &net.IPNet{IP: addrv4, Mask: addrv4.DefaultMask()} + config.EnableIPv6 = true if err := netlink.AddrAdd(inf.Link, &netlink.Addr{IPNet: bridgeIPv6}); err != nil { t.Fatalf("Failed to assign IPv6 %s to interface: %v", bridgeIPv6, err) } - if err := netlink.AddrAdd(inf.Link, &netlink.Addr{IPNet: inf.Config.AddressIPv4}); err != nil { - t.Fatalf("Failed to assign IPv4 %s to interface: %v", inf.Config.AddressIPv4, err) + if err := netlink.AddrAdd(inf.Link, &netlink.Addr{IPNet: config.AddressIPv4}); err != nil { + t.Fatalf("Failed to assign IPv4 %s to interface: %v", config.AddressIPv4, err) } - if err := setupVerifyConfiguredAddresses(inf); err != nil { + if err := setupVerifyConfiguredAddresses(config, inf); err != nil { t.Fatalf("Address verification failed: %v", err) } } @@ -92,14 +96,15 @@ func TestSetupVerifyIPv6Missing(t *testing.T) { addrv4 := net.IPv4(192, 168, 1, 1) inf := setupVerifyTest(t) - inf.Config.AddressIPv4 = &net.IPNet{IP: addrv4, Mask: addrv4.DefaultMask()} - inf.Config.EnableIPv6 = true + config := &Configuration{} + config.AddressIPv4 = &net.IPNet{IP: addrv4, Mask: addrv4.DefaultMask()} + config.EnableIPv6 = true - if err := netlink.AddrAdd(inf.Link, &netlink.Addr{IPNet: inf.Config.AddressIPv4}); err != nil { - t.Fatalf("Failed to assign IPv4 %s to interface: %v", inf.Config.AddressIPv4, err) + if err := netlink.AddrAdd(inf.Link, &netlink.Addr{IPNet: config.AddressIPv4}); err != nil { + t.Fatalf("Failed to assign IPv4 %s to interface: %v", config.AddressIPv4, err) } - if err := setupVerifyConfiguredAddresses(inf); err == nil { + if err := setupVerifyConfiguredAddresses(config, inf); err == nil { t.Fatal("Address verification was expected to fail") } } diff --git a/libnetwork_test.go b/libnetwork_test.go index ffa20fb..f122ef2 100644 --- a/libnetwork_test.go +++ b/libnetwork_test.go @@ -1,7 +1,6 @@ package libnetwork_test import ( - "flag" "net" "testing" @@ -12,14 +11,9 @@ import ( "github.com/vishvananda/netlink" ) -var bridgeName = "docker0" -var enableBridgeTest = flag.Bool("enable-bridge-test", false, "") +var bridgeName = "dockertest0" func TestSimplebridge(t *testing.T) { - if *enableBridgeTest == false { - t.Skip() - } - bridge := &netlink.Bridge{LinkAttrs: netlink.LinkAttrs{Name: bridgeName}} netlink.LinkDel(bridge) @@ -43,23 +37,38 @@ func TestSimplebridge(t *testing.T) { log.Debug("Adding a simple bridge") options := options.Generic{ - "BridgeName": bridgeName, - "AddressIPv4": subnet, - "FixedCIDR": cidr, - "FixedCIDRv6": cidrv6, - "EnableIPv6": true, - "EnableIPTables": true, - "EnableIPMasquerade": true, - "EnableICC": true, - "EnableIPForwarding": true} + "BridgeName": bridgeName, + "AddressIPv4": subnet, + "FixedCIDR": cidr, + "FixedCIDRv6": cidrv6, + "EnableIPv6": true, + "EnableIPTables": true, + "EnableIPMasquerade": true, + "EnableICC": true, + "EnableIPForwarding": true, + "AllowNonDefaultBridge": true} controller := libnetwork.New() - network, err := controller.NewNetwork("simplebridge", "dummy", options) + driver, err := controller.NewNetworkDriver("simplebridge", options) if err != nil { t.Fatal(err) } + network, err := controller.NewNetwork(driver, "testnetwork", "") + if err != nil { + t.Fatal(err) + } + + ep, _, err := network.CreateEndpoint("testep", "", "") + if err != nil { + t.Fatal(err) + } + + if err := ep.Delete(); err != nil { + t.Fatal(err) + } + if err := network.Delete(); err != nil { t.Fatal(err) } diff --git a/network.go b/network.go index 8b7361c..67ca1f4 100644 --- a/network.go +++ b/network.go @@ -5,9 +5,17 @@ create network namespaces and allocate interfaces for containers to use. // Create a new controller instance controller := libnetwork.New() -options := options.Generic{} +// This option is only needed for in-tree drivers. Plugins(in future) will get +// their options through plugin infrastructure. +option := options.Generic{} +driver, err := controller.NewNetworkDriver("simplebridge", option) +if err != nil { + return +} + +netOptions := options.Generic{} // Create a network for containers to join. -network, err := controller.NewNetwork("simplebridge", "network1", options) +network, err := controller.NewNetwork(driver, "network1", netOptions) if err != nil { return } @@ -53,13 +61,14 @@ import ( // NetworkController provides the interface for controller instance which manages // networks. type NetworkController interface { + NewNetworkDriver(networkType string, options interface{}) (*NetworkDriver, error) // Create a new network. The options parameter carry driver specific options. // Labels support will be added in the near future. - NewNetwork(networkType, name string, options interface{}) (Network, error) + NewNetwork(d *NetworkDriver, name string, options interface{}) (Network, error) } // A Network represents a logical connectivity zone that containers may -// ulteriorly join using the Link method. A Network is managed by a specific +// ulteriorly join using the CreateEndpoint method. A Network is managed by a specific // driver. type Network interface { // A user chosen name for this network. @@ -86,6 +95,11 @@ type Endpoint interface { Delete() error } +// NetworkDriver provides a reference to driver and way to push driver specific config +type NetworkDriver struct { + internalDriver driverapi.Driver +} + type endpoint struct { name string id driverapi.UUID @@ -98,11 +112,13 @@ type network struct { name string networkType string id driverapi.UUID - endpoints map[driverapi.UUID]*endpoint + driver *NetworkDriver + endpoints endpointTable sync.Mutex } type networkTable map[driverapi.UUID]*network +type endpointTable map[driverapi.UUID]*endpoint type controller struct { networks networkTable @@ -115,18 +131,34 @@ func New() NetworkController { return &controller{networkTable{}, enumerateDrivers(), sync.Mutex{}} } -// NewNetwork creates a new network of the specified networkType. The options -// are driver specific and modeled in a generic way. -func (c *controller) NewNetwork(networkType, name string, options interface{}) (Network, error) { - network := &network{name: name, networkType: networkType} - network.id = driverapi.UUID(common.GenerateRandomID()) - network.ctrlr = c - +func (c *controller) NewNetworkDriver(networkType string, options interface{}) (*NetworkDriver, error) { d, ok := c.drivers[networkType] if !ok { return nil, fmt.Errorf("unknown driver %q", networkType) } + if err := d.Config(options); err != nil { + return nil, err + } + + return &NetworkDriver{internalDriver: d}, nil +} + +// NewNetwork creates a new network of the specified networkType. The options +// are driver specific and modeled in a generic way. +func (c *controller) NewNetwork(nd *NetworkDriver, name string, options interface{}) (Network, error) { + network := &network{ + name: name, + id: driverapi.UUID(common.GenerateRandomID()), + ctrlr: c, + driver: nd} + network.endpoints = make(endpointTable) + + d := network.driver.internalDriver + if d == nil { + return nil, fmt.Errorf("invalid driver bound to network") + } + if err := d.CreateNetwork(network.id, options); err != nil { return nil, err } @@ -153,13 +185,8 @@ func (n *network) Type() string { func (n *network) Delete() error { var err error - d, ok := n.ctrlr.drivers[n.networkType] - if !ok { - return fmt.Errorf("unknown driver %q", n.networkType) - } - n.ctrlr.Lock() - _, ok = n.ctrlr.networks[n.id] + _, ok := n.ctrlr.networks[n.id] if !ok { n.ctrlr.Unlock() return fmt.Errorf("unknown network %s id %s", n.name, n.id) @@ -183,6 +210,7 @@ func (n *network) Delete() error { } }() + d := n.driver.internalDriver err = d.DeleteNetwork(n.id) return err } @@ -192,11 +220,7 @@ func (n *network) CreateEndpoint(name string, sboxKey string, options interface{ ep.id = driverapi.UUID(common.GenerateRandomID()) ep.network = n - d, ok := n.ctrlr.drivers[n.networkType] - if !ok { - return nil, nil, fmt.Errorf("unknown driver %q", n.networkType) - } - + d := n.driver.internalDriver sinfo, err := d.CreateEndpoint(n.id, ep.id, sboxKey, options) if err != nil { return nil, nil, err @@ -212,14 +236,9 @@ func (n *network) CreateEndpoint(name string, sboxKey string, options interface{ func (ep *endpoint) Delete() error { var err error - d, ok := ep.network.ctrlr.drivers[ep.network.networkType] - if !ok { - return fmt.Errorf("unknown driver %q", ep.network.networkType) - } - n := ep.network n.Lock() - _, ok = n.endpoints[ep.id] + _, ok := n.endpoints[ep.id] if !ok { n.Unlock() return fmt.Errorf("unknown endpoint %s id %s", ep.name, ep.id) @@ -235,6 +254,7 @@ func (ep *endpoint) Delete() error { } }() + d := n.driver.internalDriver err = d.DeleteEndpoint(n.id, ep.id) return err }