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 5 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
Iface string
Copy link
Contributor

Choose a reason for hiding this comment

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

Lets change Iface to "NetworkInterface" for long term clarity both in code and docs. After that lets merge! Thanks


// 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.Iface != "" {
Copy link
Contributor

Choose a reason for hiding this comment

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

Put a comment above to the tune of:

// Allow the user to override the default network device.

defaultDevice = cfg.Iface
}

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.Iface != "" {
conf.Iface = a.config.Client.Iface
}

// 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
Iface string `hcl:"iface"`
}

// 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.Iface != "" {
result.Iface = b.Iface
}

// Add the servers
result.Servers = append(result.Servers, b.Servers...)
Expand Down
2 changes: 2 additions & 0 deletions website/source/docs/agent/config.html.md
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,8 @@ configured on server nodes.
and has no default.
* `meta`: This is a key/value mapping of metadata pairs. This is a free-form
map and can contain any string values.
* `iface`: This is a string to force network fingerprinting to use a specific
network interface

## Atlas Options

Expand Down