Преглед изворни кода

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 пре 9 година
родитељ
комит
651f6ea0fa

+ 48 - 0
libnetwork/controller.go

@@ -200,6 +200,8 @@ func New(cfgOptions ...config.Option) (NetworkController, error) {
 	c.cleanupLocalEndpoints()
 	c.networkCleanup()
 
+	c.reservePools()
+
 	if err := c.startExternalKeyListener(); err != nil {
 		return nil, err
 	}
@@ -546,6 +548,52 @@ func (c *controller) NewNetwork(networkType, name string, id string, options ...
 	return network, nil
 }
 
+func (c *controller) reservePools() {
+	networks, err := c.getNetworksForScope(datastore.LocalScope)
+	if err != nil {
+		log.Warnf("Could not retrieve networks from local store during ipam allocation for existing networks: %v", err)
+		return
+	}
+
+	for _, n := range networks {
+		if !doReplayPoolReserve(n) {
+			continue
+		}
+		// Construct pseudo configs for the auto IP case
+		autoIPv4 := (len(n.ipamV4Config) == 0 || (len(n.ipamV4Config) == 1 && n.ipamV4Config[0].PreferredPool == "")) && len(n.ipamV4Info) > 0
+		autoIPv6 := (len(n.ipamV6Config) == 0 || (len(n.ipamV6Config) == 1 && n.ipamV6Config[0].PreferredPool == "")) && len(n.ipamV6Info) > 0
+		if autoIPv4 {
+			n.ipamV4Config = []*IpamConf{{PreferredPool: n.ipamV4Info[0].Pool.String()}}
+		}
+		if n.enableIPv6 && autoIPv6 {
+			n.ipamV6Config = []*IpamConf{{PreferredPool: n.ipamV6Info[0].Pool.String()}}
+		}
+		// Account current network gateways
+		for i, c := range n.ipamV4Config {
+			if c.Gateway == "" && n.ipamV4Info[i].Gateway != nil {
+				c.Gateway = n.ipamV4Info[i].Gateway.IP.String()
+			}
+		}
+		for i, c := range n.ipamV6Config {
+			if c.Gateway == "" && n.ipamV6Info[i].Gateway != nil {
+				c.Gateway = n.ipamV6Info[i].Gateway.IP.String()
+			}
+		}
+		if err := n.ipamAllocate(); err != nil {
+			log.Warnf("Failed to allocate ipam pool(s) for network %q (%s): %v", n.Name(), n.ID(), err)
+		}
+	}
+}
+
+func doReplayPoolReserve(n *network) bool {
+	_, caps, err := n.getController().getIPAMDriver(n.ipamType)
+	if err != nil {
+		log.Warnf("Failed to retrieve ipam driver for network %q (%s): %v", n.Name(), n.ID(), err)
+		return false
+	}
+	return caps.RequiresRequestReplay
+}
+
 func (c *controller) addNetwork(n *network) error {
 	d, err := n.driver(true)
 	if err != nil {

+ 5 - 0
libnetwork/docs/ipam.md

@@ -249,6 +249,7 @@ During registration, the remote driver will receive a POST message to the URL `/
 
 	{
 		"RequiresMACAddress": bool
+		"RequiresRequestReplay": bool
 	}
 	
 	
@@ -263,6 +264,10 @@ As of now libnetwork accepts the following capabilities:
 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.
 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"`.
 
+### RequiresRequestReplay
+
+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.
+
 
 ## Appendix
 

+ 1 - 1
libnetwork/drvregistry/drvregistry.go

@@ -163,7 +163,7 @@ func (r *DrvRegistry) initIPAMs(lDs, gDs interface{}) error {
 		remoteIpam.Init,
 		nullIpam.Init,
 	} {
-		if err := fn(r, lDs, gDs); err != nil {
+		if err := fn(r, nil, gDs); err != nil {
 			return err
 		}
 	}

+ 5 - 0
libnetwork/ipamapi/contract.go

@@ -80,5 +80,10 @@ type Ipam interface {
 
 // Capability represents the requirements and capabilities of the IPAM driver
 type Capability struct {
+	// Whether on address request, libnetwork must
+	// specify the endpoint MAC address
 	RequiresMACAddress bool
+	// Whether of daemon start, libnetwork must replay the pool
+	// request and the address request for current local networks
+	RequiresRequestReplay bool
 }

+ 3 - 1
libnetwork/ipams/builtin/builtin_unix.go

@@ -37,5 +37,7 @@ func Init(ic ipamapi.Callback, l, g interface{}) error {
 		return err
 	}
 
-	return ic.RegisterIpamDriver(ipamapi.DefaultIPAM, a)
+	cps := &ipamapi.Capability{RequiresRequestReplay: true}
+
+	return ic.RegisterIpamDriverWithCapabilities(ipamapi.DefaultIPAM, a, cps)
 }

+ 6 - 2
libnetwork/ipams/remote/api/api.go

@@ -22,12 +22,16 @@ func (r *Response) GetError() string {
 // GetCapabilityResponse is the response of GetCapability request
 type GetCapabilityResponse struct {
 	Response
-	RequiresMACAddress bool
+	RequiresMACAddress    bool
+	RequiresRequestReplay bool
 }
 
 // ToCapability converts the capability response into the internal ipam driver capaility structure
 func (capRes GetCapabilityResponse) ToCapability() *ipamapi.Capability {
-	return &ipamapi.Capability{RequiresMACAddress: capRes.RequiresMACAddress}
+	return &ipamapi.Capability{
+		RequiresMACAddress:    capRes.RequiresMACAddress,
+		RequiresRequestReplay: capRes.RequiresRequestReplay,
+	}
 }
 
 // GetAddressSpacesResponse is the response to the ``get default address spaces`` request message

+ 1 - 1
libnetwork/ipams/remote/remote_test.go

@@ -86,7 +86,7 @@ func TestGetCapabilities(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	if !caps.RequiresMACAddress {
+	if !caps.RequiresMACAddress || caps.RequiresRequestReplay {
 		t.Fatalf("Unexpected capability: %v", caps)
 	}
 }