diff --git a/api/client/network.go b/api/client/network.go index d9ff387fce..cb19d0d8e7 100644 --- a/api/client/network.go +++ b/api/client/network.go @@ -34,6 +34,7 @@ func (cli *DockerCli) CmdNetwork(args ...string) error { func (cli *DockerCli) CmdNetworkCreate(args ...string) error { cmd := Cli.Subcmd("network create", []string{"NETWORK-NAME"}, "Creates a new network with a name specified by the user", false) flDriver := cmd.String([]string{"d", "-driver"}, "bridge", "Driver to manage the Network") + flOpts := opts.NewMapOpts(nil, nil) flIpamDriver := cmd.String([]string{"-ipam-driver"}, "default", "IP Address Management Driver") flIpamSubnet := opts.NewListOpts(nil) @@ -41,10 +42,11 @@ func (cli *DockerCli) CmdNetworkCreate(args ...string) error { flIpamGateway := opts.NewListOpts(nil) flIpamAux := opts.NewMapOpts(nil, nil) - cmd.Var(&flIpamSubnet, []string{"-subnet"}, "Subnet in CIDR format that represents a network segment") + cmd.Var(&flIpamSubnet, []string{"-subnet"}, "subnet in CIDR format that represents a network segment") cmd.Var(&flIpamIPRange, []string{"-ip-range"}, "allocate container ip from a sub-range") cmd.Var(&flIpamGateway, []string{"-gateway"}, "ipv4 or ipv6 Gateway for the master subnet") - cmd.Var(flIpamAux, []string{"-aux-address"}, "Auxiliary ipv4 or ipv6 addresses used by network driver") + cmd.Var(flIpamAux, []string{"-aux-address"}, "auxiliary ipv4 or ipv6 addresses used by Network driver") + cmd.Var(flOpts, []string{"o", "-opt"}, "set driver specific options") cmd.Require(flag.Exact, 1) err := cmd.ParseFlags(args, true) @@ -62,6 +64,7 @@ func (cli *DockerCli) CmdNetworkCreate(args ...string) error { Name: cmd.Arg(0), Driver: *flDriver, IPAM: network.IPAM{Driver: *flIpamDriver, Config: ipamCfg}, + Options: flOpts.GetAll(), CheckDuplicate: true, } obj, _, err := readBody(cli.call("POST", "/networks/create", nc, nil)) diff --git a/api/server/router/network/network_routes.go b/api/server/router/network/network_routes.go index 8d650e74c0..0659ba61eb 100644 --- a/api/server/router/network/network_routes.go +++ b/api/server/router/network/network_routes.go @@ -96,7 +96,7 @@ func (n *networkRouter) postNetworkCreate(ctx context.Context, w http.ResponseWr warning = fmt.Sprintf("Network with name %s (id : %s) already exists", nw.Name(), nw.ID()) } - nw, err = n.daemon.CreateNetwork(create.Name, create.Driver, create.IPAM) + nw, err = n.daemon.CreateNetwork(create.Name, create.Driver, create.IPAM, create.Options) if err != nil { return err } @@ -174,6 +174,7 @@ func buildNetworkResource(nw libnetwork.Network) *types.NetworkResource { r.ID = nw.ID() r.Scope = nw.Info().Scope() r.Driver = nw.Type() + r.Options = nw.Info().DriverOptions() r.Containers = make(map[string]types.EndpointResource) buildIpamResources(r, nw) diff --git a/api/types/types.go b/api/types/types.go index ed9a0831a7..4c4635c1a0 100644 --- a/api/types/types.go +++ b/api/types/types.go @@ -319,6 +319,7 @@ type NetworkResource struct { Driver string `json:"driver"` IPAM network.IPAM `json:"ipam"` Containers map[string]EndpointResource `json:"containers"` + Options map[string]string `json:"options"` } //EndpointResource contains network resources allocated and usd for a container in a network @@ -331,10 +332,11 @@ type EndpointResource struct { // NetworkCreate is the expected body of the "create network" http request message type NetworkCreate struct { - Name string `json:"name"` - CheckDuplicate bool `json:"check_duplicate"` - Driver string `json:"driver"` - IPAM network.IPAM `json:"ipam"` + Name string `json:"name"` + CheckDuplicate bool `json:"check_duplicate"` + Driver string `json:"driver"` + IPAM network.IPAM `json:"ipam"` + Options map[string]string `json:"options"` } // NetworkCreateResponse is the response message sent by the server for network create call diff --git a/daemon/network.go b/daemon/network.go index 8a960c9924..3933c3bf98 100644 --- a/daemon/network.go +++ b/daemon/network.go @@ -80,7 +80,7 @@ func (daemon *Daemon) GetNetworksByID(partialID string) []libnetwork.Network { } // CreateNetwork creates a network with the given name, driver and other optional parameters -func (daemon *Daemon) CreateNetwork(name, driver string, ipam network.IPAM) (libnetwork.Network, error) { +func (daemon *Daemon) CreateNetwork(name, driver string, ipam network.IPAM, options map[string]string) (libnetwork.Network, error) { c := daemon.netController if driver == "" { driver = c.Config().Daemon.DefaultDriver @@ -96,6 +96,7 @@ func (daemon *Daemon) CreateNetwork(name, driver string, ipam network.IPAM) (lib if len(ipam.Config) > 0 { nwOptions = append(nwOptions, libnetwork.NetworkOptionIpam(ipam.Driver, "", v4Conf, v6Conf)) } + nwOptions = append(nwOptions, libnetwork.NetworkOptionDriverOpts(options)) return c.NewNetwork(driver, name, nwOptions...) } diff --git a/hack/vendor.sh b/hack/vendor.sh index 052303394d..63917d05d9 100755 --- a/hack/vendor.sh +++ b/hack/vendor.sh @@ -20,7 +20,7 @@ clone git github.com/tchap/go-patricia v2.1.0 clone git golang.org/x/net 3cffabab72adf04f8e3b01c5baf775361837b5fe https://github.com/golang/net.git #get libnetwork packages -clone git github.com/docker/libnetwork dd1c5f0ffe7697f75a82bd8e4bbd6f225ec5e383 +clone git github.com/docker/libnetwork 2934f6bf585fa24c86048cc85f7506a5bb626bf5 clone git github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec clone git github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b clone git github.com/hashicorp/memberlist 9a1e242e454d2443df330bdd51a436d5a9058fc4 diff --git a/integration-cli/docker_api_network_test.go b/integration-cli/docker_api_network_test.go index ed2c710fae..dc8e1b1b18 100644 --- a/integration-cli/docker_api_network_test.go +++ b/integration-cli/docker_api_network_test.go @@ -74,9 +74,10 @@ func (s *DockerSuite) TestApiNetworkInspect(c *check.C) { Config: []network.IPAMConfig{{Subnet: "172.28.0.0/16", IPRange: "172.28.5.0/24", Gateway: "172.28.5.254"}}, } config := types.NetworkCreate{ - Name: "br0", - Driver: "bridge", - IPAM: ipam, + Name: "br0", + Driver: "bridge", + IPAM: ipam, + Options: map[string]string{"foo": "bar", "opts": "dopts"}, } id0 := createNetwork(c, config, true) c.Assert(isNetworkAvailable(c, "br0"), checker.Equals, true) @@ -86,6 +87,9 @@ func (s *DockerSuite) TestApiNetworkInspect(c *check.C) { c.Assert(nr.IPAM.Config[0].Subnet, checker.Equals, "172.28.0.0/16") c.Assert(nr.IPAM.Config[0].IPRange, checker.Equals, "172.28.5.0/24") c.Assert(nr.IPAM.Config[0].Gateway, checker.Equals, "172.28.5.254") + c.Assert(nr.Options["foo"], checker.Equals, "bar") + c.Assert(nr.Options["opts"], checker.Equals, "dopts") + // delete the network and make sure it is deleted deleteNetwork(c, id0, true) c.Assert(isNetworkAvailable(c, "br0"), checker.Equals, false) diff --git a/integration-cli/docker_cli_network_unix_test.go b/integration-cli/docker_cli_network_unix_test.go index eadcca81dd..0586f39b51 100644 --- a/integration-cli/docker_cli_network_unix_test.go +++ b/integration-cli/docker_cli_network_unix_test.go @@ -15,11 +15,15 @@ import ( "github.com/docker/docker/api/types" "github.com/docker/docker/pkg/integration/checker" "github.com/docker/libnetwork/driverapi" + remoteapi "github.com/docker/libnetwork/drivers/remote/api" + "github.com/docker/libnetwork/netlabel" "github.com/go-check/check" ) const dummyNetworkDriver = "dummy-network-driver" +var remoteDriverNetworkRequest remoteapi.CreateNetworkRequest + func init() { check.Suite(&DockerNetworkSuite{ ds: &DockerSuite{}, @@ -57,6 +61,11 @@ func (s *DockerNetworkSuite) SetUpSuite(c *check.C) { }) mux.HandleFunc(fmt.Sprintf("/%s.CreateNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { + err := json.NewDecoder(r.Body).Decode(&remoteDriverNetworkRequest) + if err != nil { + http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest) + return + } w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") fmt.Fprintf(w, "null") }) @@ -256,3 +265,16 @@ func (s *DockerNetworkSuite) TestDockerNetworkIpamInvalidCombinations(c *check.C c.Assert(err, check.NotNil) dockerCmd(c, "network", "rm", "test0") } + +func (s *DockerNetworkSuite) TestDockerNetworkDriverOptions(c *check.C) { + dockerCmd(c, "network", "create", "-d", dummyNetworkDriver, "-o", "opt1=drv1", "-o", "opt2=drv2", "testopt") + assertNwIsAvailable(c, "testopt") + gopts := remoteDriverNetworkRequest.Options[netlabel.GenericData] + c.Assert(gopts, checker.NotNil) + opts, ok := gopts.(map[string]interface{}) + c.Assert(ok, checker.Equals, true) + c.Assert(opts["opt1"], checker.Equals, "drv1") + c.Assert(opts["opt2"], checker.Equals, "drv2") + dockerCmd(c, "network", "rm", "testopt") + +} diff --git a/vendor/src/github.com/docker/libnetwork/controller.go b/vendor/src/github.com/docker/libnetwork/controller.go index e802825010..18fa883bf3 100644 --- a/vendor/src/github.com/docker/libnetwork/controller.go +++ b/vendor/src/github.com/docker/libnetwork/controller.go @@ -74,7 +74,6 @@ type NetworkController interface { Config() config.Config // Create a new network. The options parameter carries network specific options. - // Labels support will be added in the near future. NewNetwork(networkType, name string, options ...NetworkOption) (Network, error) // Networks returns the list of Network(s) managed by this controller. diff --git a/vendor/src/github.com/docker/libnetwork/network.go b/vendor/src/github.com/docker/libnetwork/network.go index b9a2d5a1b9..7b14fc830b 100644 --- a/vendor/src/github.com/docker/libnetwork/network.go +++ b/vendor/src/github.com/docker/libnetwork/network.go @@ -33,7 +33,6 @@ type Network interface { // Create a new endpoint to this network symbolically identified by the // specified unique name. The options parameter carry driver specific options. - // Labels support will be added in the near future. CreateEndpoint(name string, options ...EndpointOption) (Endpoint, error) // Delete the network. @@ -58,7 +57,7 @@ type Network interface { // NetworkInfo returns some configuration and operational information about the network type NetworkInfo interface { IpamConfig() (string, []*IpamConf, []*IpamConf) - Labels() map[string]string + DriverOptions() map[string]string Scope() string } @@ -402,7 +401,7 @@ func (n *network) UnmarshalJSON(b []byte) (err error) { if v, ok := netMap["generic"]; ok { n.generic = v.(map[string]interface{}) - // Restore labels in their map[string]string form + // Restore opts in their map[string]string form if v, ok := n.generic[netlabel.GenericData]; ok { var lmap map[string]string ba, err := json.Marshal(v) @@ -484,19 +483,19 @@ func NetworkOptionIpam(ipamDriver string, addrSpace string, ipV4 []*IpamConf, ip } } -// NetworkOptionLabels function returns an option setter for any parameter described by a map -func NetworkOptionLabels(labels map[string]string) NetworkOption { +// NetworkOptionDriverOpts function returns an option setter for any parameter described by a map +func NetworkOptionDriverOpts(opts map[string]string) NetworkOption { return func(n *network) { if n.generic == nil { n.generic = make(map[string]interface{}) } - if labels == nil { - labels = make(map[string]string) + if opts == nil { + opts = make(map[string]string) } // Store the options - n.generic[netlabel.GenericData] = labels + n.generic[netlabel.GenericData] = opts // Decode and store the endpoint options of libnetwork interest - if val, ok := labels[netlabel.EnableIPv6]; ok { + if val, ok := opts[netlabel.EnableIPv6]; ok { var err error if n.enableIPv6, err = strconv.ParseBool(val); err != nil { log.Warnf("Failed to parse %s' value: %s (%s)", netlabel.EnableIPv6, val, err.Error()) @@ -1056,7 +1055,7 @@ func (n *network) Info() NetworkInfo { return n } -func (n *network) Labels() map[string]string { +func (n *network) DriverOptions() map[string]string { n.Lock() defer n.Unlock() if n.generic != nil {