Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fingerprint: config parameter for interface and native method for IP address #189

Merged
merged 7 commits into from
Oct 2, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't that be err != nil?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, no, that function should return the IP if there was no error, so if err == nil. Look at the if body.

If err is different than nil, its execution continues, and we would try the ifconfig method.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah, I see. Thanks.

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