github.com/mattyr/nomad@v0.3.3-0.20160919021406-3485a065154a/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 switch { 59 case err != nil: 60 return false, fmt.Errorf("Error while detecting network interface during fingerprinting: %v", err) 61 case intf == nil: 62 // No interface could be found 63 return false, nil 64 } 65 66 if ip, err = f.ipAddress(intf); err != nil { 67 return false, fmt.Errorf("Unable to find IP address of interface: %s, err: %v", intf.Name, err) 68 } 69 70 newNetwork.Device = intf.Name 71 node.Attributes["unique.network.ip-address"] = ip 72 newNetwork.IP = ip 73 newNetwork.CIDR = newNetwork.IP + "/32" 74 75 f.logger.Printf("[DEBUG] fingerprint.network: Detected interface %v with IP %v during fingerprinting", intf.Name, ip) 76 77 if throughput := f.linkSpeed(intf.Name); throughput > 0 { 78 newNetwork.MBits = throughput 79 f.logger.Printf("[DEBUG] fingerprint.network: link speed for %v set to %v", intf.Name, newNetwork.MBits) 80 } else { 81 f.logger.Printf("[DEBUG] fingerprint.network: Unable to read link speed; setting to default %v", cfg.NetworkSpeed) 82 newNetwork.MBits = cfg.NetworkSpeed 83 } 84 85 if node.Resources == nil { 86 node.Resources = &structs.Resources{} 87 } 88 89 node.Resources.Networks = append(node.Resources.Networks, newNetwork) 90 91 // return true, because we have a network connection 92 return true, nil 93 } 94 95 // Gets the ipv4 addr for a network interface 96 func (f *NetworkFingerprint) ipAddress(intf *net.Interface) (string, error) { 97 var addrs []net.Addr 98 var err error 99 100 if addrs, err = f.interfaceDetector.Addrs(intf); err != nil { 101 return "", err 102 } 103 104 if len(addrs) == 0 { 105 return "", errors.New(fmt.Sprintf("Interface %s has no IP address", intf.Name)) 106 } 107 for _, addr := range addrs { 108 var ip net.IP 109 switch v := (addr).(type) { 110 case *net.IPNet: 111 ip = v.IP 112 case *net.IPAddr: 113 ip = v.IP 114 } 115 if ip.To4() != nil { 116 return ip.String(), nil 117 } 118 } 119 120 return "", fmt.Errorf("Couldn't parse IP address for interface %s", intf.Name) 121 122 } 123 124 // Checks if the device is marked UP by the operator 125 func (f *NetworkFingerprint) isDeviceEnabled(intf *net.Interface) bool { 126 return intf.Flags&net.FlagUp != 0 127 } 128 129 // Checks if the device has any IP address configured 130 func (f *NetworkFingerprint) deviceHasIpAddress(intf *net.Interface) bool { 131 _, err := f.ipAddress(intf) 132 return err == nil 133 } 134 135 func (n *NetworkFingerprint) isDeviceLoopBackOrPointToPoint(intf *net.Interface) bool { 136 return intf.Flags&(net.FlagLoopback|net.FlagPointToPoint) != 0 137 } 138 139 // Returns the interface with the name passed by user 140 // If the name is blank then it iterates through all the devices 141 // and finds one which is routable and marked as UP 142 // It excludes PPP and lo devices unless they are specifically asked 143 func (f *NetworkFingerprint) findInterface(deviceName string) (*net.Interface, error) { 144 var interfaces []net.Interface 145 var err error 146 147 if deviceName != "" { 148 return f.interfaceDetector.InterfaceByName(deviceName) 149 } 150 151 var intfs []net.Interface 152 153 if intfs, err = f.interfaceDetector.Interfaces(); err != nil { 154 return nil, err 155 } 156 157 for _, intf := range intfs { 158 if f.isDeviceEnabled(&intf) && !f.isDeviceLoopBackOrPointToPoint(&intf) && f.deviceHasIpAddress(&intf) { 159 interfaces = append(interfaces, intf) 160 } 161 } 162 163 if len(interfaces) == 0 { 164 return nil, nil 165 } 166 return &interfaces[0], nil 167 }