Browse code

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 <madhu@docker.com>

Madhu Venugopal authored on 2015/06/07 02:21:51
Showing 13 changed files
... ...
@@ -92,6 +92,12 @@ type NetworkController interface {
92 92
 // When the function returns true, the walk will stop.
93 93
 type NetworkWalker func(nw Network) bool
94 94
 
95
+type driverData struct {
96
+	driver     driverapi.Driver
97
+	capability driverapi.Capability
98
+}
99
+
100
+type driverTable map[string]*driverData
95 101
 type networkTable map[types.UUID]*network
96 102
 type endpointTable map[types.UUID]*endpoint
97 103
 type sandboxTable map[string]*sandboxData
... ...
@@ -175,21 +181,21 @@ func (c *controller) hostLeaveCallback(hosts []net.IP) {
175 175
 
176 176
 func (c *controller) ConfigureNetworkDriver(networkType string, options map[string]interface{}) error {
177 177
 	c.Lock()
178
-	d, ok := c.drivers[networkType]
178
+	dd, ok := c.drivers[networkType]
179 179
 	c.Unlock()
180 180
 	if !ok {
181 181
 		return NetworkTypeError(networkType)
182 182
 	}
183
-	return d.Config(options)
183
+	return dd.driver.Config(options)
184 184
 }
185 185
 
186
-func (c *controller) RegisterDriver(networkType string, driver driverapi.Driver) error {
186
+func (c *controller) RegisterDriver(networkType string, driver driverapi.Driver, capability driverapi.Capability) error {
187 187
 	c.Lock()
188 188
 	defer c.Unlock()
189 189
 	if _, ok := c.drivers[networkType]; ok {
190 190
 		return driverapi.ErrActiveRegistration(networkType)
191 191
 	}
192
-	c.drivers[networkType] = driver
192
+	c.drivers[networkType] = &driverData{driver, capability}
193 193
 	return nil
194 194
 }
195 195
 
... ...
@@ -238,18 +244,21 @@ func (c *controller) addNetwork(n *network) error {
238 238
 
239 239
 	c.Lock()
240 240
 	// Check if a driver for the specified network type is available
241
-	d, ok := c.drivers[n.networkType]
241
+	dd, ok := c.drivers[n.networkType]
242 242
 	c.Unlock()
243 243
 
244 244
 	if !ok {
245 245
 		var err error
246
-		d, err = c.loadDriver(n.networkType)
246
+		dd, err = c.loadDriver(n.networkType)
247 247
 		if err != nil {
248 248
 			return err
249 249
 		}
250 250
 	}
251 251
 
252
-	n.driver = d
252
+	n.Lock()
253
+	n.driver = dd.driver
254
+	d := n.driver
255
+	n.Unlock()
253 256
 
254 257
 	// Create the network
255 258
 	if err := d.CreateNetwork(n.id, n.generic); err != nil {
... ...
@@ -317,7 +326,7 @@ func (c *controller) NetworkByID(id string) (Network, error) {
317 317
 	return nil, ErrNoSuchNetwork(id)
318 318
 }
319 319
 
320
-func (c *controller) loadDriver(networkType string) (driverapi.Driver, error) {
320
+func (c *controller) loadDriver(networkType string) (*driverData, error) {
321 321
 	// Plugins pkg performs lazy loading of plugins that acts as remote drivers.
322 322
 	// As per the design, this Get call will result in remote driver discovery if there is a corresponding plugin available.
323 323
 	_, err := plugins.Get(networkType, driverapi.NetworkPluginEndpointType)
... ...
@@ -329,11 +338,24 @@ func (c *controller) loadDriver(networkType string) (driverapi.Driver, error) {
329 329
 	}
330 330
 	c.Lock()
331 331
 	defer c.Unlock()
332
-	d, ok := c.drivers[networkType]
332
+	dd, ok := c.drivers[networkType]
333 333
 	if !ok {
334 334
 		return nil, ErrInvalidNetworkDriver(networkType)
335 335
 	}
336
-	return d, nil
336
+	return dd, nil
337
+}
338
+
339
+func (c *controller) isDriverGlobalScoped(networkType string) (bool, error) {
340
+	c.Lock()
341
+	dd, ok := c.drivers[networkType]
342
+	c.Unlock()
343
+	if !ok {
344
+		return false, types.NotFoundErrorf("driver not found for %s", networkType)
345
+	}
346
+	if dd.capability.Scope == driverapi.GlobalScope {
347
+		return true, nil
348
+	}
349
+	return false, nil
337 350
 }
338 351
 
339 352
 func (c *controller) GC() {
... ...
@@ -118,5 +118,20 @@ type JoinInfo interface {
118 118
 // DriverCallback provides a Callback interface for Drivers into LibNetwork
119 119
 type DriverCallback interface {
120 120
 	// RegisterDriver provides a way for Remote drivers to dynamically register new NetworkType and associate with a driver instance
121
-	RegisterDriver(name string, driver Driver) error
121
+	RegisterDriver(name string, driver Driver, capability Capability) error
122
+}
123
+
124
+// Scope indicates the drivers scope capability
125
+type Scope int
126
+
127
+const (
128
+	// LocalScope represents the driver capable of providing networking services for containers in a single host
129
+	LocalScope Scope = iota
130
+	// GlobalScope represents the driver capable of providing networking services for containers across hosts
131
+	GlobalScope
132
+)
133
+
134
+// Capability represents the high level capabilities of the drivers which libnetwork can make use of
135
+type Capability struct {
136
+	Scope Scope
122 137
 }
... ...
@@ -110,7 +110,10 @@ func Init(dc driverapi.DriverCallback) error {
110 110
 	if out, err := exec.Command("modprobe", "-va", "bridge", "nf_nat", "br_netfilter").Output(); err != nil {
111 111
 		logrus.Warnf("Running modprobe bridge nf_nat failed with message: %s, error: %v", out, err)
112 112
 	}
113
-	return dc.RegisterDriver(networkType, newDriver())
113
+	c := driverapi.Capability{
114
+		Scope: driverapi.LocalScope,
115
+	}
116
+	return dc.RegisterDriver(networkType, newDriver(), c)
114 117
 }
115 118
 
116 119
 // Validate performs a static validation on the network configuration parameters.
... ...
@@ -16,7 +16,10 @@ type driver struct {
16 16
 
17 17
 // Init registers a new instance of host driver
18 18
 func Init(dc driverapi.DriverCallback) error {
19
-	return dc.RegisterDriver(networkType, &driver{})
19
+	c := driverapi.Capability{
20
+		Scope: driverapi.LocalScope,
21
+	}
22
+	return dc.RegisterDriver(networkType, &driver{}, c)
20 23
 }
21 24
 
22 25
 func (d *driver) Config(option map[string]interface{}) error {
... ...
@@ -16,7 +16,10 @@ type driver struct {
16 16
 
17 17
 // Init registers a new instance of null driver
18 18
 func Init(dc driverapi.DriverCallback) error {
19
-	return dc.RegisterDriver(networkType, &driver{})
19
+	c := driverapi.Capability{
20
+		Scope: driverapi.LocalScope,
21
+	}
22
+	return dc.RegisterDriver(networkType, &driver{}, c)
20 23
 }
21 24
 
22 25
 func (d *driver) Config(option map[string]interface{}) error {
... ...
@@ -23,7 +23,10 @@ func newDriver(name string, client *plugins.Client) driverapi.Driver {
23 23
 // plugin is activated.
24 24
 func Init(dc driverapi.DriverCallback) error {
25 25
 	plugins.Handle(driverapi.NetworkPluginEndpointType, func(name string, client *plugins.Client) {
26
-		if err := dc.RegisterDriver(name, newDriver(name, client)); err != nil {
26
+		c := driverapi.Capability{
27
+			Scope: driverapi.GlobalScope,
28
+		}
29
+		if err := dc.RegisterDriver(name, newDriver(name, client), c); err != nil {
27 30
 			log.Errorf("error registering driver for %s due to %v", name, err)
28 31
 		}
29 32
 	})
... ...
@@ -13,7 +13,10 @@ type driver struct{}
13 13
 
14 14
 // Init registers a new instance of null driver
15 15
 func Init(dc driverapi.DriverCallback) error {
16
-	return dc.RegisterDriver(networkType, &driver{})
16
+	c := driverapi.Capability{
17
+		Scope: driverapi.LocalScope,
18
+	}
19
+	return dc.RegisterDriver(networkType, &driver{}, c)
17 20
 }
18 21
 
19 22
 func (d *driver) Config(option map[string]interface{}) error {
... ...
@@ -6,8 +6,6 @@ import (
6 6
 	"github.com/docker/libnetwork/drivers/remote"
7 7
 )
8 8
 
9
-type driverTable map[string]driverapi.Driver
10
-
11 9
 func initDrivers(dc driverapi.DriverCallback) error {
12 10
 	for _, fn := range [](func(driverapi.DriverCallback) error){
13 11
 		null.Init,
... ...
@@ -8,8 +8,6 @@ import (
8 8
 	"github.com/docker/libnetwork/drivers/remote"
9 9
 )
10 10
 
11
-type driverTable map[string]driverapi.Driver
12
-
13 11
 func initDrivers(dc driverapi.DriverCallback) error {
14 12
 	for _, fn := range [](func(driverapi.DriverCallback) error){
15 13
 		bridge.Init,
... ...
@@ -5,8 +5,6 @@ import (
5 5
 	"github.com/docker/libnetwork/drivers/windows"
6 6
 )
7 7
 
8
-type driverTable map[string]driverapi.Driver
9
-
10 8
 func initDrivers(dc driverapi.DriverCallback) error {
11 9
 	for _, fn := range [](func(driverapi.DriverCallback) error){
12 10
 		windows.Init,
... ...
@@ -13,14 +13,14 @@ func TestDriverRegistration(t *testing.T) {
13 13
 	if err != nil {
14 14
 		t.Fatal(err)
15 15
 	}
16
-	err = c.(*controller).RegisterDriver(bridgeNetType, nil)
16
+	err = c.(*controller).RegisterDriver(bridgeNetType, nil, driverapi.Capability{})
17 17
 	if err == nil {
18 18
 		t.Fatalf("Expecting the RegisterDriver to fail for %s", bridgeNetType)
19 19
 	}
20 20
 	if _, ok := err.(driverapi.ErrActiveRegistration); !ok {
21 21
 		t.Fatalf("Failed for unexpected reason: %v", err)
22 22
 	}
23
-	err = c.(*controller).RegisterDriver("test-dummy", nil)
23
+	err = c.(*controller).RegisterDriver("test-dummy", nil, driverapi.Capability{})
24 24
 	if err != nil {
25 25
 		t.Fatalf("Test failed with an error %v", err)
26 26
 	}
... ...
@@ -2,7 +2,6 @@ package libnetwork
2 2
 
3 3
 import (
4 4
 	"encoding/json"
5
-	"strings"
6 5
 	"sync"
7 6
 
8 7
 	log "github.com/Sirupsen/logrus"
... ...
@@ -377,12 +376,9 @@ func (n *network) EndpointByID(id string) (Endpoint, error) {
377 377
 	return nil, ErrNoSuchEndpoint(id)
378 378
 }
379 379
 
380
-func isReservedNetwork(name string) bool {
381
-	reserved := []string{"bridge", "none", "host"}
382
-	for _, r := range reserved {
383
-		if strings.EqualFold(r, name) {
384
-			return true
385
-		}
386
-	}
387
-	return false
380
+func (n *network) isGlobalScoped() (bool, error) {
381
+	n.Lock()
382
+	c := n.ctrlr
383
+	n.Unlock()
384
+	return c.isDriverGlobalScoped(n.networkType)
388 385
 }
... ...
@@ -37,8 +37,9 @@ func (c *controller) newNetworkFromStore(n *network) error {
37 37
 }
38 38
 
39 39
 func (c *controller) updateNetworkToStore(n *network) error {
40
-	if isReservedNetwork(n.Name()) {
41
-		return nil
40
+	global, err := n.isGlobalScoped()
41
+	if err != nil || !global {
42
+		return err
42 43
 	}
43 44
 	c.Lock()
44 45
 	cs := c.store
... ...
@@ -52,8 +53,9 @@ func (c *controller) updateNetworkToStore(n *network) error {
52 52
 }
53 53
 
54 54
 func (c *controller) deleteNetworkFromStore(n *network) error {
55
-	if isReservedNetwork(n.Name()) {
56
-		return nil
55
+	global, err := n.isGlobalScoped()
56
+	if err != nil || !global {
57
+		return err
57 58
 	}
58 59
 	c.Lock()
59 60
 	cs := c.store
... ...
@@ -111,12 +113,13 @@ func (c *controller) newEndpointFromStore(key string, ep *endpoint) error {
111 111
 
112 112
 func (c *controller) updateEndpointToStore(ep *endpoint) error {
113 113
 	ep.Lock()
114
+	n := ep.network
114 115
 	name := ep.name
115
-	if isReservedNetwork(ep.network.name) {
116
-		ep.Unlock()
117
-		return nil
118
-	}
119 116
 	ep.Unlock()
117
+	global, err := n.isGlobalScoped()
118
+	if err != nil || !global {
119
+		return err
120
+	}
120 121
 	c.Lock()
121 122
 	cs := c.store
122 123
 	c.Unlock()
... ...
@@ -137,9 +140,14 @@ func (c *controller) getEndpointFromStore(eid types.UUID) (*endpoint, error) {
137 137
 }
138 138
 
139 139
 func (c *controller) deleteEndpointFromStore(ep *endpoint) error {
140
-	if isReservedNetwork(ep.network.Name()) {
141
-		return nil
140
+	ep.Lock()
141
+	n := ep.network
142
+	ep.Unlock()
143
+	global, err := n.isGlobalScoped()
144
+	if err != nil || !global {
145
+		return err
142 146
 	}
147
+
143 148
 	c.Lock()
144 149
 	cs := c.store
145 150
 	c.Unlock()