Browse code

Avoid persisting ipam data if it can be reconstructed

- Also restore older behavior where overlap check is not run
when preferred pool is specified. Got broken by recent changes

Signed-off-by: Alessandro Boch <aboch@docker.com>

Alessandro Boch authored on 2016/04/19 07:11:36
Showing 7 changed files
... ...
@@ -200,6 +200,8 @@ func New(cfgOptions ...config.Option) (NetworkController, error) {
200 200
 	c.cleanupLocalEndpoints()
201 201
 	c.networkCleanup()
202 202
 
203
+	c.reservePools()
204
+
203 205
 	if err := c.startExternalKeyListener(); err != nil {
204 206
 		return nil, err
205 207
 	}
... ...
@@ -546,6 +548,52 @@ func (c *controller) NewNetwork(networkType, name string, id string, options ...
546 546
 	return network, nil
547 547
 }
548 548
 
549
+func (c *controller) reservePools() {
550
+	networks, err := c.getNetworksForScope(datastore.LocalScope)
551
+	if err != nil {
552
+		log.Warnf("Could not retrieve networks from local store during ipam allocation for existing networks: %v", err)
553
+		return
554
+	}
555
+
556
+	for _, n := range networks {
557
+		if !doReplayPoolReserve(n) {
558
+			continue
559
+		}
560
+		// Construct pseudo configs for the auto IP case
561
+		autoIPv4 := (len(n.ipamV4Config) == 0 || (len(n.ipamV4Config) == 1 && n.ipamV4Config[0].PreferredPool == "")) && len(n.ipamV4Info) > 0
562
+		autoIPv6 := (len(n.ipamV6Config) == 0 || (len(n.ipamV6Config) == 1 && n.ipamV6Config[0].PreferredPool == "")) && len(n.ipamV6Info) > 0
563
+		if autoIPv4 {
564
+			n.ipamV4Config = []*IpamConf{{PreferredPool: n.ipamV4Info[0].Pool.String()}}
565
+		}
566
+		if n.enableIPv6 && autoIPv6 {
567
+			n.ipamV6Config = []*IpamConf{{PreferredPool: n.ipamV6Info[0].Pool.String()}}
568
+		}
569
+		// Account current network gateways
570
+		for i, c := range n.ipamV4Config {
571
+			if c.Gateway == "" && n.ipamV4Info[i].Gateway != nil {
572
+				c.Gateway = n.ipamV4Info[i].Gateway.IP.String()
573
+			}
574
+		}
575
+		for i, c := range n.ipamV6Config {
576
+			if c.Gateway == "" && n.ipamV6Info[i].Gateway != nil {
577
+				c.Gateway = n.ipamV6Info[i].Gateway.IP.String()
578
+			}
579
+		}
580
+		if err := n.ipamAllocate(); err != nil {
581
+			log.Warnf("Failed to allocate ipam pool(s) for network %q (%s): %v", n.Name(), n.ID(), err)
582
+		}
583
+	}
584
+}
585
+
586
+func doReplayPoolReserve(n *network) bool {
587
+	_, caps, err := n.getController().getIPAMDriver(n.ipamType)
588
+	if err != nil {
589
+		log.Warnf("Failed to retrieve ipam driver for network %q (%s): %v", n.Name(), n.ID(), err)
590
+		return false
591
+	}
592
+	return caps.RequiresRequestReplay
593
+}
594
+
549 595
 func (c *controller) addNetwork(n *network) error {
550 596
 	d, err := n.driver(true)
551 597
 	if err != nil {
... ...
@@ -249,6 +249,7 @@ During registration, the remote driver will receive a POST message to the URL `/
249 249
 
250 250
 	{
251 251
 		"RequiresMACAddress": bool
252
+		"RequiresRequestReplay": bool
252 253
 	}
253 254
 	
254 255
 	
... ...
@@ -263,6 +264,10 @@ As of now libnetwork accepts the following capabilities:
263 263
 It is a boolean value which tells libnetwork whether the ipam driver needs to know the interface MAC address in order to properly process the `RequestAddress()` call.
264 264
 If true, on `CreateEndpoint()` request, libnetwork will generate a random MAC address for the endpoint (if an explicit MAC address was not already provided by the user) and pass it to `RequestAddress()` when requesting the IP address inside the options map. The key will be the `netlabel.MacAddress` constant: `"com.docker.network.endpoint.macaddress"`.
265 265
 
266
+### RequiresRequestReplay
267
+
268
+It is a boolean value which tells libnetwork whether the ipam driver needs to receive the replay of the `RequestPool()` and `RequestAddress()` requests on daemon reload.  When libnetwork controller is initializing, it retrieves from local store the list of current local scope networks and, if this capability flag is set, it allows the IPAM driver to reconstruct the database of pools by replaying the `RequestPool()` requests for each pool and the `RequestAddress()` for each network gateway owned by the local networks. This can be useful to ipam drivers which decide not to persist the pools allocated to local scope networks.
269
+
266 270
 
267 271
 ## Appendix
268 272
 
... ...
@@ -163,7 +163,7 @@ func (r *DrvRegistry) initIPAMs(lDs, gDs interface{}) error {
163 163
 		remoteIpam.Init,
164 164
 		nullIpam.Init,
165 165
 	} {
166
-		if err := fn(r, lDs, gDs); err != nil {
166
+		if err := fn(r, nil, gDs); err != nil {
167 167
 			return err
168 168
 		}
169 169
 	}
... ...
@@ -80,5 +80,10 @@ type Ipam interface {
80 80
 
81 81
 // Capability represents the requirements and capabilities of the IPAM driver
82 82
 type Capability struct {
83
+	// Whether on address request, libnetwork must
84
+	// specify the endpoint MAC address
83 85
 	RequiresMACAddress bool
86
+	// Whether of daemon start, libnetwork must replay the pool
87
+	// request and the address request for current local networks
88
+	RequiresRequestReplay bool
84 89
 }
... ...
@@ -37,5 +37,7 @@ func Init(ic ipamapi.Callback, l, g interface{}) error {
37 37
 		return err
38 38
 	}
39 39
 
40
-	return ic.RegisterIpamDriver(ipamapi.DefaultIPAM, a)
40
+	cps := &ipamapi.Capability{RequiresRequestReplay: true}
41
+
42
+	return ic.RegisterIpamDriverWithCapabilities(ipamapi.DefaultIPAM, a, cps)
41 43
 }
... ...
@@ -22,12 +22,16 @@ func (r *Response) GetError() string {
22 22
 // GetCapabilityResponse is the response of GetCapability request
23 23
 type GetCapabilityResponse struct {
24 24
 	Response
25
-	RequiresMACAddress bool
25
+	RequiresMACAddress    bool
26
+	RequiresRequestReplay bool
26 27
 }
27 28
 
28 29
 // ToCapability converts the capability response into the internal ipam driver capaility structure
29 30
 func (capRes GetCapabilityResponse) ToCapability() *ipamapi.Capability {
30
-	return &ipamapi.Capability{RequiresMACAddress: capRes.RequiresMACAddress}
31
+	return &ipamapi.Capability{
32
+		RequiresMACAddress:    capRes.RequiresMACAddress,
33
+		RequiresRequestReplay: capRes.RequiresRequestReplay,
34
+	}
31 35
 }
32 36
 
33 37
 // GetAddressSpacesResponse is the response to the ``get default address spaces`` request message
... ...
@@ -86,7 +86,7 @@ func TestGetCapabilities(t *testing.T) {
86 86
 		t.Fatal(err)
87 87
 	}
88 88
 
89
-	if !caps.RequiresMACAddress {
89
+	if !caps.RequiresMACAddress || caps.RequiresRequestReplay {
90 90
 		t.Fatalf("Unexpected capability: %v", caps)
91 91
 	}
92 92
 }