mirror of
				https://github.com/moby/moby.git
				synced 2022-11-09 12:21:53 -05:00 
			
		
		
		
	Merge pull request #32717 from fcrisciani/data_path
Data path traffic separation option in swarm mode
This commit is contained in:
		
						commit
						0307fe1a0b
					
				
					 20 changed files with 197 additions and 66 deletions
				
			
		| 
						 | 
				
			
			@ -132,6 +132,7 @@ type ExternalCA struct {
 | 
			
		|||
type InitRequest struct {
 | 
			
		||||
	ListenAddr       string
 | 
			
		||||
	AdvertiseAddr    string
 | 
			
		||||
	DataPathAddr     string
 | 
			
		||||
	ForceNewCluster  bool
 | 
			
		||||
	Spec             Spec
 | 
			
		||||
	AutoLockManagers bool
 | 
			
		||||
| 
						 | 
				
			
			@ -142,6 +143,7 @@ type InitRequest struct {
 | 
			
		|||
type JoinRequest struct {
 | 
			
		||||
	ListenAddr    string
 | 
			
		||||
	AdvertiseAddr string
 | 
			
		||||
	DataPathAddr  string
 | 
			
		||||
	RemoteAddrs   []string
 | 
			
		||||
	JoinToken     string // accept by secret
 | 
			
		||||
	Availability  NodeAvailability
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,6 +19,7 @@ type initOptions struct {
 | 
			
		|||
	listenAddr NodeAddrOption
 | 
			
		||||
	// Not a NodeAddrOption because it has no default port.
 | 
			
		||||
	advertiseAddr   string
 | 
			
		||||
	dataPathAddr    string
 | 
			
		||||
	forceNewCluster bool
 | 
			
		||||
	availability    string
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -40,6 +41,7 @@ func newInitCommand(dockerCli command.Cli) *cobra.Command {
 | 
			
		|||
	flags := cmd.Flags()
 | 
			
		||||
	flags.Var(&opts.listenAddr, flagListenAddr, "Listen address (format: <ip|interface>[:port])")
 | 
			
		||||
	flags.StringVar(&opts.advertiseAddr, flagAdvertiseAddr, "", "Advertised address (format: <ip|interface>[:port])")
 | 
			
		||||
	flags.StringVar(&opts.dataPathAddr, flagDataPathAddr, "", "Address or interface to use for data path traffic (format: <ip|interface>)")
 | 
			
		||||
	flags.BoolVar(&opts.forceNewCluster, "force-new-cluster", false, "Force create a new cluster from current state")
 | 
			
		||||
	flags.BoolVar(&opts.autolock, flagAutolock, false, "Enable manager autolocking (requiring an unlock key to start a stopped manager)")
 | 
			
		||||
	flags.StringVar(&opts.availability, flagAvailability, "active", `Availability of the node ("active"|"pause"|"drain")`)
 | 
			
		||||
| 
						 | 
				
			
			@ -54,6 +56,7 @@ func runInit(dockerCli command.Cli, flags *pflag.FlagSet, opts initOptions) erro
 | 
			
		|||
	req := swarm.InitRequest{
 | 
			
		||||
		ListenAddr:       opts.listenAddr.String(),
 | 
			
		||||
		AdvertiseAddr:    opts.advertiseAddr,
 | 
			
		||||
		DataPathAddr:     opts.dataPathAddr,
 | 
			
		||||
		ForceNewCluster:  opts.forceNewCluster,
 | 
			
		||||
		Spec:             opts.swarmOptions.ToSpec(flags),
 | 
			
		||||
		AutoLockManagers: opts.swarmOptions.autolock,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,6 +19,7 @@ type joinOptions struct {
 | 
			
		|||
	listenAddr NodeAddrOption
 | 
			
		||||
	// Not a NodeAddrOption because it has no default port.
 | 
			
		||||
	advertiseAddr string
 | 
			
		||||
	dataPathAddr  string
 | 
			
		||||
	token         string
 | 
			
		||||
	availability  string
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -41,6 +42,7 @@ func newJoinCommand(dockerCli command.Cli) *cobra.Command {
 | 
			
		|||
	flags := cmd.Flags()
 | 
			
		||||
	flags.Var(&opts.listenAddr, flagListenAddr, "Listen address (format: <ip|interface>[:port])")
 | 
			
		||||
	flags.StringVar(&opts.advertiseAddr, flagAdvertiseAddr, "", "Advertised address (format: <ip|interface>[:port])")
 | 
			
		||||
	flags.StringVar(&opts.dataPathAddr, flagDataPathAddr, "", "Address or interface to use for data path traffic (format: <ip|interface>)")
 | 
			
		||||
	flags.StringVar(&opts.token, flagToken, "", "Token for entry into the swarm")
 | 
			
		||||
	flags.StringVar(&opts.availability, flagAvailability, "active", `Availability of the node ("active"|"pause"|"drain")`)
 | 
			
		||||
	return cmd
 | 
			
		||||
| 
						 | 
				
			
			@ -54,6 +56,7 @@ func runJoin(dockerCli command.Cli, flags *pflag.FlagSet, opts joinOptions) erro
 | 
			
		|||
		JoinToken:     opts.token,
 | 
			
		||||
		ListenAddr:    opts.listenAddr.String(),
 | 
			
		||||
		AdvertiseAddr: opts.advertiseAddr,
 | 
			
		||||
		DataPathAddr:  opts.dataPathAddr,
 | 
			
		||||
		RemoteAddrs:   []string{opts.remote},
 | 
			
		||||
	}
 | 
			
		||||
	if flags.Changed(flagAvailability) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,6 +19,7 @@ const (
 | 
			
		|||
	flagDispatcherHeartbeat = "dispatcher-heartbeat"
 | 
			
		||||
	flagListenAddr          = "listen-addr"
 | 
			
		||||
	flagAdvertiseAddr       = "advertise-addr"
 | 
			
		||||
	flagDataPathAddr        = "data-path-addr"
 | 
			
		||||
	flagQuiet               = "quiet"
 | 
			
		||||
	flagRotate              = "rotate"
 | 
			
		||||
	flagToken               = "token"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3301,7 +3301,7 @@ _docker_swarm_init() {
 | 
			
		|||
 | 
			
		||||
	case "$cur" in
 | 
			
		||||
		-*)
 | 
			
		||||
			COMPREPLY=( $( compgen -W "--advertise-addr --autolock --availability --cert-expiry --dispatcher-heartbeat --external-ca --force-new-cluster --help --listen-addr --max-snapshots --snapshot-interval --task-history-limit" -- "$cur" ) )
 | 
			
		||||
			COMPREPLY=( $( compgen -W "--advertise-addr --data-path-addr --autolock --availability --cert-expiry --dispatcher-heartbeat --external-ca --force-new-cluster --help --listen-addr --max-snapshots --snapshot-interval --task-history-limit" -- "$cur" ) )
 | 
			
		||||
			;;
 | 
			
		||||
	esac
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -3337,7 +3337,7 @@ _docker_swarm_join() {
 | 
			
		|||
 | 
			
		||||
	case "$cur" in
 | 
			
		||||
		-*)
 | 
			
		||||
			COMPREPLY=( $( compgen -W "--advertise-addr --availability --help --listen-addr --token" -- "$cur" ) )
 | 
			
		||||
			COMPREPLY=( $( compgen -W "--advertise-addr --data-path-addr --availability --help --listen-addr --token" -- "$cur" ) )
 | 
			
		||||
			;;
 | 
			
		||||
		*:)
 | 
			
		||||
			COMPREPLY=( $( compgen -W "2377" -- "${cur##*:}" ) )
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2267,6 +2267,7 @@ __docker_swarm_subcommand() {
 | 
			
		|||
            _arguments $(__docker_arguments) \
 | 
			
		||||
                $opts_help \
 | 
			
		||||
                "($help)--advertise-addr=[Advertised address]:ip\:port: " \
 | 
			
		||||
                "($help)--data-path-addr=[Data path IP or interface]:ip " \
 | 
			
		||||
                "($help)--autolock[Enable manager autolocking]" \
 | 
			
		||||
                "($help)--availability=[Availability of the node]:availability:(active drain pause)" \
 | 
			
		||||
                "($help)--cert-expiry=[Validity period for node certificates]:duration: " \
 | 
			
		||||
| 
						 | 
				
			
			@ -2282,6 +2283,7 @@ __docker_swarm_subcommand() {
 | 
			
		|||
            _arguments $(__docker_arguments) -A '-*' \
 | 
			
		||||
                $opts_help \
 | 
			
		||||
                "($help)--advertise-addr=[Advertised address]:ip\:port: " \
 | 
			
		||||
                "($help)--data-path-addr=[Data path IP or interface]:ip " \
 | 
			
		||||
                "($help)--availability=[Availability of the node]:availability:(active drain pause)" \
 | 
			
		||||
                "($help)--listen-addr=[Listen address]:ip\:port: " \
 | 
			
		||||
                "($help)--token=[Token for entry into the swarm]:secret: " \
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -270,6 +270,16 @@ func (c *Cluster) GetAdvertiseAddress() string {
 | 
			
		|||
	return c.currentNodeState().actualLocalAddr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetDataPathAddress returns the address to be used for the data path traffic, if specified.
 | 
			
		||||
func (c *Cluster) GetDataPathAddress() string {
 | 
			
		||||
	c.mu.RLock()
 | 
			
		||||
	defer c.mu.RUnlock()
 | 
			
		||||
	if c.nr != nil {
 | 
			
		||||
		return c.nr.config.DataPathAddr
 | 
			
		||||
	}
 | 
			
		||||
	return ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetRemoteAddress returns a known advertise address of a remote manager if
 | 
			
		||||
// available.
 | 
			
		||||
// todo: change to array/connect with info
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,8 +10,10 @@ var (
 | 
			
		|||
	errNoSuchInterface         = errors.New("no such interface")
 | 
			
		||||
	errNoIP                    = errors.New("could not find the system's IP address")
 | 
			
		||||
	errMustSpecifyListenAddr   = errors.New("must specify a listening address because the address to advertise is not recognized as a system address, and a system's IP address to use could not be uniquely identified")
 | 
			
		||||
	errBadNetworkIdentifier    = errors.New("must specify a valid IP address or interface name")
 | 
			
		||||
	errBadListenAddr           = errors.New("listen address must be an IP address or network interface (with optional port number)")
 | 
			
		||||
	errBadAdvertiseAddr        = errors.New("advertise address must be a non-zero IP address or network interface (with optional port number)")
 | 
			
		||||
	errBadDataPathAddr         = errors.New("data path address must be a non-zero IP address or network interface (without a port number)")
 | 
			
		||||
	errBadDefaultAdvertiseAddr = errors.New("default advertise address must be a non-zero IP address or network interface (without a port number)")
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -20,23 +22,17 @@ func resolveListenAddr(specifiedAddr string) (string, string, error) {
 | 
			
		|||
	if err != nil {
 | 
			
		||||
		return "", "", fmt.Errorf("could not parse listen address %s", specifiedAddr)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Does the host component match any of the interface names on the
 | 
			
		||||
	// system? If so, use the address from that interface.
 | 
			
		||||
	interfaceAddr, err := resolveInterfaceAddr(specifiedHost)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		return interfaceAddr.String(), specifiedPort, nil
 | 
			
		||||
	}
 | 
			
		||||
	if err != errNoSuchInterface {
 | 
			
		||||
	specifiedIP, err := resolveInputIPAddr(specifiedHost, true)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if err == errBadNetworkIdentifier {
 | 
			
		||||
			err = errBadListenAddr
 | 
			
		||||
		}
 | 
			
		||||
		return "", "", err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// If it's not an interface, it must be an IP (for now)
 | 
			
		||||
	if net.ParseIP(specifiedHost) == nil {
 | 
			
		||||
		return "", "", errBadListenAddr
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return specifiedHost, specifiedPort, nil
 | 
			
		||||
	return specifiedIP.String(), specifiedPort, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Cluster) resolveAdvertiseAddr(advertiseAddr, listenAddrPort string) (string, string, error) {
 | 
			
		||||
| 
						 | 
				
			
			@ -57,43 +53,32 @@ func (c *Cluster) resolveAdvertiseAddr(advertiseAddr, listenAddrPort string) (st
 | 
			
		|||
			advertiseHost = advertiseAddr
 | 
			
		||||
			advertisePort = listenAddrPort
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Does the host component match any of the interface names on the
 | 
			
		||||
		// system? If so, use the address from that interface.
 | 
			
		||||
		interfaceAddr, err := resolveInterfaceAddr(advertiseHost)
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			return interfaceAddr.String(), advertisePort, nil
 | 
			
		||||
		}
 | 
			
		||||
		if err != errNoSuchInterface {
 | 
			
		||||
		advertiseIP, err := resolveInputIPAddr(advertiseHost, false)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			if err == errBadNetworkIdentifier {
 | 
			
		||||
				err = errBadAdvertiseAddr
 | 
			
		||||
			}
 | 
			
		||||
			return "", "", err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// If it's not an interface, it must be an IP (for now)
 | 
			
		||||
		if ip := net.ParseIP(advertiseHost); ip == nil || ip.IsUnspecified() {
 | 
			
		||||
			return "", "", errBadAdvertiseAddr
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return advertiseHost, advertisePort, nil
 | 
			
		||||
		return advertiseIP.String(), advertisePort, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if c.config.DefaultAdvertiseAddr != "" {
 | 
			
		||||
		// Does the default advertise address component match any of the
 | 
			
		||||
		// interface names on the system? If so, use the address from
 | 
			
		||||
		// that interface.
 | 
			
		||||
		interfaceAddr, err := resolveInterfaceAddr(c.config.DefaultAdvertiseAddr)
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			return interfaceAddr.String(), listenAddrPort, nil
 | 
			
		||||
		}
 | 
			
		||||
		if err != errNoSuchInterface {
 | 
			
		||||
		defaultAdvertiseIP, err := resolveInputIPAddr(c.config.DefaultAdvertiseAddr, false)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			if err == errBadNetworkIdentifier {
 | 
			
		||||
				err = errBadDefaultAdvertiseAddr
 | 
			
		||||
			}
 | 
			
		||||
			return "", "", err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// If it's not an interface, it must be an IP (for now)
 | 
			
		||||
		if ip := net.ParseIP(c.config.DefaultAdvertiseAddr); ip == nil || ip.IsUnspecified() {
 | 
			
		||||
			return "", "", errBadDefaultAdvertiseAddr
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return c.config.DefaultAdvertiseAddr, listenAddrPort, nil
 | 
			
		||||
		return defaultAdvertiseIP.String(), listenAddrPort, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	systemAddr, err := c.resolveSystemAddr()
 | 
			
		||||
| 
						 | 
				
			
			@ -103,6 +88,22 @@ func (c *Cluster) resolveAdvertiseAddr(advertiseAddr, listenAddrPort string) (st
 | 
			
		|||
	return systemAddr.String(), listenAddrPort, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func resolveDataPathAddr(dataPathAddr string) (string, error) {
 | 
			
		||||
	if dataPathAddr == "" {
 | 
			
		||||
		// dataPathAddr is not defined
 | 
			
		||||
		return "", nil
 | 
			
		||||
	}
 | 
			
		||||
	// If a data path flag is specified try to resolve the IP address.
 | 
			
		||||
	dataPathIP, err := resolveInputIPAddr(dataPathAddr, false)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if err == errBadNetworkIdentifier {
 | 
			
		||||
			err = errBadDataPathAddr
 | 
			
		||||
		}
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
	return dataPathIP.String(), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func resolveInterfaceAddr(specifiedInterface string) (net.IP, error) {
 | 
			
		||||
	// Use a specific interface's IP address.
 | 
			
		||||
	intf, err := net.InterfaceByName(specifiedInterface)
 | 
			
		||||
| 
						 | 
				
			
			@ -149,6 +150,30 @@ func resolveInterfaceAddr(specifiedInterface string) (net.IP, error) {
 | 
			
		|||
	return interfaceAddr6, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// resolveInputIPAddr tries to resolve the IP address from the string passed as input
 | 
			
		||||
// - tries to match the string as an interface name, if so returns the IP address associated with it
 | 
			
		||||
// - on failure of previous step tries to parse the string as an IP address itself
 | 
			
		||||
//	 if succeeds returns the IP address
 | 
			
		||||
func resolveInputIPAddr(input string, isUnspecifiedValid bool) (net.IP, error) {
 | 
			
		||||
	// Try to see if it is an interface name
 | 
			
		||||
	interfaceAddr, err := resolveInterfaceAddr(input)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		return interfaceAddr, nil
 | 
			
		||||
	}
 | 
			
		||||
	// String matched interface but there is a potential ambiguity to be resolved
 | 
			
		||||
	if err != errNoSuchInterface {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// String is not an interface check if it is a valid IP
 | 
			
		||||
	if ip := net.ParseIP(input); ip != nil && (isUnspecifiedValid || !ip.IsUnspecified()) {
 | 
			
		||||
		return ip, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Not valid IP found
 | 
			
		||||
	return nil, errBadNetworkIdentifier
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Cluster) resolveSystemAddrViaSubnetCheck() (net.IP, error) {
 | 
			
		||||
	// Use the system's only IP address, or fail if there are
 | 
			
		||||
	// multiple addresses to choose from. Skip interfaces which
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -46,7 +46,10 @@ type nodeStartConfig struct {
 | 
			
		|||
	ListenAddr string
 | 
			
		||||
	// AdvertiseAddr is the address other nodes should connect to,
 | 
			
		||||
	// including a port.
 | 
			
		||||
	AdvertiseAddr   string
 | 
			
		||||
	AdvertiseAddr string
 | 
			
		||||
	// DataPathAddr is the address that has to be used for the data path
 | 
			
		||||
	DataPathAddr string
 | 
			
		||||
 | 
			
		||||
	joinAddr        string
 | 
			
		||||
	forceNewCluster bool
 | 
			
		||||
	joinToken       string
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -54,6 +54,11 @@ func (c *Cluster) Init(req types.InitRequest) (string, error) {
 | 
			
		|||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dataPathAddr, err := resolveDataPathAddr(req.DataPathAddr)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	localAddr := listenHost
 | 
			
		||||
 | 
			
		||||
	// If the local address is undetermined, the advertise address
 | 
			
		||||
| 
						 | 
				
			
			@ -93,6 +98,7 @@ func (c *Cluster) Init(req types.InitRequest) (string, error) {
 | 
			
		|||
		LocalAddr:       localAddr,
 | 
			
		||||
		ListenAddr:      net.JoinHostPort(listenHost, listenPort),
 | 
			
		||||
		AdvertiseAddr:   net.JoinHostPort(advertiseHost, advertisePort),
 | 
			
		||||
		DataPathAddr:    dataPathAddr,
 | 
			
		||||
		availability:    req.Availability,
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
| 
						 | 
				
			
			@ -155,12 +161,18 @@ func (c *Cluster) Join(req types.JoinRequest) error {
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dataPathAddr, err := resolveDataPathAddr(req.DataPathAddr)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	clearPersistentState(c.root)
 | 
			
		||||
 | 
			
		||||
	nr, err := c.newNodeRunner(nodeStartConfig{
 | 
			
		||||
		RemoteAddr:    req.RemoteAddrs[0],
 | 
			
		||||
		ListenAddr:    net.JoinHostPort(listenHost, listenPort),
 | 
			
		||||
		AdvertiseAddr: advertiseAddr,
 | 
			
		||||
		DataPathAddr:  dataPathAddr,
 | 
			
		||||
		joinAddr:      req.RemoteAddrs[0],
 | 
			
		||||
		joinToken:     req.JoinToken,
 | 
			
		||||
		availability:  req.Availability,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,6 +25,7 @@ Options:
 | 
			
		|||
      --autolock                        Enable manager autolocking (requiring an unlock key to start a stopped manager)
 | 
			
		||||
      --availability string             Availability of the node ("active"|"pause"|"drain") (default "active")
 | 
			
		||||
      --cert-expiry duration            Validity period for node certificates (ns|us|ms|s|m|h) (default 2160h0m0s)
 | 
			
		||||
      --data-path-addr string           Address or interface to use for data path traffic (format: <ip|interface>)
 | 
			
		||||
      --dispatcher-heartbeat duration   Dispatcher heartbeat period (ns|us|ms|s|m|h) (default 5s)
 | 
			
		||||
      --external-ca external-ca         Specifications of one or more certificate signing endpoints
 | 
			
		||||
      --force-new-cluster               Force create a new cluster from current state
 | 
			
		||||
| 
						 | 
				
			
			@ -118,6 +119,15 @@ for example `--advertise-addr eth0:2377`.
 | 
			
		|||
Specifying a port is optional. If the value is a bare IP address or interface
 | 
			
		||||
name, the default port 2377 will be used.
 | 
			
		||||
 | 
			
		||||
### `--data-path-addr`
 | 
			
		||||
 | 
			
		||||
This flag specifies the address that global scope network drivers will publish towards
 | 
			
		||||
other nodes in order to reach the containers running on this node.
 | 
			
		||||
Using this parameter it is then possible to separate the container's data traffic from the
 | 
			
		||||
management traffic of the cluster.
 | 
			
		||||
If unspecified, Docker will use the same IP address or interface that is used for the
 | 
			
		||||
advertise address.
 | 
			
		||||
 | 
			
		||||
### `--task-history-limit`
 | 
			
		||||
 | 
			
		||||
This flag sets up task history retention limit.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,6 +23,7 @@ Join a swarm as a node and/or manager
 | 
			
		|||
Options:
 | 
			
		||||
      --advertise-addr string   Advertised address (format: <ip|interface>[:port])
 | 
			
		||||
      --availability string     Availability of the node ("active"|"pause"|"drain") (default "active")
 | 
			
		||||
      --data-path-addr string   Address or interface to use for data path traffic (format: <ip|interface>)
 | 
			
		||||
      --help                    Print usage
 | 
			
		||||
      --listen-addr node-addr   Listen address (format: <ip|interface>[:port]) (default 0.0.0.0:2377)
 | 
			
		||||
      --token string            Token for entry into the swarm
 | 
			
		||||
| 
						 | 
				
			
			@ -95,6 +96,15 @@ name, the default port 2377 will be used.
 | 
			
		|||
 | 
			
		||||
This flag is generally not necessary when joining an existing swarm.
 | 
			
		||||
 | 
			
		||||
### `--data-path-addr`
 | 
			
		||||
 | 
			
		||||
This flag specifies the address that global scope network drivers will publish towards
 | 
			
		||||
other nodes in order to reach the containers running on this node.
 | 
			
		||||
Using this parameter it is then possible to separate the container's data traffic from the
 | 
			
		||||
management traffic of the cluster.
 | 
			
		||||
If unspecified, Docker will use the same IP address or interface that is used for the
 | 
			
		||||
advertise address.
 | 
			
		||||
 | 
			
		||||
### `--token string`
 | 
			
		||||
 | 
			
		||||
Secret value required for nodes to join the swarm
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1932,3 +1932,15 @@ func (s *DockerSwarmSuite) TestSwarmServiceLsFilterMode(c *check.C) {
 | 
			
		|||
	c.Assert(out, checker.Contains, "top1")
 | 
			
		||||
	c.Assert(out, checker.Not(checker.Contains), "top2")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *DockerSwarmSuite) TestSwarmInitUnspecifiedDataPathAddr(c *check.C) {
 | 
			
		||||
	d := s.AddDaemon(c, false, false)
 | 
			
		||||
 | 
			
		||||
	out, err := d.Cmd("swarm", "init", "--data-path-addr", "0.0.0.0")
 | 
			
		||||
	c.Assert(err, checker.NotNil)
 | 
			
		||||
	c.Assert(out, checker.Contains, "data path address must be a non-zero IP")
 | 
			
		||||
 | 
			
		||||
	out, err = d.Cmd("swarm", "init", "--data-path-addr", "0.0.0.0:2000")
 | 
			
		||||
	c.Assert(err, checker.NotNil)
 | 
			
		||||
	c.Assert(out, checker.Contains, "data path address must be a non-zero IP")
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,7 +24,7 @@ github.com/RackSec/srslog 456df3a81436d29ba874f3590eeeee25d666f8a5
 | 
			
		|||
github.com/imdario/mergo 0.2.1
 | 
			
		||||
 | 
			
		||||
#get libnetwork packages
 | 
			
		||||
github.com/docker/libnetwork b13e0604016a4944025aaff521d9c125850b0d04
 | 
			
		||||
github.com/docker/libnetwork 5dc95a3f9ce4b70bf08492ca37ec55c5b6d84975
 | 
			
		||||
github.com/docker/go-events 18b43f1bc85d9cdd42c05a6cd2d444c7a200a894
 | 
			
		||||
github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80
 | 
			
		||||
github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										45
									
								
								vendor/github.com/docker/libnetwork/agent.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										45
									
								
								vendor/github.com/docker/libnetwork/agent.go
									
										
									
										generated
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -39,11 +39,21 @@ type agent struct {
 | 
			
		|||
	networkDB         *networkdb.NetworkDB
 | 
			
		||||
	bindAddr          string
 | 
			
		||||
	advertiseAddr     string
 | 
			
		||||
	dataPathAddr      string
 | 
			
		||||
	epTblCancel       func()
 | 
			
		||||
	driverCancelFuncs map[string][]func()
 | 
			
		||||
	sync.Mutex
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (a *agent) dataPathAddress() string {
 | 
			
		||||
	a.Lock()
 | 
			
		||||
	defer a.Unlock()
 | 
			
		||||
	if a.dataPathAddr != "" {
 | 
			
		||||
		return a.dataPathAddr
 | 
			
		||||
	}
 | 
			
		||||
	return a.advertiseAddr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const libnetworkEPTable = "endpoint_table"
 | 
			
		||||
 | 
			
		||||
func getBindAddr(ifaceName string) (string, error) {
 | 
			
		||||
| 
						 | 
				
			
			@ -187,16 +197,25 @@ func (c *controller) agentSetup() error {
 | 
			
		|||
	clusterProvider := c.cfg.Daemon.ClusterProvider
 | 
			
		||||
	agent := c.agent
 | 
			
		||||
	c.Unlock()
 | 
			
		||||
 | 
			
		||||
	if clusterProvider == nil {
 | 
			
		||||
		msg := "Aborting initialization of Libnetwork Agent because cluster provider is now unset"
 | 
			
		||||
		logrus.Errorf(msg)
 | 
			
		||||
		return fmt.Errorf(msg)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bindAddr := clusterProvider.GetLocalAddress()
 | 
			
		||||
	advAddr := clusterProvider.GetAdvertiseAddress()
 | 
			
		||||
	dataAddr := clusterProvider.GetDataPathAddress()
 | 
			
		||||
	remote := clusterProvider.GetRemoteAddress()
 | 
			
		||||
	remoteAddr, _, _ := net.SplitHostPort(remote)
 | 
			
		||||
	listen := clusterProvider.GetListenAddress()
 | 
			
		||||
	listenAddr, _, _ := net.SplitHostPort(listen)
 | 
			
		||||
 | 
			
		||||
	logrus.Infof("Initializing Libnetwork Agent Listen-Addr=%s Local-addr=%s Adv-addr=%s Remote-addr =%s", listenAddr, bindAddr, advAddr, remoteAddr)
 | 
			
		||||
	logrus.Infof("Initializing Libnetwork Agent Listen-Addr=%s Local-addr=%s Adv-addr=%s Data-addr=%s Remote-addr=%s",
 | 
			
		||||
		listenAddr, bindAddr, advAddr, dataAddr, remoteAddr)
 | 
			
		||||
	if advAddr != "" && agent == nil {
 | 
			
		||||
		if err := c.agentInit(listenAddr, bindAddr, advAddr); err != nil {
 | 
			
		||||
		if err := c.agentInit(listenAddr, bindAddr, advAddr, dataAddr); err != nil {
 | 
			
		||||
			logrus.Errorf("Error in agentInit : %v", err)
 | 
			
		||||
		} else {
 | 
			
		||||
			c.drvRegistry.WalkDrivers(func(name string, driver driverapi.Driver, capability driverapi.Capability) bool {
 | 
			
		||||
| 
						 | 
				
			
			@ -262,7 +281,7 @@ func (c *controller) getPrimaryKeyTag(subsys string) ([]byte, uint64, error) {
 | 
			
		|||
	return keys[1].Key, keys[1].LamportTime, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *controller) agentInit(listenAddr, bindAddrOrInterface, advertiseAddr string) error {
 | 
			
		||||
func (c *controller) agentInit(listenAddr, bindAddrOrInterface, advertiseAddr, dataPathAddr string) error {
 | 
			
		||||
	if !c.isAgent() {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -296,6 +315,7 @@ func (c *controller) agentInit(listenAddr, bindAddrOrInterface, advertiseAddr st
 | 
			
		|||
		networkDB:         nDB,
 | 
			
		||||
		bindAddr:          bindAddr,
 | 
			
		||||
		advertiseAddr:     advertiseAddr,
 | 
			
		||||
		dataPathAddr:      dataPathAddr,
 | 
			
		||||
		epTblCancel:       cancel,
 | 
			
		||||
		driverCancelFuncs: make(map[string][]func()),
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -336,25 +356,22 @@ func (c *controller) agentDriverNotify(d driverapi.Driver) {
 | 
			
		|||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	d.DiscoverNew(discoverapi.NodeDiscovery, discoverapi.NodeDiscoveryData{
 | 
			
		||||
		Address:     agent.advertiseAddr,
 | 
			
		||||
	if err := d.DiscoverNew(discoverapi.NodeDiscovery, discoverapi.NodeDiscoveryData{
 | 
			
		||||
		Address:     agent.dataPathAddress(),
 | 
			
		||||
		BindAddress: agent.bindAddr,
 | 
			
		||||
		Self:        true,
 | 
			
		||||
	})
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
		logrus.Warnf("Failed the node discovery in driver: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	drvEnc := discoverapi.DriverEncryptionConfig{}
 | 
			
		||||
	keys, tags := c.getKeys(subsysIPSec)
 | 
			
		||||
	drvEnc.Keys = keys
 | 
			
		||||
	drvEnc.Tags = tags
 | 
			
		||||
 | 
			
		||||
	c.drvRegistry.WalkDrivers(func(name string, driver driverapi.Driver, capability driverapi.Capability) bool {
 | 
			
		||||
		err := driver.DiscoverNew(discoverapi.EncryptionKeysConfig, drvEnc)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			logrus.Warnf("Failed to set datapath keys in driver %s: %v", name, err)
 | 
			
		||||
		}
 | 
			
		||||
		return false
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	if err := d.DiscoverNew(discoverapi.EncryptionKeysConfig, drvEnc); err != nil {
 | 
			
		||||
		logrus.Warnf("Failed to set datapath keys in driver: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *controller) agentClose() {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										1
									
								
								vendor/github.com/docker/libnetwork/cluster/provider.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/docker/libnetwork/cluster/provider.go
									
										
									
										generated
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -12,6 +12,7 @@ type Provider interface {
 | 
			
		|||
	GetLocalAddress() string
 | 
			
		||||
	GetListenAddress() string
 | 
			
		||||
	GetAdvertiseAddress() string
 | 
			
		||||
	GetDataPathAddress() string
 | 
			
		||||
	GetRemoteAddress() string
 | 
			
		||||
	ListenClusterEvents() <-chan struct{}
 | 
			
		||||
	AttachNetwork(string, string, []string) (*network.NetworkingConfig, error)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										13
									
								
								vendor/github.com/docker/libnetwork/default_gateway.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										13
									
								
								vendor/github.com/docker/libnetwork/default_gateway.go
									
										
									
										generated
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -4,6 +4,7 @@ import (
 | 
			
		|||
	"fmt"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/Sirupsen/logrus"
 | 
			
		||||
	"github.com/docker/libnetwork/netlabel"
 | 
			
		||||
	"github.com/docker/libnetwork/types"
 | 
			
		||||
)
 | 
			
		||||
| 
						 | 
				
			
			@ -72,9 +73,19 @@ func (sb *sandbox) setupDefaultGW() error {
 | 
			
		|||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("container %s: endpoint create on GW Network failed: %v", sb.containerID, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	defer func() {
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			if err2 := newEp.Delete(true); err2 != nil {
 | 
			
		||||
				logrus.Warnf("Failed to remove gw endpoint for container %s after failing to join the gateway network: %v",
 | 
			
		||||
					sb.containerID, err2)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	epLocal := newEp.(*endpoint)
 | 
			
		||||
 | 
			
		||||
	if err := epLocal.sbJoin(sb); err != nil {
 | 
			
		||||
	if err = epLocal.sbJoin(sb); err != nil {
 | 
			
		||||
		return fmt.Errorf("container %s: endpoint join on GW Network failed: %v", sb.containerID, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										22
									
								
								vendor/github.com/docker/libnetwork/endpoint.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										22
									
								
								vendor/github.com/docker/libnetwork/endpoint.go
									
										
									
										generated
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -427,7 +427,7 @@ func (ep *endpoint) Join(sbox Sandbox, options ...EndpointOption) error {
 | 
			
		|||
	return ep.sbJoin(sb, options...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (ep *endpoint) sbJoin(sb *sandbox, options ...EndpointOption) error {
 | 
			
		||||
func (ep *endpoint) sbJoin(sb *sandbox, options ...EndpointOption) (err error) {
 | 
			
		||||
	n, err := ep.getNetworkFromStore()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("failed to get network from store during join: %v", err)
 | 
			
		||||
| 
						 | 
				
			
			@ -462,7 +462,7 @@ func (ep *endpoint) sbJoin(sb *sandbox, options ...EndpointOption) error {
 | 
			
		|||
 | 
			
		||||
	d, err := n.driver(true)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("failed to join endpoint: %v", err)
 | 
			
		||||
		return fmt.Errorf("failed to get driver during join: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = d.Join(nid, epid, sb.Key(), ep, sb.Labels())
 | 
			
		||||
| 
						 | 
				
			
			@ -471,8 +471,8 @@ func (ep *endpoint) sbJoin(sb *sandbox, options ...EndpointOption) error {
 | 
			
		|||
	}
 | 
			
		||||
	defer func() {
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			if err := d.Leave(nid, epid); err != nil {
 | 
			
		||||
				logrus.Warnf("driver leave failed while rolling back join: %v", err)
 | 
			
		||||
			if e := d.Leave(nid, epid); e != nil {
 | 
			
		||||
				logrus.Warnf("driver leave failed while rolling back join: %v", e)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
| 
						 | 
				
			
			@ -538,11 +538,11 @@ func (ep *endpoint) sbJoin(sb *sandbox, options ...EndpointOption) error {
 | 
			
		|||
			logrus.Debugf("Revoking external connectivity on endpoint %s (%s)", extEp.Name(), extEp.ID())
 | 
			
		||||
			extN, err := extEp.getNetworkFromStore()
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return fmt.Errorf("failed to get network from store during join: %v", err)
 | 
			
		||||
				return fmt.Errorf("failed to get network from store for revoking external connectivity during join: %v", err)
 | 
			
		||||
			}
 | 
			
		||||
			extD, err := extN.driver(true)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return fmt.Errorf("failed to join endpoint: %v", err)
 | 
			
		||||
				return fmt.Errorf("failed to get driver for revoking external connectivity during join: %v", err)
 | 
			
		||||
			}
 | 
			
		||||
			if err = extD.RevokeExternalConnectivity(extEp.network.ID(), extEp.ID()); err != nil {
 | 
			
		||||
				return types.InternalErrorf(
 | 
			
		||||
| 
						 | 
				
			
			@ -570,9 +570,9 @@ func (ep *endpoint) sbJoin(sb *sandbox, options ...EndpointOption) error {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	if !sb.needDefaultGW() {
 | 
			
		||||
		if err := sb.clearDefaultGW(); err != nil {
 | 
			
		||||
		if e := sb.clearDefaultGW(); e != nil {
 | 
			
		||||
			logrus.Warnf("Failure while disconnecting sandbox %s (%s) from gateway network: %v",
 | 
			
		||||
				sb.ID(), sb.ContainerID(), err)
 | 
			
		||||
				sb.ID(), sb.ContainerID(), e)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -705,7 +705,7 @@ func (ep *endpoint) sbLeave(sb *sandbox, force bool, options ...EndpointOption)
 | 
			
		|||
 | 
			
		||||
	d, err := n.driver(!force)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("failed to leave endpoint: %v", err)
 | 
			
		||||
		return fmt.Errorf("failed to get driver during endpoint leave: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ep.Lock()
 | 
			
		||||
| 
						 | 
				
			
			@ -765,11 +765,11 @@ func (ep *endpoint) sbLeave(sb *sandbox, force bool, options ...EndpointOption)
 | 
			
		|||
		logrus.Debugf("Programming external connectivity on endpoint %s (%s)", extEp.Name(), extEp.ID())
 | 
			
		||||
		extN, err := extEp.getNetworkFromStore()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return fmt.Errorf("failed to get network from store during leave: %v", err)
 | 
			
		||||
			return fmt.Errorf("failed to get network from store for programming external connectivity during leave: %v", err)
 | 
			
		||||
		}
 | 
			
		||||
		extD, err := extN.driver(true)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return fmt.Errorf("failed to leave endpoint: %v", err)
 | 
			
		||||
			return fmt.Errorf("failed to get driver for programming external connectivity during leave: %v", err)
 | 
			
		||||
		}
 | 
			
		||||
		if err := extD.ProgramExternalConnectivity(extEp.network.ID(), extEp.ID(), sb.Labels()); err != nil {
 | 
			
		||||
			logrus.Warnf("driver failed programming external connectivity on endpoint %s: (%s) %v",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										9
									
								
								vendor/github.com/docker/libnetwork/networkdb/broadcast.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								vendor/github.com/docker/libnetwork/networkdb/broadcast.go
									
										
									
										generated
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -86,6 +86,15 @@ func (nDB *NetworkDB) sendNodeEvent(event NodeEvent_Type) error {
 | 
			
		|||
		notify: notifyCh,
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	nDB.RLock()
 | 
			
		||||
	noPeers := len(nDB.nodes) <= 1
 | 
			
		||||
	nDB.RUnlock()
 | 
			
		||||
 | 
			
		||||
	// Message enqueued, do not wait for a send if no peer is present
 | 
			
		||||
	if noPeers {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Wait for the broadcast
 | 
			
		||||
	select {
 | 
			
		||||
	case <-notifyCh:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										2
									
								
								vendor/github.com/docker/libnetwork/networkdb/cluster.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/docker/libnetwork/networkdb/cluster.go
									
										
									
										generated
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -17,7 +17,7 @@ import (
 | 
			
		|||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	reapInterval     = 60 * time.Second
 | 
			
		||||
	reapInterval     = 30 * time.Minute
 | 
			
		||||
	reapPeriod       = 5 * time.Second
 | 
			
		||||
	retryInterval    = 1 * time.Second
 | 
			
		||||
	nodeReapInterval = 24 * time.Hour
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue