Skip to content

Commit

Permalink
Merge pull request #189 from apognu/dev/net-fingerprint
Browse files Browse the repository at this point in the history
Fingerprint: config parameter for interface and native method for IP address
  • Loading branch information
dadgar committed Oct 2, 2015
2 parents 96b6109 + e3bcf44 commit e943746
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 4 deletions.
3 changes: 3 additions & 0 deletions client/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ type Config struct {
// Region is the clients region
Region string

// Network interface to be used in network fingerprinting
NetworkInterface string

// Servers is a list of known server addresses. These are as "host:port"
Servers []string

Expand Down
57 changes: 56 additions & 1 deletion client/fingerprint/network_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
package fingerprint

import (
"errors"
"fmt"
"io/ioutil"
"log"
Expand Down Expand Up @@ -38,10 +39,14 @@ func (f *NetworkFingerprint) Fingerprint(cfg *config.Config, node *structs.Node)
if "darwin" == runtime.GOOS {
defaultDevice = "en0"
}
// User-defined override for the default interface
if cfg.NetworkInterface != "" {
defaultDevice = cfg.NetworkInterface
}

newNetwork.Device = defaultDevice

if ip := f.ifConfig(defaultDevice); ip != "" {
if ip := f.ipAddress(defaultDevice); ip != "" {
node.Attributes["network.ip-address"] = ip
newNetwork.IP = ip
newNetwork.CIDR = newNetwork.IP + "/32"
Expand Down Expand Up @@ -129,6 +134,56 @@ func (f *NetworkFingerprint) linkSpeedEthtool(path, device string) int {
return mbs
}

// ipAddress returns the first IPv4 address on the configured default interface
// Tries Golang native functions and falls back onto ifconfig
func (f *NetworkFingerprint) ipAddress(device string) string {
if ip, err := f.nativeIpAddress(device); err == nil {
return ip
}

return f.ifConfig(device)
}

func (f *NetworkFingerprint) nativeIpAddress(device string) (string, error) {
// Find IP address on configured interface
var ip string
ifaces, err := net.Interfaces()
if err != nil {
return "", errors.New("could not retrieve interface list")
}

// TODO: should we handle IPv6 here? How do we determine precedence?
for _, i := range ifaces {
if i.Name != device {
continue
}

addrs, err := i.Addrs()
if err != nil {
return "", errors.New("could not retrieve interface IP addresses")
}

for _, a := range addrs {
switch v := a.(type) {
case *net.IPNet:
if v.IP.To4() != nil {
ip = v.IP.String()
}
case *net.IPAddr:
if v.IP.To4() != nil {
ip = v.IP.String()
}
}
}
}

if net.ParseIP(ip) == nil {
return "", errors.New(fmt.Sprintf("could not parse IP address `%s`", ip))
}

return ip, nil
}

// ifConfig returns the IP Address for this node according to ifConfig, for the
// specified device.
func (f *NetworkFingerprint) ifConfig(device string) string {
Expand Down
3 changes: 3 additions & 0 deletions command/agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,9 @@ func (a *Agent) setupClient() error {
conf.AllocDir = a.config.Client.AllocDir
}
conf.Servers = a.config.Client.Servers
if a.config.Client.NetworkInterface != "" {
conf.NetworkInterface = a.config.Client.NetworkInterface
}

// Setup the node
conf.Node = new(structs.Node)
Expand Down
6 changes: 6 additions & 0 deletions command/agent/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,9 @@ type ClientConfig struct {

// Metadata associated with the node
Meta map[string]string `hcl:"meta"`

// Interface to use for network fingerprinting
NetworkInterface string `hcl:"network_interface"`
}

// ServerConfig is configuration specific to the server mode
Expand Down Expand Up @@ -384,6 +387,9 @@ func (a *ClientConfig) Merge(b *ClientConfig) *ClientConfig {
if b.NodeClass != "" {
result.NodeClass = b.NodeClass
}
if b.NetworkInterface != "" {
result.NetworkInterface = b.NetworkInterface
}

// Add the servers
result.Servers = append(result.Servers, b.Servers...)
Expand Down
8 changes: 5 additions & 3 deletions website/source/docs/agent/config.html.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ nodes, unless otherwise specified:
TCP and UDP should be routable between the server nodes on this port.
Defaults to `4648`. Only used on server nodes.

* <a id="addresses">`addresses`</a>: Controls the bind address for individual
* <a id="addresses">`addresses`</a>: Controls the bind address for individual
network services. Any values configured in this block take precedence over the
default [bind_addr](#bind_addr). The value is a map of IP addresses and
supports the following keys:
Expand Down Expand Up @@ -154,7 +154,7 @@ configured on client nodes.
* `enabled`: A boolean indicating if server mode should be enabled for the
local agent. All other server options depend on this value being set.
Defaults to `false`.
* <a id="bootstrap_expect">`bootstrap_expect`</a>: This is an integer
* <a id="bootstrap_expect">`bootstrap_expect`</a>: This is an integer
representing the number of server nodes to wait for before bootstrapping. It
is most common to use the odd-numbered integers `3` or `5` for this value,
depending on the cluster size. A value of `1` does not provide any fault
Expand Down Expand Up @@ -205,8 +205,10 @@ configured on server nodes.
* <a id="node_class">`node_class`</a>: A string used to logically group client
nodes by class. This can be used during job placement as a filter. This
option is not required and has no default.
* <a id="meta">`meta`</a>: This is a key/value mapping of metadata pairs. This
* <a id="meta">`meta`</a>: This is a key/value mapping of metadata pairs. This
is a free-form map and can contain any string values.
* `network_interface`: This is a string to force network fingerprinting to use
a specific network interface

## Atlas Options

Expand Down

0 comments on commit e943746

Please sign in to comment.