github.com/dkerwin/nomad@v0.3.3-0.20160525181927-74554135514b/client/fingerprint/network.go (about)

     1  package fingerprint
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"log"
     7  	"net"
     8  
     9  	"github.com/hashicorp/nomad/client/config"
    10  	"github.com/hashicorp/nomad/nomad/structs"
    11  )
    12  
    13  // NetworkFingerprint is used to fingerprint the Network capabilities of a node
    14  type NetworkFingerprint struct {
    15  	StaticFingerprinter
    16  	logger            *log.Logger
    17  	interfaceDetector NetworkInterfaceDetector
    18  }
    19  
    20  // An interface to isolate calls to various api in net package
    21  // This facilitates testing where we can implement
    22  // fake interfaces and addresses to test varios code paths
    23  type NetworkInterfaceDetector interface {
    24  	Interfaces() ([]net.Interface, error)
    25  	InterfaceByName(name string) (*net.Interface, error)
    26  	Addrs(intf *net.Interface) ([]net.Addr, error)
    27  }
    28  
    29  // Implements the interface detector which calls net directly
    30  type DefaultNetworkInterfaceDetector struct {
    31  }
    32  
    33  func (b *DefaultNetworkInterfaceDetector) Interfaces() ([]net.Interface, error) {
    34  	return net.Interfaces()
    35  }
    36  
    37  func (b *DefaultNetworkInterfaceDetector) InterfaceByName(name string) (*net.Interface, error) {
    38  	return net.InterfaceByName(name)
    39  }
    40  
    41  func (b *DefaultNetworkInterfaceDetector) Addrs(intf *net.Interface) ([]net.Addr, error) {
    42  	return intf.Addrs()
    43  }
    44  
    45  // NewNetworkFingerprint returns a new NetworkFingerprinter with the given
    46  // logger
    47  func NewNetworkFingerprint(logger *log.Logger) Fingerprint {
    48  	f := &NetworkFingerprint{logger: logger, interfaceDetector: &DefaultNetworkInterfaceDetector{}}
    49  	return f
    50  }
    51  
    52  func (f *NetworkFingerprint) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) {
    53  	// newNetwork is populated and addded to the Nodes resources
    54  	newNetwork := &structs.NetworkResource{}
    55  	var ip string
    56  
    57  	intf, err := f.findInterface(cfg.NetworkInterface)
    58  	if err != nil {
    59  		return false, fmt.Errorf("Error while detecting network interface during fingerprinting: %v", err)
    60  	}
    61  
    62  	// No interface could be found
    63  	if intf == nil {
    64  		return false, nil
    65  	}
    66  
    67  	if ip, err = f.ipAddress(intf); err != nil {
    68  		return false, fmt.Errorf("Unable to find IP address of interface: %s, err: %v", intf.Name, err)
    69  	}
    70  
    71  	newNetwork.Device = intf.Name
    72  	node.Attributes["unique.network.ip-address"] = ip
    73  	newNetwork.IP = ip
    74  	newNetwork.CIDR = newNetwork.IP + "/32"
    75  
    76  	f.logger.Printf("[DEBUG] fingerprint.network: Detected interface %v with IP %v during fingerprinting", intf.Name, ip)
    77  
    78  	if throughput := f.linkSpeed(intf.Name); throughput > 0 {
    79  		newNetwork.MBits = throughput
    80  		f.logger.Printf("[DEBUG] fingerprint.network: link speed for %v set to %v", intf.Name, newNetwork.MBits)
    81  	} else {
    82  		f.logger.Printf("[DEBUG] fingerprint.network: Unable to read link speed; setting to default %v", cfg.NetworkSpeed)
    83  		newNetwork.MBits = cfg.NetworkSpeed
    84  	}
    85  
    86  	if node.Resources == nil {
    87  		node.Resources = &structs.Resources{}
    88  	}
    89  
    90  	node.Resources.Networks = append(node.Resources.Networks, newNetwork)
    91  
    92  	// return true, because we have a network connection
    93  	return true, nil
    94  }
    95  
    96  // Gets the ipv4 addr for a network interface
    97  func (f *NetworkFingerprint) ipAddress(intf *net.Interface) (string, error) {
    98  	var addrs []net.Addr
    99  	var err error
   100  
   101  	if addrs, err = f.interfaceDetector.Addrs(intf); err != nil {
   102  		return "", err
   103  	}
   104  
   105  	if len(addrs) == 0 {
   106  		return "", errors.New(fmt.Sprintf("Interface %s has no IP address", intf.Name))
   107  	}
   108  	for _, addr := range addrs {
   109  		var ip net.IP
   110  		switch v := (addr).(type) {
   111  		case *net.IPNet:
   112  			ip = v.IP
   113  		case *net.IPAddr:
   114  			ip = v.IP
   115  		}
   116  		if ip.To4() != nil {
   117  			return ip.String(), nil
   118  		}
   119  	}
   120  
   121  	return "", fmt.Errorf("Couldn't parse IP address for interface %s", intf.Name)
   122  
   123  }
   124  
   125  // Checks if the device is marked UP by the operator
   126  func (f *NetworkFingerprint) isDeviceEnabled(intf *net.Interface) bool {
   127  	return intf.Flags&net.FlagUp != 0
   128  }
   129  
   130  // Checks if the device has any IP address configured
   131  func (f *NetworkFingerprint) deviceHasIpAddress(intf *net.Interface) bool {
   132  	_, err := f.ipAddress(intf)
   133  	return err == nil
   134  }
   135  
   136  func (n *NetworkFingerprint) isDeviceLoopBackOrPointToPoint(intf *net.Interface) bool {
   137  	return intf.Flags&(net.FlagLoopback|net.FlagPointToPoint) != 0
   138  }
   139  
   140  // Returns the interface with the name passed by user
   141  // If the name is blank then it iterates through all the devices
   142  // and finds one which is routable and marked as UP
   143  // It excludes PPP and lo devices unless they are specifically asked
   144  func (f *NetworkFingerprint) findInterface(deviceName string) (*net.Interface, error) {
   145  	var interfaces []net.Interface
   146  	var err error
   147  
   148  	if deviceName != "" {
   149  		return f.interfaceDetector.InterfaceByName(deviceName)
   150  	}
   151  
   152  	var intfs []net.Interface
   153  
   154  	if intfs, err = f.interfaceDetector.Interfaces(); err != nil {
   155  		return nil, err
   156  	}
   157  
   158  	for _, intf := range intfs {
   159  		if f.isDeviceEnabled(&intf) && !f.isDeviceLoopBackOrPointToPoint(&intf) && f.deviceHasIpAddress(&intf) {
   160  			interfaces = append(interfaces, intf)
   161  		}
   162  	}
   163  
   164  	if len(interfaces) == 0 {
   165  		return nil, nil
   166  	}
   167  	return &interfaces[0], nil
   168  }