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