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 }