Signed-off-by: Alessandro Boch <aboch@docker.com>
| ... | ... |
@@ -99,9 +99,7 @@ func (daemon *Daemon) CreateNetwork(name, driver string, ipam network.IPAM, opti |
| 99 | 99 |
return nil, err |
| 100 | 100 |
} |
| 101 | 101 |
|
| 102 |
- if len(ipam.Config) > 0 {
|
|
| 103 |
- nwOptions = append(nwOptions, libnetwork.NetworkOptionIpam(ipam.Driver, "", v4Conf, v6Conf)) |
|
| 104 |
- } |
|
| 102 |
+ nwOptions = append(nwOptions, libnetwork.NetworkOptionIpam(ipam.Driver, "", v4Conf, v6Conf)) |
|
| 105 | 103 |
nwOptions = append(nwOptions, libnetwork.NetworkOptionDriverOpts(options)) |
| 106 | 104 |
return c.NewNetwork(driver, name, nwOptions...) |
| 107 | 105 |
} |
| ... | ... |
@@ -16,11 +16,14 @@ import ( |
| 16 | 16 |
"github.com/docker/docker/pkg/integration/checker" |
| 17 | 17 |
"github.com/docker/libnetwork/driverapi" |
| 18 | 18 |
remoteapi "github.com/docker/libnetwork/drivers/remote/api" |
| 19 |
+ "github.com/docker/libnetwork/ipamapi" |
|
| 20 |
+ remoteipam "github.com/docker/libnetwork/ipams/remote/api" |
|
| 19 | 21 |
"github.com/docker/libnetwork/netlabel" |
| 20 | 22 |
"github.com/go-check/check" |
| 21 | 23 |
) |
| 22 | 24 |
|
| 23 | 25 |
const dummyNetworkDriver = "dummy-network-driver" |
| 26 |
+const dummyIpamDriver = "dummy-ipam-driver" |
|
| 24 | 27 |
|
| 25 | 28 |
var remoteDriverNetworkRequest remoteapi.CreateNetworkRequest |
| 26 | 29 |
|
| ... | ... |
@@ -52,9 +55,10 @@ func (s *DockerNetworkSuite) SetUpSuite(c *check.C) {
|
| 52 | 52 |
|
| 53 | 53 |
mux.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) {
|
| 54 | 54 |
w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
|
| 55 |
- fmt.Fprintf(w, `{"Implements": ["%s"]}`, driverapi.NetworkPluginEndpointType)
|
|
| 55 |
+ fmt.Fprintf(w, `{"Implements": ["%s", "%s"]}`, driverapi.NetworkPluginEndpointType, ipamapi.PluginEndpointType)
|
|
| 56 | 56 |
}) |
| 57 | 57 |
|
| 58 |
+ // Network driver implementation |
|
| 58 | 59 |
mux.HandleFunc(fmt.Sprintf("/%s.GetCapabilities", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
|
| 59 | 60 |
w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
|
| 60 | 61 |
fmt.Fprintf(w, `{"Scope":"local"}`)
|
| ... | ... |
@@ -75,12 +79,99 @@ func (s *DockerNetworkSuite) SetUpSuite(c *check.C) {
|
| 75 | 75 |
fmt.Fprintf(w, "null") |
| 76 | 76 |
}) |
| 77 | 77 |
|
| 78 |
+ // Ipam Driver implementation |
|
| 79 |
+ var ( |
|
| 80 |
+ poolRequest remoteipam.RequestPoolRequest |
|
| 81 |
+ poolReleaseReq remoteipam.ReleasePoolRequest |
|
| 82 |
+ addressRequest remoteipam.RequestAddressRequest |
|
| 83 |
+ addressReleaseReq remoteipam.ReleaseAddressRequest |
|
| 84 |
+ lAS = "localAS" |
|
| 85 |
+ gAS = "globalAS" |
|
| 86 |
+ pool = "172.28.0.0/16" |
|
| 87 |
+ poolID = lAS + "/" + pool |
|
| 88 |
+ gw = "172.28.255.254/16" |
|
| 89 |
+ ) |
|
| 90 |
+ |
|
| 91 |
+ mux.HandleFunc(fmt.Sprintf("/%s.GetDefaultAddressSpaces", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
|
|
| 92 |
+ w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
|
|
| 93 |
+ fmt.Fprintf(w, `{"LocalDefaultAddressSpace":"`+lAS+`", "GlobalDefaultAddressSpace": "`+gAS+`"}`)
|
|
| 94 |
+ }) |
|
| 95 |
+ |
|
| 96 |
+ mux.HandleFunc(fmt.Sprintf("/%s.RequestPool", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
|
|
| 97 |
+ err := json.NewDecoder(r.Body).Decode(&poolRequest) |
|
| 98 |
+ if err != nil {
|
|
| 99 |
+ http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest) |
|
| 100 |
+ return |
|
| 101 |
+ } |
|
| 102 |
+ w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
|
|
| 103 |
+ if poolRequest.AddressSpace != lAS && poolRequest.AddressSpace != gAS {
|
|
| 104 |
+ fmt.Fprintf(w, `{"Error":"Unknown address space in pool request: `+poolRequest.AddressSpace+`"}`)
|
|
| 105 |
+ } else if poolRequest.Pool != "" && poolRequest.Pool != pool {
|
|
| 106 |
+ fmt.Fprintf(w, `{"Error":"Cannot handle explicit pool requests yet"}`)
|
|
| 107 |
+ } else {
|
|
| 108 |
+ fmt.Fprintf(w, `{"PoolID":"`+poolID+`", "Pool":"`+pool+`"}`)
|
|
| 109 |
+ } |
|
| 110 |
+ }) |
|
| 111 |
+ |
|
| 112 |
+ mux.HandleFunc(fmt.Sprintf("/%s.RequestAddress", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
|
|
| 113 |
+ err := json.NewDecoder(r.Body).Decode(&addressRequest) |
|
| 114 |
+ if err != nil {
|
|
| 115 |
+ http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest) |
|
| 116 |
+ return |
|
| 117 |
+ } |
|
| 118 |
+ w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
|
|
| 119 |
+ // make sure libnetwork is now querying on the expected pool id |
|
| 120 |
+ if addressRequest.PoolID != poolID {
|
|
| 121 |
+ fmt.Fprintf(w, `{"Error":"unknown pool id"}`)
|
|
| 122 |
+ } else if addressRequest.Address != "" {
|
|
| 123 |
+ fmt.Fprintf(w, `{"Error":"Cannot handle explicit address requests yet"}`)
|
|
| 124 |
+ } else {
|
|
| 125 |
+ fmt.Fprintf(w, `{"Address":"`+gw+`"}`)
|
|
| 126 |
+ } |
|
| 127 |
+ }) |
|
| 128 |
+ |
|
| 129 |
+ mux.HandleFunc(fmt.Sprintf("/%s.ReleaseAddress", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
|
|
| 130 |
+ err := json.NewDecoder(r.Body).Decode(&addressReleaseReq) |
|
| 131 |
+ if err != nil {
|
|
| 132 |
+ http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest) |
|
| 133 |
+ return |
|
| 134 |
+ } |
|
| 135 |
+ w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
|
|
| 136 |
+ // make sure libnetwork is now asking to release the expected address fro mthe expected poolid |
|
| 137 |
+ if addressRequest.PoolID != poolID {
|
|
| 138 |
+ fmt.Fprintf(w, `{"Error":"unknown pool id"}`)
|
|
| 139 |
+ } else if addressReleaseReq.Address != gw {
|
|
| 140 |
+ fmt.Fprintf(w, `{"Error":"unknown address"}`)
|
|
| 141 |
+ } else {
|
|
| 142 |
+ fmt.Fprintf(w, "null") |
|
| 143 |
+ } |
|
| 144 |
+ }) |
|
| 145 |
+ |
|
| 146 |
+ mux.HandleFunc(fmt.Sprintf("/%s.ReleasePool", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
|
|
| 147 |
+ err := json.NewDecoder(r.Body).Decode(&poolReleaseReq) |
|
| 148 |
+ if err != nil {
|
|
| 149 |
+ http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest) |
|
| 150 |
+ return |
|
| 151 |
+ } |
|
| 152 |
+ w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
|
|
| 153 |
+ // make sure libnetwork is now asking to release the expected poolid |
|
| 154 |
+ if addressRequest.PoolID != poolID {
|
|
| 155 |
+ fmt.Fprintf(w, `{"Error":"unknown pool id"}`)
|
|
| 156 |
+ } else {
|
|
| 157 |
+ fmt.Fprintf(w, "null") |
|
| 158 |
+ } |
|
| 159 |
+ }) |
|
| 160 |
+ |
|
| 78 | 161 |
err := os.MkdirAll("/etc/docker/plugins", 0755)
|
| 79 | 162 |
c.Assert(err, checker.IsNil) |
| 80 | 163 |
|
| 81 | 164 |
fileName := fmt.Sprintf("/etc/docker/plugins/%s.spec", dummyNetworkDriver)
|
| 82 | 165 |
err = ioutil.WriteFile(fileName, []byte(s.server.URL), 0644) |
| 83 | 166 |
c.Assert(err, checker.IsNil) |
| 167 |
+ |
|
| 168 |
+ ipamFileName := fmt.Sprintf("/etc/docker/plugins/%s.spec", dummyIpamDriver)
|
|
| 169 |
+ err = ioutil.WriteFile(ipamFileName, []byte(s.server.URL), 0644) |
|
| 170 |
+ c.Assert(err, checker.IsNil) |
|
| 84 | 171 |
} |
| 85 | 172 |
|
| 86 | 173 |
func (s *DockerNetworkSuite) TearDownSuite(c *check.C) {
|
| ... | ... |
@@ -227,6 +318,21 @@ func (s *DockerNetworkSuite) TestDockerNetworkIpamMultipleNetworks(c *check.C) {
|
| 227 | 227 |
} |
| 228 | 228 |
} |
| 229 | 229 |
|
| 230 |
+func (s *DockerNetworkSuite) TestDockerNetworkCustomIpam(c *check.C) {
|
|
| 231 |
+ // Create a bridge network using custom ipam driver |
|
| 232 |
+ dockerCmd(c, "network", "create", "--ipam-driver", dummyIpamDriver, "br0") |
|
| 233 |
+ assertNwIsAvailable(c, "br0") |
|
| 234 |
+ |
|
| 235 |
+ // Verify expected network ipam fields are there |
|
| 236 |
+ nr := getNetworkResource(c, "br0") |
|
| 237 |
+ c.Assert(nr.Driver, checker.Equals, "bridge") |
|
| 238 |
+ c.Assert(nr.IPAM.Driver, checker.Equals, dummyIpamDriver) |
|
| 239 |
+ |
|
| 240 |
+ // remove network and exercise remote ipam driver |
|
| 241 |
+ dockerCmd(c, "network", "rm", "br0") |
|
| 242 |
+ assertNwNotAvailable(c, "br0") |
|
| 243 |
+} |
|
| 244 |
+ |
|
| 230 | 245 |
func (s *DockerNetworkSuite) TestDockerNetworkInspect(c *check.C) {
|
| 231 | 246 |
// if unspecified, network gateway will be selected from inside preferred pool |
| 232 | 247 |
dockerCmd(c, "network", "create", "--driver=bridge", "--subnet=172.28.0.0/16", "--ip-range=172.28.5.0/24", "--gateway=172.28.5.254", "br0") |