mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Allow user to control the default address pools
- Via daemon flag --default-address-pools base=<CIDR>,size=<int> Signed-off-by: Elango Siva <elango@docker.com>
This commit is contained in:
parent
1a57535aa2
commit
173b3c364e
8 changed files with 300 additions and 1 deletions
|
@ -18,6 +18,7 @@ func installConfigFlags(conf *config.Config, flags *pflag.FlagSet) {
|
|||
installUnixConfigFlags(conf, flags)
|
||||
|
||||
conf.Ulimits = make(map[string]*units.Ulimit)
|
||||
conf.NetworkConfig.DefaultAddressPools = opts.PoolsOpt{}
|
||||
|
||||
// Set default value for `--default-shm-size`
|
||||
conf.ShmSize = opts.MemBytes(config.DefaultShmSize)
|
||||
|
@ -44,4 +45,6 @@ func installConfigFlags(conf *config.Config, flags *pflag.FlagSet) {
|
|||
flags.Var(&conf.ShmSize, "default-shm-size", "Default shm size for containers")
|
||||
flags.BoolVar(&conf.NoNewPrivileges, "no-new-privileges", false, "Set no-new-privileges by default for new containers")
|
||||
flags.StringVar(&conf.IpcMode, "default-ipc-mode", config.DefaultIpcMode, `Default mode for containers ipc ("shareable" | "private")`)
|
||||
flags.Var(&conf.NetworkConfig.DefaultAddressPools, "default-address-pool", "Default address pools for node specific local networks")
|
||||
|
||||
}
|
||||
|
|
|
@ -71,6 +71,12 @@ type commonBridgeConfig struct {
|
|||
FixedCIDR string `json:"fixed-cidr,omitempty"`
|
||||
}
|
||||
|
||||
// NetworkConfig stores the daemon-wide networking configurations
|
||||
type NetworkConfig struct {
|
||||
// Default address pools for docker networks
|
||||
DefaultAddressPools opts.PoolsOpt `json:"default-address-pools,omitempty"`
|
||||
}
|
||||
|
||||
// CommonTLSOptions defines TLS configuration for the daemon server.
|
||||
// It includes json tags to deserialize configuration from a file
|
||||
// using the same names that the flags in the command line use.
|
||||
|
@ -173,6 +179,7 @@ type CommonConfig struct {
|
|||
|
||||
LogConfig
|
||||
BridgeConfig // bridgeConfig holds bridge network specific configuration.
|
||||
NetworkConfig
|
||||
registry.ServiceOptions
|
||||
|
||||
sync.Mutex
|
||||
|
|
|
@ -23,7 +23,6 @@ type Config struct {
|
|||
|
||||
// These fields are common to all unix platforms.
|
||||
CommonUnixConfig
|
||||
|
||||
// Fields below here are platform specific.
|
||||
CgroupParent string `json:"cgroup-parent,omitempty"`
|
||||
EnableSelinuxSupport bool `json:"selinux-enabled,omitempty"`
|
||||
|
|
|
@ -1223,6 +1223,10 @@ func (daemon *Daemon) networkOptions(dconfig *config.Config, pg plugingetter.Plu
|
|||
options = append(options, nwconfig.OptionLabels(dconfig.Labels))
|
||||
options = append(options, driverOptions(dconfig)...)
|
||||
|
||||
if len(dconfig.NetworkConfig.DefaultAddressPools.Value()) > 0 {
|
||||
options = append(options, nwconfig.OptionDefaultAddressPoolConfig(dconfig.NetworkConfig.DefaultAddressPools.Value()))
|
||||
}
|
||||
|
||||
if daemon.configStore != nil && daemon.configStore.LiveRestoreEnabled && len(activeSandboxes) != 0 {
|
||||
options = append(options, nwconfig.OptionActiveSandboxes(activeSandboxes))
|
||||
}
|
||||
|
|
|
@ -833,6 +833,9 @@ func (daemon *Daemon) initNetworkController(config *config.Config, activeSandbox
|
|||
if err = n.Delete(); err != nil {
|
||||
return nil, fmt.Errorf("could not delete the default bridge network: %v", err)
|
||||
}
|
||||
if len(config.NetworkConfig.DefaultAddressPools.Value()) > 0 && !daemon.configStore.LiveRestoreEnabled {
|
||||
removeDefaultBridgeInterface()
|
||||
}
|
||||
}
|
||||
|
||||
if !config.DisableBridge {
|
||||
|
|
|
@ -9,10 +9,189 @@ import (
|
|||
swarmtypes "github.com/docker/docker/api/types/swarm"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/docker/docker/integration/internal/swarm"
|
||||
"github.com/docker/docker/internal/test/daemon"
|
||||
"github.com/gotestyourself/gotestyourself/assert"
|
||||
"github.com/gotestyourself/gotestyourself/icmd"
|
||||
"github.com/gotestyourself/gotestyourself/poll"
|
||||
)
|
||||
|
||||
// delInterface removes given network interface
|
||||
func delInterface(t *testing.T, ifName string) {
|
||||
icmd.RunCommand("ip", "link", "delete", ifName).Assert(t, icmd.Success)
|
||||
icmd.RunCommand("iptables", "-t", "nat", "--flush").Assert(t, icmd.Success)
|
||||
icmd.RunCommand("iptables", "--flush").Assert(t, icmd.Success)
|
||||
}
|
||||
|
||||
func TestDaemonRestartWithLiveRestore(t *testing.T) {
|
||||
d := daemon.New(t)
|
||||
defer d.Stop(t)
|
||||
d.Start(t)
|
||||
d.Restart(t, "--live-restore=true",
|
||||
"--default-address-pool", "base=175.30.0.0/16,size=16",
|
||||
"--default-address-pool", "base=175.33.0.0/16,size=24")
|
||||
|
||||
// Verify bridge network's subnet
|
||||
cli, err := d.NewClient()
|
||||
assert.Assert(t, err)
|
||||
defer cli.Close()
|
||||
out, err := cli.NetworkInspect(context.Background(), "bridge", types.NetworkInspectOptions{})
|
||||
assert.NilError(t, err)
|
||||
// Make sure docker0 doesn't get override with new IP in live restore case
|
||||
assert.Equal(t, out.IPAM.Config[0].Subnet, "172.18.0.0/16")
|
||||
}
|
||||
|
||||
func TestDaemonDefaultNetworkPools(t *testing.T) {
|
||||
// Remove docker0 bridge and the start daemon defining the predefined address pools
|
||||
defaultNetworkBridge := "docker0"
|
||||
delInterface(t, defaultNetworkBridge)
|
||||
d := daemon.New(t)
|
||||
defer d.Stop(t)
|
||||
d.Start(t,
|
||||
"--default-address-pool", "base=175.30.0.0/16,size=16",
|
||||
"--default-address-pool", "base=175.33.0.0/16,size=24")
|
||||
|
||||
// Verify bridge network's subnet
|
||||
cli, err := d.NewClient()
|
||||
assert.Assert(t, err)
|
||||
defer cli.Close()
|
||||
out, err := cli.NetworkInspect(context.Background(), "bridge", types.NetworkInspectOptions{})
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, out.IPAM.Config[0].Subnet, "175.30.0.0/16")
|
||||
|
||||
// Create a bridge network and verify its subnet is the second default pool
|
||||
name := "elango"
|
||||
networkCreate := types.NetworkCreate{
|
||||
CheckDuplicate: false,
|
||||
}
|
||||
networkCreate.Driver = "bridge"
|
||||
_, err = cli.NetworkCreate(context.Background(), name, networkCreate)
|
||||
assert.NilError(t, err)
|
||||
out, err = cli.NetworkInspect(context.Background(), name, types.NetworkInspectOptions{})
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, out.IPAM.Config[0].Subnet, "175.33.0.0/24")
|
||||
|
||||
// Create a bridge network and verify its subnet is the third default pool
|
||||
name = "saanvi"
|
||||
networkCreate = types.NetworkCreate{
|
||||
CheckDuplicate: false,
|
||||
}
|
||||
networkCreate.Driver = "bridge"
|
||||
_, err = cli.NetworkCreate(context.Background(), name, networkCreate)
|
||||
assert.NilError(t, err)
|
||||
out, err = cli.NetworkInspect(context.Background(), name, types.NetworkInspectOptions{})
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, out.IPAM.Config[0].Subnet, "175.33.1.0/24")
|
||||
delInterface(t, defaultNetworkBridge)
|
||||
|
||||
}
|
||||
|
||||
func TestDaemonRestartWithExistingNetwork(t *testing.T) {
|
||||
defaultNetworkBridge := "docker0"
|
||||
d := daemon.New(t)
|
||||
d.Start(t)
|
||||
defer d.Stop(t)
|
||||
// Verify bridge network's subnet
|
||||
cli, err := d.NewClient()
|
||||
assert.Assert(t, err)
|
||||
defer cli.Close()
|
||||
|
||||
// Create a bridge network
|
||||
name := "elango"
|
||||
networkCreate := types.NetworkCreate{
|
||||
CheckDuplicate: false,
|
||||
}
|
||||
networkCreate.Driver = "bridge"
|
||||
_, err = cli.NetworkCreate(context.Background(), name, networkCreate)
|
||||
assert.NilError(t, err)
|
||||
out, err := cli.NetworkInspect(context.Background(), name, types.NetworkInspectOptions{})
|
||||
assert.NilError(t, err)
|
||||
networkip := out.IPAM.Config[0].Subnet
|
||||
|
||||
// Restart daemon with default address pool option
|
||||
d.Restart(t,
|
||||
"--default-address-pool", "base=175.30.0.0/16,size=16",
|
||||
"--default-address-pool", "base=175.33.0.0/16,size=24")
|
||||
|
||||
out1, err := cli.NetworkInspect(context.Background(), name, types.NetworkInspectOptions{})
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, out1.IPAM.Config[0].Subnet, networkip)
|
||||
delInterface(t, defaultNetworkBridge)
|
||||
}
|
||||
|
||||
func TestDaemonRestartWithExistingNetworkWithDefaultPoolRange(t *testing.T) {
|
||||
defaultNetworkBridge := "docker0"
|
||||
d := daemon.New(t)
|
||||
d.Start(t)
|
||||
defer d.Stop(t)
|
||||
// Verify bridge network's subnet
|
||||
cli, err := d.NewClient()
|
||||
assert.Assert(t, err)
|
||||
defer cli.Close()
|
||||
|
||||
// Create a bridge network
|
||||
name := "elango"
|
||||
networkCreate := types.NetworkCreate{
|
||||
CheckDuplicate: false,
|
||||
}
|
||||
networkCreate.Driver = "bridge"
|
||||
_, err = cli.NetworkCreate(context.Background(), name, networkCreate)
|
||||
assert.NilError(t, err)
|
||||
out, err := cli.NetworkInspect(context.Background(), name, types.NetworkInspectOptions{})
|
||||
assert.NilError(t, err)
|
||||
networkip := out.IPAM.Config[0].Subnet
|
||||
|
||||
// Create a bridge network
|
||||
name = "sthira"
|
||||
networkCreate = types.NetworkCreate{
|
||||
CheckDuplicate: false,
|
||||
}
|
||||
networkCreate.Driver = "bridge"
|
||||
_, err = cli.NetworkCreate(context.Background(), name, networkCreate)
|
||||
assert.NilError(t, err)
|
||||
out, err = cli.NetworkInspect(context.Background(), name, types.NetworkInspectOptions{})
|
||||
assert.NilError(t, err)
|
||||
networkip2 := out.IPAM.Config[0].Subnet
|
||||
|
||||
// Restart daemon with default address pool option
|
||||
d.Restart(t,
|
||||
"--default-address-pool", "base=175.18.0.0/16,size=16",
|
||||
"--default-address-pool", "base=175.19.0.0/16,size=24")
|
||||
|
||||
// Create a bridge network
|
||||
name = "saanvi"
|
||||
networkCreate = types.NetworkCreate{
|
||||
CheckDuplicate: false,
|
||||
}
|
||||
networkCreate.Driver = "bridge"
|
||||
_, err = cli.NetworkCreate(context.Background(), name, networkCreate)
|
||||
assert.NilError(t, err)
|
||||
out1, err := cli.NetworkInspect(context.Background(), name, types.NetworkInspectOptions{})
|
||||
assert.NilError(t, err)
|
||||
|
||||
assert.Check(t, (out1.IPAM.Config[0].Subnet != networkip))
|
||||
assert.Check(t, (out1.IPAM.Config[0].Subnet != networkip2))
|
||||
delInterface(t, defaultNetworkBridge)
|
||||
}
|
||||
|
||||
func TestDaemonWithBipAndDefaultNetworkPool(t *testing.T) {
|
||||
defaultNetworkBridge := "docker0"
|
||||
d := daemon.New(t)
|
||||
defer d.Stop(t)
|
||||
d.Start(t, "--bip=172.60.0.1/16",
|
||||
"--default-address-pool", "base=175.30.0.0/16,size=16",
|
||||
"--default-address-pool", "base=175.33.0.0/16,size=24")
|
||||
|
||||
// Verify bridge network's subnet
|
||||
cli, err := d.NewClient()
|
||||
assert.Assert(t, err)
|
||||
defer cli.Close()
|
||||
out, err := cli.NetworkInspect(context.Background(), "bridge", types.NetworkInspectOptions{})
|
||||
assert.NilError(t, err)
|
||||
// Make sure BIP IP doesn't get override with new default address pool .
|
||||
assert.Equal(t, out.IPAM.Config[0].Subnet, "172.60.0.1/16")
|
||||
delInterface(t, defaultNetworkBridge)
|
||||
}
|
||||
|
||||
func TestServiceWithPredefinedNetwork(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
d := swarm.NewSwarm(t, testEnv)
|
||||
|
|
84
opts/address_pools.go
Normal file
84
opts/address_pools.go
Normal file
|
@ -0,0 +1,84 @@
|
|||
package opts
|
||||
|
||||
import (
|
||||
"encoding/csv"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
types "github.com/docker/libnetwork/ipamutils"
|
||||
)
|
||||
|
||||
// PoolsOpt is a Value type for parsing the default address pools definitions
|
||||
type PoolsOpt struct {
|
||||
values []*types.NetworkToSplit
|
||||
}
|
||||
|
||||
// UnmarshalJSON fills values structure info from JSON input
|
||||
func (p *PoolsOpt) UnmarshalJSON(raw []byte) error {
|
||||
return json.Unmarshal(raw, &(p.values))
|
||||
}
|
||||
|
||||
// Set predefined pools
|
||||
func (p *PoolsOpt) Set(value string) error {
|
||||
csvReader := csv.NewReader(strings.NewReader(value))
|
||||
fields, err := csvReader.Read()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
poolsDef := types.NetworkToSplit{}
|
||||
|
||||
for _, field := range fields {
|
||||
parts := strings.SplitN(field, "=", 2)
|
||||
if len(parts) != 2 {
|
||||
return fmt.Errorf("invalid field '%s' must be a key=value pair", field)
|
||||
}
|
||||
|
||||
key := strings.ToLower(parts[0])
|
||||
value := strings.ToLower(parts[1])
|
||||
|
||||
switch key {
|
||||
case "base":
|
||||
poolsDef.Base = value
|
||||
case "size":
|
||||
size, err := strconv.Atoi(value)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid size value: %q (must be integer): %v", value, err)
|
||||
}
|
||||
poolsDef.Size = size
|
||||
default:
|
||||
return fmt.Errorf("unexpected key '%s' in '%s'", key, field)
|
||||
}
|
||||
}
|
||||
|
||||
p.values = append(p.values, &poolsDef)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Type returns the type of this option
|
||||
func (p *PoolsOpt) Type() string {
|
||||
return "pool-options"
|
||||
}
|
||||
|
||||
// String returns a string repr of this option
|
||||
func (p *PoolsOpt) String() string {
|
||||
pools := []string{}
|
||||
for _, pool := range p.values {
|
||||
repr := fmt.Sprintf("%s %d", pool.Base, pool.Size)
|
||||
pools = append(pools, repr)
|
||||
}
|
||||
return strings.Join(pools, ", ")
|
||||
}
|
||||
|
||||
// Value returns the mounts
|
||||
func (p *PoolsOpt) Value() []*types.NetworkToSplit {
|
||||
return p.values
|
||||
}
|
||||
|
||||
// Name returns the flag name of this option
|
||||
func (p *PoolsOpt) Name() string {
|
||||
return "default-address-pools"
|
||||
}
|
20
opts/address_pools_test.go
Normal file
20
opts/address_pools_test.go
Normal file
|
@ -0,0 +1,20 @@
|
|||
package opts // import "github.com/docker/docker/opts"
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAddressPoolOpt(t *testing.T) {
|
||||
poolopt := &PoolsOpt{}
|
||||
var addresspool = "base=175.30.0.0/16,size=16"
|
||||
var invalidAddresspoolString = "base=175.30.0.0/16,size=16, base=175.33.0.0/16,size=24"
|
||||
|
||||
if err := poolopt.Set(addresspool); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := poolopt.Set(invalidAddresspoolString); err == nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue