From 2e40befd82befe38fc5d6311a2006fa09a9a4df2 Mon Sep 17 00:00:00 2001 From: Madhu Venugopal Date: Sat, 6 Jun 2015 10:21:51 -0700 Subject: [PATCH] Replacing isReservedNetwork with Driver capability Currently store makes use of a static isReservedNetwork check to decide if a network needs to be stored in the distributed store or not. But it is better if the check is not static, but be determined based on the capability of the driver that backs the network. Hence introducing a new capability mechanism to the driver which it can express its capability during registration. Making use of first such capability : Scope. This can be expanded in the future for more such cases. Signed-off-by: Madhu Venugopal --- controller.go | 42 ++++++++++++++++++++++++++++--------- driverapi/driverapi.go | 17 ++++++++++++++- drivers/bridge/bridge.go | 5 ++++- drivers/host/host.go | 5 ++++- drivers/null/null.go | 5 ++++- drivers/remote/driver.go | 5 ++++- drivers/windows/windows.go | 5 ++++- drivers_freebsd.go | 2 -- drivers_linux.go | 2 -- drivers_windows.go | 2 -- libnetwork_internal_test.go | 4 ++-- network.go | 14 +++++-------- store.go | 28 ++++++++++++++++--------- 13 files changed, 93 insertions(+), 43 deletions(-) diff --git a/controller.go b/controller.go index d11ffda..35f945e 100644 --- a/controller.go +++ b/controller.go @@ -92,6 +92,12 @@ type NetworkController interface { // When the function returns true, the walk will stop. type NetworkWalker func(nw Network) bool +type driverData struct { + driver driverapi.Driver + capability driverapi.Capability +} + +type driverTable map[string]*driverData type networkTable map[types.UUID]*network type endpointTable map[types.UUID]*endpoint type sandboxTable map[string]*sandboxData @@ -175,21 +181,21 @@ func (c *controller) hostLeaveCallback(hosts []net.IP) { func (c *controller) ConfigureNetworkDriver(networkType string, options map[string]interface{}) error { c.Lock() - d, ok := c.drivers[networkType] + dd, ok := c.drivers[networkType] c.Unlock() if !ok { return NetworkTypeError(networkType) } - return d.Config(options) + return dd.driver.Config(options) } -func (c *controller) RegisterDriver(networkType string, driver driverapi.Driver) error { +func (c *controller) RegisterDriver(networkType string, driver driverapi.Driver, capability driverapi.Capability) error { c.Lock() defer c.Unlock() if _, ok := c.drivers[networkType]; ok { return driverapi.ErrActiveRegistration(networkType) } - c.drivers[networkType] = driver + c.drivers[networkType] = &driverData{driver, capability} return nil } @@ -238,18 +244,21 @@ func (c *controller) addNetwork(n *network) error { c.Lock() // Check if a driver for the specified network type is available - d, ok := c.drivers[n.networkType] + dd, ok := c.drivers[n.networkType] c.Unlock() if !ok { var err error - d, err = c.loadDriver(n.networkType) + dd, err = c.loadDriver(n.networkType) if err != nil { return err } } - n.driver = d + n.Lock() + n.driver = dd.driver + d := n.driver + n.Unlock() // Create the network if err := d.CreateNetwork(n.id, n.generic); err != nil { @@ -317,7 +326,7 @@ func (c *controller) NetworkByID(id string) (Network, error) { return nil, ErrNoSuchNetwork(id) } -func (c *controller) loadDriver(networkType string) (driverapi.Driver, error) { +func (c *controller) loadDriver(networkType string) (*driverData, error) { // Plugins pkg performs lazy loading of plugins that acts as remote drivers. // As per the design, this Get call will result in remote driver discovery if there is a corresponding plugin available. _, err := plugins.Get(networkType, driverapi.NetworkPluginEndpointType) @@ -329,11 +338,24 @@ func (c *controller) loadDriver(networkType string) (driverapi.Driver, error) { } c.Lock() defer c.Unlock() - d, ok := c.drivers[networkType] + dd, ok := c.drivers[networkType] if !ok { return nil, ErrInvalidNetworkDriver(networkType) } - return d, nil + return dd, nil +} + +func (c *controller) isDriverGlobalScoped(networkType string) (bool, error) { + c.Lock() + dd, ok := c.drivers[networkType] + c.Unlock() + if !ok { + return false, types.NotFoundErrorf("driver not found for %s", networkType) + } + if dd.capability.Scope == driverapi.GlobalScope { + return true, nil + } + return false, nil } func (c *controller) GC() { diff --git a/driverapi/driverapi.go b/driverapi/driverapi.go index 45c136d..e53947d 100644 --- a/driverapi/driverapi.go +++ b/driverapi/driverapi.go @@ -118,5 +118,20 @@ type JoinInfo interface { // DriverCallback provides a Callback interface for Drivers into LibNetwork type DriverCallback interface { // RegisterDriver provides a way for Remote drivers to dynamically register new NetworkType and associate with a driver instance - RegisterDriver(name string, driver Driver) error + RegisterDriver(name string, driver Driver, capability Capability) error +} + +// Scope indicates the drivers scope capability +type Scope int + +const ( + // LocalScope represents the driver capable of providing networking services for containers in a single host + LocalScope Scope = iota + // GlobalScope represents the driver capable of providing networking services for containers across hosts + GlobalScope +) + +// Capability represents the high level capabilities of the drivers which libnetwork can make use of +type Capability struct { + Scope Scope } diff --git a/drivers/bridge/bridge.go b/drivers/bridge/bridge.go index ce58ddb..33326e7 100644 --- a/drivers/bridge/bridge.go +++ b/drivers/bridge/bridge.go @@ -110,7 +110,10 @@ func Init(dc driverapi.DriverCallback) error { if out, err := exec.Command("modprobe", "-va", "bridge", "nf_nat", "br_netfilter").Output(); err != nil { logrus.Warnf("Running modprobe bridge nf_nat failed with message: %s, error: %v", out, err) } - return dc.RegisterDriver(networkType, newDriver()) + c := driverapi.Capability{ + Scope: driverapi.LocalScope, + } + return dc.RegisterDriver(networkType, newDriver(), c) } // Validate performs a static validation on the network configuration parameters. diff --git a/drivers/host/host.go b/drivers/host/host.go index 8698766..072cc89 100644 --- a/drivers/host/host.go +++ b/drivers/host/host.go @@ -16,7 +16,10 @@ type driver struct { // Init registers a new instance of host driver func Init(dc driverapi.DriverCallback) error { - return dc.RegisterDriver(networkType, &driver{}) + c := driverapi.Capability{ + Scope: driverapi.LocalScope, + } + return dc.RegisterDriver(networkType, &driver{}, c) } func (d *driver) Config(option map[string]interface{}) error { diff --git a/drivers/null/null.go b/drivers/null/null.go index 26f9d00..d1f2797 100644 --- a/drivers/null/null.go +++ b/drivers/null/null.go @@ -16,7 +16,10 @@ type driver struct { // Init registers a new instance of null driver func Init(dc driverapi.DriverCallback) error { - return dc.RegisterDriver(networkType, &driver{}) + c := driverapi.Capability{ + Scope: driverapi.LocalScope, + } + return dc.RegisterDriver(networkType, &driver{}, c) } func (d *driver) Config(option map[string]interface{}) error { diff --git a/drivers/remote/driver.go b/drivers/remote/driver.go index 858064c..1395933 100644 --- a/drivers/remote/driver.go +++ b/drivers/remote/driver.go @@ -23,7 +23,10 @@ func newDriver(name string, client *plugins.Client) driverapi.Driver { // plugin is activated. func Init(dc driverapi.DriverCallback) error { plugins.Handle(driverapi.NetworkPluginEndpointType, func(name string, client *plugins.Client) { - if err := dc.RegisterDriver(name, newDriver(name, client)); err != nil { + c := driverapi.Capability{ + Scope: driverapi.GlobalScope, + } + if err := dc.RegisterDriver(name, newDriver(name, client), c); err != nil { log.Errorf("error registering driver for %s due to %v", name, err) } }) diff --git a/drivers/windows/windows.go b/drivers/windows/windows.go index 8606a6f..925e402 100644 --- a/drivers/windows/windows.go +++ b/drivers/windows/windows.go @@ -13,7 +13,10 @@ type driver struct{} // Init registers a new instance of null driver func Init(dc driverapi.DriverCallback) error { - return dc.RegisterDriver(networkType, &driver{}) + c := driverapi.Capability{ + Scope: driverapi.LocalScope, + } + return dc.RegisterDriver(networkType, &driver{}, c) } func (d *driver) Config(option map[string]interface{}) error { diff --git a/drivers_freebsd.go b/drivers_freebsd.go index c693d7c..683af06 100644 --- a/drivers_freebsd.go +++ b/drivers_freebsd.go @@ -6,8 +6,6 @@ import ( "github.com/docker/libnetwork/drivers/remote" ) -type driverTable map[string]driverapi.Driver - func initDrivers(dc driverapi.DriverCallback) error { for _, fn := range [](func(driverapi.DriverCallback) error){ null.Init, diff --git a/drivers_linux.go b/drivers_linux.go index 130f7ab..7de28f9 100644 --- a/drivers_linux.go +++ b/drivers_linux.go @@ -8,8 +8,6 @@ import ( "github.com/docker/libnetwork/drivers/remote" ) -type driverTable map[string]driverapi.Driver - func initDrivers(dc driverapi.DriverCallback) error { for _, fn := range [](func(driverapi.DriverCallback) error){ bridge.Init, diff --git a/drivers_windows.go b/drivers_windows.go index b1ab31e..334cd7c 100644 --- a/drivers_windows.go +++ b/drivers_windows.go @@ -5,8 +5,6 @@ import ( "github.com/docker/libnetwork/drivers/windows" ) -type driverTable map[string]driverapi.Driver - func initDrivers(dc driverapi.DriverCallback) error { for _, fn := range [](func(driverapi.DriverCallback) error){ windows.Init, diff --git a/libnetwork_internal_test.go b/libnetwork_internal_test.go index 3778921..23a0a54 100644 --- a/libnetwork_internal_test.go +++ b/libnetwork_internal_test.go @@ -13,14 +13,14 @@ func TestDriverRegistration(t *testing.T) { if err != nil { t.Fatal(err) } - err = c.(*controller).RegisterDriver(bridgeNetType, nil) + err = c.(*controller).RegisterDriver(bridgeNetType, nil, driverapi.Capability{}) if err == nil { t.Fatalf("Expecting the RegisterDriver to fail for %s", bridgeNetType) } if _, ok := err.(driverapi.ErrActiveRegistration); !ok { t.Fatalf("Failed for unexpected reason: %v", err) } - err = c.(*controller).RegisterDriver("test-dummy", nil) + err = c.(*controller).RegisterDriver("test-dummy", nil, driverapi.Capability{}) if err != nil { t.Fatalf("Test failed with an error %v", err) } diff --git a/network.go b/network.go index 88398f8..8f3e799 100644 --- a/network.go +++ b/network.go @@ -2,7 +2,6 @@ package libnetwork import ( "encoding/json" - "strings" "sync" log "github.com/Sirupsen/logrus" @@ -377,12 +376,9 @@ func (n *network) EndpointByID(id string) (Endpoint, error) { return nil, ErrNoSuchEndpoint(id) } -func isReservedNetwork(name string) bool { - reserved := []string{"bridge", "none", "host"} - for _, r := range reserved { - if strings.EqualFold(r, name) { - return true - } - } - return false +func (n *network) isGlobalScoped() (bool, error) { + n.Lock() + c := n.ctrlr + n.Unlock() + return c.isDriverGlobalScoped(n.networkType) } diff --git a/store.go b/store.go index a7c47c8..c72d739 100644 --- a/store.go +++ b/store.go @@ -37,8 +37,9 @@ func (c *controller) newNetworkFromStore(n *network) error { } func (c *controller) updateNetworkToStore(n *network) error { - if isReservedNetwork(n.Name()) { - return nil + global, err := n.isGlobalScoped() + if err != nil || !global { + return err } c.Lock() cs := c.store @@ -52,8 +53,9 @@ func (c *controller) updateNetworkToStore(n *network) error { } func (c *controller) deleteNetworkFromStore(n *network) error { - if isReservedNetwork(n.Name()) { - return nil + global, err := n.isGlobalScoped() + if err != nil || !global { + return err } c.Lock() cs := c.store @@ -111,12 +113,13 @@ func (c *controller) newEndpointFromStore(key string, ep *endpoint) error { func (c *controller) updateEndpointToStore(ep *endpoint) error { ep.Lock() + n := ep.network name := ep.name - if isReservedNetwork(ep.network.name) { - ep.Unlock() - return nil - } ep.Unlock() + global, err := n.isGlobalScoped() + if err != nil || !global { + return err + } c.Lock() cs := c.store c.Unlock() @@ -137,9 +140,14 @@ func (c *controller) getEndpointFromStore(eid types.UUID) (*endpoint, error) { } func (c *controller) deleteEndpointFromStore(ep *endpoint) error { - if isReservedNetwork(ep.network.Name()) { - return nil + ep.Lock() + n := ep.network + ep.Unlock() + global, err := n.isGlobalScoped() + if err != nil || !global { + return err } + c.Lock() cs := c.store c.Unlock()