diff --git a/libnetwork/api/api.go b/libnetwork/api/api.go index 70092e403e..bfb94af06b 100644 --- a/libnetwork/api/api.go +++ b/libnetwork/api/api.go @@ -8,6 +8,7 @@ import ( "strings" "github.com/docker/libnetwork" + "github.com/docker/libnetwork/netlabel" "github.com/docker/libnetwork/types" "github.com/gorilla/mux" ) @@ -279,6 +280,11 @@ func procCreateNetwork(c libnetwork.NetworkController, vars map[string]string, b processCreateDefaults(c, &create) options := []libnetwork.NetworkOption{} + if len(create.NetworkOpts) > 0 { + if _, ok := create.NetworkOpts[netlabel.Internal]; ok { + options = append(options, libnetwork.NetworkOptionInternalNetwork()) + } + } if len(create.DriverOpts) > 0 { options = append(options, libnetwork.NetworkOptionDriverOpts(create.DriverOpts)) } diff --git a/libnetwork/api/types.go b/libnetwork/api/types.go index f25060de1b..df565c4056 100644 --- a/libnetwork/api/types.go +++ b/libnetwork/api/types.go @@ -37,6 +37,7 @@ type networkCreate struct { Name string `json:"name"` NetworkType string `json:"network_type"` DriverOpts map[string]string `json:"driver_opts"` + NetworkOpts map[string]string `json:"network_opts"` } // endpointCreate represents the body of the "create endpoint" http request message diff --git a/libnetwork/client/network.go b/libnetwork/client/network.go index f8e745695e..e539f2e85c 100644 --- a/libnetwork/client/network.go +++ b/libnetwork/client/network.go @@ -9,6 +9,7 @@ import ( flag "github.com/docker/docker/pkg/mflag" "github.com/docker/docker/pkg/stringid" + "github.com/docker/libnetwork/netlabel" ) type command struct { @@ -41,15 +42,19 @@ func (cli *NetworkCli) CmdNetwork(chain string, args ...string) error { func (cli *NetworkCli) CmdNetworkCreate(chain string, args ...string) error { cmd := cli.Subcmd(chain, "create", "NETWORK-NAME", "Creates a new network with a name specified by the user", false) flDriver := cmd.String([]string{"d", "-driver"}, "", "Driver to manage the Network") + flInternal := cmd.Bool([]string{"-internal"}, false, "Config the network to be internal") cmd.Require(flag.Exact, 1) err := cmd.ParseFlags(args, true) if err != nil { return err } - + networkOpts := make(map[string]string) + if *flInternal { + networkOpts[netlabel.Internal] = "true" + } // Construct network create request body var driverOpts []string - nc := networkCreate{Name: cmd.Arg(0), NetworkType: *flDriver, DriverOpts: driverOpts} + nc := networkCreate{Name: cmd.Arg(0), NetworkType: *flDriver, DriverOpts: driverOpts, NetworkOpts: networkOpts} obj, _, err := readBody(cli.call("POST", "/networks", nc, nil)) if err != nil { return err diff --git a/libnetwork/client/types.go b/libnetwork/client/types.go index f481f2a8da..c87b6792fc 100644 --- a/libnetwork/client/types.go +++ b/libnetwork/client/types.go @@ -34,9 +34,10 @@ type SandboxResource struct { // networkCreate is the expected body of the "create network" http request message type networkCreate struct { - Name string `json:"name"` - NetworkType string `json:"network_type"` - DriverOpts []string `json:"driver_opts"` + Name string `json:"name"` + NetworkType string `json:"network_type"` + DriverOpts []string `json:"driver_opts"` + NetworkOpts map[string]string `json:"network_opts"` } // serviceCreate represents the body of the "publish service" http request message diff --git a/libnetwork/default_gateway.go b/libnetwork/default_gateway.go index 139242c6a5..d9277ba577 100644 --- a/libnetwork/default_gateway.go +++ b/libnetwork/default_gateway.go @@ -103,6 +103,9 @@ func (sb *sandbox) needDefaultGW() bool { if ep.getNetwork().Type() == "null" || ep.getNetwork().Type() == "host" { continue } + if ep.getNetwork().Internal() { + return false + } if ep.joinInfo.disableGatewayService { return false } diff --git a/libnetwork/drivers/bridge/bridge.go b/libnetwork/drivers/bridge/bridge.go index 7991c6f67c..04f5a4c81b 100644 --- a/libnetwork/drivers/bridge/bridge.go +++ b/libnetwork/drivers/bridge/bridge.go @@ -490,6 +490,12 @@ func parseNetworkOptions(id string, option options.Generic) (*networkConfigurati config.EnableIPv6 = val.(bool) } + if val, ok := option[netlabel.Internal]; ok { + if internal, ok := val.(bool); ok && internal { + return nil, &driverapi.ErrNotImplemented{} + } + } + // Finally validate the configuration if err = config.Validate(); err != nil { return nil, err diff --git a/libnetwork/libnetwork_test.go b/libnetwork/libnetwork_test.go index aa4b3b103d..480604dcf4 100644 --- a/libnetwork/libnetwork_test.go +++ b/libnetwork/libnetwork_test.go @@ -2344,3 +2344,10 @@ func TestParallel2(t *testing.T) { func TestParallel3(t *testing.T) { runParallelTests(t, 3) } + +func TestNetworkInternal(t *testing.T) { + _, err := controller.NewNetwork(bridgeNetType, "testnetworkinternal", libnetwork.NetworkOptionInternalNetwork()) + if err == nil || err.Error() != (&driverapi.ErrNotImplemented{}).Error() { + t.Fatal("bridge network can't be internal") + } +} diff --git a/libnetwork/netlabel/labels.go b/libnetwork/netlabel/labels.go index cb0c2f5402..c6d7f13477 100644 --- a/libnetwork/netlabel/labels.go +++ b/libnetwork/netlabel/labels.go @@ -41,6 +41,9 @@ const ( // Gateway represents the gateway for the network Gateway = Prefix + ".gateway" + + // Internal constant represents that the network is internal which disables default gateway service + Internal = Prefix + ".internal" ) var ( diff --git a/libnetwork/network.go b/libnetwork/network.go index 922beb2eab..f18c91a19b 100644 --- a/libnetwork/network.go +++ b/libnetwork/network.go @@ -163,6 +163,7 @@ type network struct { persist bool stopWatchCh chan struct{} drvOnce *sync.Once + internal bool sync.Mutex } @@ -305,6 +306,7 @@ func (n *network) CopyTo(o datastore.KVObject) error { dstN.dbIndex = n.dbIndex dstN.dbExists = n.dbExists dstN.drvOnce = n.drvOnce + dstN.internal = n.internal for _, v4conf := range n.ipamV4Config { dstV4Conf := &IpamConf{} @@ -391,6 +393,7 @@ func (n *network) MarshalJSON() ([]byte, error) { } netMap["ipamV6Info"] = string(iis) } + netMap["internal"] = n.internal return json.Marshal(netMap) } @@ -454,6 +457,9 @@ func (n *network) UnmarshalJSON(b []byte) (err error) { return err } } + if v, ok := netMap["internal"]; ok { + n.internal = v.(bool) + } return nil } @@ -480,6 +486,18 @@ func NetworkOptionPersist(persist bool) NetworkOption { } } +// NetworkOptionInternalNetwork returns an option setter to config the network +// to be internal which disables default gateway service +func NetworkOptionInternalNetwork() NetworkOption { + return func(n *network) { + n.internal = true + if n.generic == nil { + n.generic = make(map[string]interface{}) + } + n.generic[netlabel.Internal] = true + } +} + // NetworkOptionIpam function returns an option setter for the ipam configuration for this network func NetworkOptionIpam(ipamDriver string, addrSpace string, ipV4 []*IpamConf, ipV6 []*IpamConf) NetworkOption { return func(n *network) { @@ -1187,3 +1205,10 @@ func (n *network) IpamInfo() ([]*IpamInfo, []*IpamInfo) { return v4Info, v6Info } + +func (n *network) Internal() bool { + n.Lock() + defer n.Unlock() + + return n.internal +} diff --git a/libnetwork/test/integration/dnet/helpers.bash b/libnetwork/test/integration/dnet/helpers.bash index e1e2fc70e5..867996237a 100644 --- a/libnetwork/test/integration/dnet/helpers.bash +++ b/libnetwork/test/integration/dnet/helpers.bash @@ -280,7 +280,11 @@ function test_overlay() { end=3 # Setup overlay network and connect containers ot it if [ -z "${2}" -o "${2}" != "skip_add" ]; then - dnet_cmd $(inst_id2port 1) network create -d overlay multihost + if [ -z "${2}" -o "${2}" != "internal" ]; then + dnet_cmd $(inst_id2port 1) network create -d overlay multihost + else + dnet_cmd $(inst_id2port 1) network create -d overlay --internal multihost + fi fi for i in `seq ${start} ${end}`; @@ -292,8 +296,13 @@ function test_overlay() { # Now test connectivity between all the containers using service names for i in `seq ${start} ${end}`; do - runc $(dnet_container_name $i $dnet_suffix) $(get_sbox_id ${i} container_${i}) \ - "ping -c 1 www.google.com" + if [ -z "${2}" -o "${2}" != "internal" ]; then + runc $(dnet_container_name $i $dnet_suffix) $(get_sbox_id ${i} container_${i}) \ + "ping -c 1 www.google.com" + else + default_route=`runc $(dnet_container_name $i $dnet_suffix) $(get_sbox_id ${i} container_${i}) "ip route | grep default"` + [ "$default_route" = "" ] + fi for j in `seq ${start} ${end}`; do if [ "$i" -eq "$j" ]; then diff --git a/libnetwork/test/integration/dnet/overlay-consul.bats b/libnetwork/test/integration/dnet/overlay-consul.bats index 85a70f2af0..721b7b87c4 100644 --- a/libnetwork/test/integration/dnet/overlay-consul.bats +++ b/libnetwork/test/integration/dnet/overlay-consul.bats @@ -29,3 +29,8 @@ load helpers wait_for_dnet $(inst_id2port 3) dnet-3-consul test_overlay consul skip_add } + +@test "Test overlay network internal network with consul" { + skip_for_circleci + test_overlay consul internal +} \ No newline at end of file