mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
bbbddeebba
Pull request https://github.com/docker/docker/pull/27745 added support for the client to talk to older versions of the daemon. Various flags were added to docker 1.13 that are not compatible with older daemons. This PR adds annotations to those flags, so that they are automatically hidden if the daemon is older than docker 1.13 (API 1.25). Not all new flags affect the API (some are client-side only). The following PR's added new flags to docker 1.13 that affect the API; - https://github.com/docker/docker/pull/23430 added `--cpu-rt-period`and `--cpu-rt-runtime` - https://github.com/docker/docker/pull/27800 / https://github.com/docker/docker/pull/25317 added `--group` / `--group-add` / `--group-rm` - https://github.com/docker/docker/pull/27702 added `--network` to `docker build` - https://github.com/docker/docker/pull/25962 added `--attachable` to `docker network create` - https://github.com/docker/docker/pull/27998 added `--compose-file` to `docker stack deploy` - https://github.com/docker/docker/pull/22566 added `--stop-timeout` to `docker run` and `docker create` - https://github.com/docker/docker/pull/26061 added `--init` to `docker run` and `docker create` - https://github.com/docker/docker/pull/26941 added `--init-path` to `docker run` and `docker create` - https://github.com/docker/docker/pull/27958 added `--cpus` on `docker run` / `docker create` - https://github.com/docker/docker/pull/27567 added `--dns`, `--dns-opt`, and `--dns-search` to `docker service create` - https://github.com/docker/docker/pull/27596 added `--force` to `docker service update` - https://github.com/docker/docker/pull/27857 added `--hostname` to `docker service create` - https://github.com/docker/docker/pull/28031 added `--hosts`, `--host-add` / `--host-rm` to `docker service create` and `docker service update` - https://github.com/docker/docker/pull/28076 added `--tty` on `docker service create` / `docker service update` - https://github.com/docker/docker/pull/26421 added `--update-max-failure-ratio`, `--update-monitor` and `--rollback` on `docker service update` - https://github.com/docker/docker/pull/27369 added `--health-cmd`, `--health-interval`, `--health-retries`, `--health-timeout` and `--no-healthcheck` options to `docker service create` and `docker service update` Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
227 lines
6.2 KiB
Go
227 lines
6.2 KiB
Go
package network
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
"strings"
|
|
|
|
"golang.org/x/net/context"
|
|
|
|
"github.com/docker/docker/api/types"
|
|
"github.com/docker/docker/api/types/network"
|
|
"github.com/docker/docker/cli"
|
|
"github.com/docker/docker/cli/command"
|
|
"github.com/docker/docker/opts"
|
|
runconfigopts "github.com/docker/docker/runconfig/opts"
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
type createOptions struct {
|
|
name string
|
|
driver string
|
|
driverOpts opts.MapOpts
|
|
labels opts.ListOpts
|
|
internal bool
|
|
ipv6 bool
|
|
attachable bool
|
|
|
|
ipamDriver string
|
|
ipamSubnet []string
|
|
ipamIPRange []string
|
|
ipamGateway []string
|
|
ipamAux opts.MapOpts
|
|
ipamOpt opts.MapOpts
|
|
}
|
|
|
|
func newCreateCommand(dockerCli *command.DockerCli) *cobra.Command {
|
|
opts := createOptions{
|
|
driverOpts: *opts.NewMapOpts(nil, nil),
|
|
labels: opts.NewListOpts(opts.ValidateEnv),
|
|
ipamAux: *opts.NewMapOpts(nil, nil),
|
|
ipamOpt: *opts.NewMapOpts(nil, nil),
|
|
}
|
|
|
|
cmd := &cobra.Command{
|
|
Use: "create [OPTIONS] NETWORK",
|
|
Short: "Create a network",
|
|
Args: cli.ExactArgs(1),
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
opts.name = args[0]
|
|
return runCreate(dockerCli, opts)
|
|
},
|
|
}
|
|
|
|
flags := cmd.Flags()
|
|
flags.StringVarP(&opts.driver, "driver", "d", "bridge", "Driver to manage the Network")
|
|
flags.VarP(&opts.driverOpts, "opt", "o", "Set driver specific options")
|
|
flags.Var(&opts.labels, "label", "Set metadata on a network")
|
|
flags.BoolVar(&opts.internal, "internal", false, "Restrict external access to the network")
|
|
flags.BoolVar(&opts.ipv6, "ipv6", false, "Enable IPv6 networking")
|
|
flags.BoolVar(&opts.attachable, "attachable", false, "Enable manual container attachment")
|
|
flags.SetAnnotation("attachable", "version", []string{"1.25"})
|
|
|
|
flags.StringVar(&opts.ipamDriver, "ipam-driver", "default", "IP Address Management Driver")
|
|
flags.StringSliceVar(&opts.ipamSubnet, "subnet", []string{}, "Subnet in CIDR format that represents a network segment")
|
|
flags.StringSliceVar(&opts.ipamIPRange, "ip-range", []string{}, "Allocate container ip from a sub-range")
|
|
flags.StringSliceVar(&opts.ipamGateway, "gateway", []string{}, "IPv4 or IPv6 Gateway for the master subnet")
|
|
|
|
flags.Var(&opts.ipamAux, "aux-address", "Auxiliary IPv4 or IPv6 addresses used by Network driver")
|
|
flags.Var(&opts.ipamOpt, "ipam-opt", "Set IPAM driver specific options")
|
|
|
|
return cmd
|
|
}
|
|
|
|
func runCreate(dockerCli *command.DockerCli, opts createOptions) error {
|
|
client := dockerCli.Client()
|
|
|
|
ipamCfg, err := consolidateIpam(opts.ipamSubnet, opts.ipamIPRange, opts.ipamGateway, opts.ipamAux.GetAll())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Construct network create request body
|
|
nc := types.NetworkCreate{
|
|
Driver: opts.driver,
|
|
Options: opts.driverOpts.GetAll(),
|
|
IPAM: &network.IPAM{
|
|
Driver: opts.ipamDriver,
|
|
Config: ipamCfg,
|
|
Options: opts.ipamOpt.GetAll(),
|
|
},
|
|
CheckDuplicate: true,
|
|
Internal: opts.internal,
|
|
EnableIPv6: opts.ipv6,
|
|
Attachable: opts.attachable,
|
|
Labels: runconfigopts.ConvertKVStringsToMap(opts.labels.GetAll()),
|
|
}
|
|
|
|
resp, err := client.NetworkCreate(context.Background(), opts.name, nc)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
fmt.Fprintf(dockerCli.Out(), "%s\n", resp.ID)
|
|
return nil
|
|
}
|
|
|
|
// Consolidates the ipam configuration as a group from different related configurations
|
|
// user can configure network with multiple non-overlapping subnets and hence it is
|
|
// possible to correlate the various related parameters and consolidate them.
|
|
// consoidateIpam consolidates subnets, ip-ranges, gateways and auxiliary addresses into
|
|
// structured ipam data.
|
|
func consolidateIpam(subnets, ranges, gateways []string, auxaddrs map[string]string) ([]network.IPAMConfig, error) {
|
|
if len(subnets) < len(ranges) || len(subnets) < len(gateways) {
|
|
return nil, fmt.Errorf("every ip-range or gateway must have a corresponding subnet")
|
|
}
|
|
iData := map[string]*network.IPAMConfig{}
|
|
|
|
// Populate non-overlapping subnets into consolidation map
|
|
for _, s := range subnets {
|
|
for k := range iData {
|
|
ok1, err := subnetMatches(s, k)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
ok2, err := subnetMatches(k, s)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if ok1 || ok2 {
|
|
return nil, fmt.Errorf("multiple overlapping subnet configuration is not supported")
|
|
}
|
|
}
|
|
iData[s] = &network.IPAMConfig{Subnet: s, AuxAddress: map[string]string{}}
|
|
}
|
|
|
|
// Validate and add valid ip ranges
|
|
for _, r := range ranges {
|
|
match := false
|
|
for _, s := range subnets {
|
|
ok, err := subnetMatches(s, r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if !ok {
|
|
continue
|
|
}
|
|
if iData[s].IPRange != "" {
|
|
return nil, fmt.Errorf("cannot configure multiple ranges (%s, %s) on the same subnet (%s)", r, iData[s].IPRange, s)
|
|
}
|
|
d := iData[s]
|
|
d.IPRange = r
|
|
match = true
|
|
}
|
|
if !match {
|
|
return nil, fmt.Errorf("no matching subnet for range %s", r)
|
|
}
|
|
}
|
|
|
|
// Validate and add valid gateways
|
|
for _, g := range gateways {
|
|
match := false
|
|
for _, s := range subnets {
|
|
ok, err := subnetMatches(s, g)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if !ok {
|
|
continue
|
|
}
|
|
if iData[s].Gateway != "" {
|
|
return nil, fmt.Errorf("cannot configure multiple gateways (%s, %s) for the same subnet (%s)", g, iData[s].Gateway, s)
|
|
}
|
|
d := iData[s]
|
|
d.Gateway = g
|
|
match = true
|
|
}
|
|
if !match {
|
|
return nil, fmt.Errorf("no matching subnet for gateway %s", g)
|
|
}
|
|
}
|
|
|
|
// Validate and add aux-addresses
|
|
for key, aa := range auxaddrs {
|
|
match := false
|
|
for _, s := range subnets {
|
|
ok, err := subnetMatches(s, aa)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if !ok {
|
|
continue
|
|
}
|
|
iData[s].AuxAddress[key] = aa
|
|
match = true
|
|
}
|
|
if !match {
|
|
return nil, fmt.Errorf("no matching subnet for aux-address %s", aa)
|
|
}
|
|
}
|
|
|
|
idl := []network.IPAMConfig{}
|
|
for _, v := range iData {
|
|
idl = append(idl, *v)
|
|
}
|
|
return idl, nil
|
|
}
|
|
|
|
func subnetMatches(subnet, data string) (bool, error) {
|
|
var (
|
|
ip net.IP
|
|
)
|
|
|
|
_, s, err := net.ParseCIDR(subnet)
|
|
if err != nil {
|
|
return false, fmt.Errorf("Invalid subnet %s : %v", s, err)
|
|
}
|
|
|
|
if strings.Contains(data, "/") {
|
|
ip, _, err = net.ParseCIDR(data)
|
|
if err != nil {
|
|
return false, fmt.Errorf("Invalid cidr %s : %v", data, err)
|
|
}
|
|
} else {
|
|
ip = net.ParseIP(data)
|
|
}
|
|
|
|
return s.Contains(ip), nil
|
|
}
|