Skip to content

Commit e943746

Browse files
committed
Merge pull request #189 from apognu/dev/net-fingerprint
Fingerprint: config parameter for interface and native method for IP address
2 parents 96b6109 + e3bcf44 commit e943746

File tree

5 files changed

+73
-4
lines changed

5 files changed

+73
-4
lines changed

client/config/config.go

+3
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ type Config struct {
3131
// Region is the clients region
3232
Region string
3333

34+
// Network interface to be used in network fingerprinting
35+
NetworkInterface string
36+
3437
// Servers is a list of known server addresses. These are as "host:port"
3538
Servers []string
3639

client/fingerprint/network_unix.go

+56-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
package fingerprint
44

55
import (
6+
"errors"
67
"fmt"
78
"io/ioutil"
89
"log"
@@ -38,10 +39,14 @@ func (f *NetworkFingerprint) Fingerprint(cfg *config.Config, node *structs.Node)
3839
if "darwin" == runtime.GOOS {
3940
defaultDevice = "en0"
4041
}
42+
// User-defined override for the default interface
43+
if cfg.NetworkInterface != "" {
44+
defaultDevice = cfg.NetworkInterface
45+
}
4146

4247
newNetwork.Device = defaultDevice
4348

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

137+
// ipAddress returns the first IPv4 address on the configured default interface
138+
// Tries Golang native functions and falls back onto ifconfig
139+
func (f *NetworkFingerprint) ipAddress(device string) string {
140+
if ip, err := f.nativeIpAddress(device); err == nil {
141+
return ip
142+
}
143+
144+
return f.ifConfig(device)
145+
}
146+
147+
func (f *NetworkFingerprint) nativeIpAddress(device string) (string, error) {
148+
// Find IP address on configured interface
149+
var ip string
150+
ifaces, err := net.Interfaces()
151+
if err != nil {
152+
return "", errors.New("could not retrieve interface list")
153+
}
154+
155+
// TODO: should we handle IPv6 here? How do we determine precedence?
156+
for _, i := range ifaces {
157+
if i.Name != device {
158+
continue
159+
}
160+
161+
addrs, err := i.Addrs()
162+
if err != nil {
163+
return "", errors.New("could not retrieve interface IP addresses")
164+
}
165+
166+
for _, a := range addrs {
167+
switch v := a.(type) {
168+
case *net.IPNet:
169+
if v.IP.To4() != nil {
170+
ip = v.IP.String()
171+
}
172+
case *net.IPAddr:
173+
if v.IP.To4() != nil {
174+
ip = v.IP.String()
175+
}
176+
}
177+
}
178+
}
179+
180+
if net.ParseIP(ip) == nil {
181+
return "", errors.New(fmt.Sprintf("could not parse IP address `%s`", ip))
182+
}
183+
184+
return ip, nil
185+
}
186+
132187
// ifConfig returns the IP Address for this node according to ifConfig, for the
133188
// specified device.
134189
func (f *NetworkFingerprint) ifConfig(device string) string {

command/agent/agent.go

+3
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,9 @@ func (a *Agent) setupClient() error {
192192
conf.AllocDir = a.config.Client.AllocDir
193193
}
194194
conf.Servers = a.config.Client.Servers
195+
if a.config.Client.NetworkInterface != "" {
196+
conf.NetworkInterface = a.config.Client.NetworkInterface
197+
}
195198

196199
// Setup the node
197200
conf.Node = new(structs.Node)

command/agent/config.go

+6
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,9 @@ type ClientConfig struct {
139139

140140
// Metadata associated with the node
141141
Meta map[string]string `hcl:"meta"`
142+
143+
// Interface to use for network fingerprinting
144+
NetworkInterface string `hcl:"network_interface"`
142145
}
143146

144147
// ServerConfig is configuration specific to the server mode
@@ -384,6 +387,9 @@ func (a *ClientConfig) Merge(b *ClientConfig) *ClientConfig {
384387
if b.NodeClass != "" {
385388
result.NodeClass = b.NodeClass
386389
}
390+
if b.NetworkInterface != "" {
391+
result.NetworkInterface = b.NetworkInterface
392+
}
387393

388394
// Add the servers
389395
result.Servers = append(result.Servers, b.Servers...)

website/source/docs/agent/config.html.md

+5-3
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ nodes, unless otherwise specified:
8484
TCP and UDP should be routable between the server nodes on this port.
8585
Defaults to `4648`. Only used on server nodes.
8686

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

211213
## Atlas Options
212214

0 commit comments

Comments
 (0)