github.com/hhrutter/nomad@v0.6.0-rc2.0.20170723054333-80c4b03f0705/client/fingerprint/network_test.go (about) 1 package fingerprint 2 3 import ( 4 "fmt" 5 "net" 6 "os" 7 "testing" 8 9 "github.com/hashicorp/nomad/client/config" 10 "github.com/hashicorp/nomad/nomad/structs" 11 ) 12 13 // Set skipOnlineTestEnvVar to a non-empty value to skip network tests. Useful 14 // when working offline (e.g. an airplane). 15 const skipOnlineTestsEnvVar = "TEST_NOMAD_SKIP_ONLINE_NET" 16 17 var ( 18 lo = net.Interface{ 19 Index: 2, 20 MTU: 65536, 21 Name: "lo", 22 HardwareAddr: []byte{23, 43, 54, 54}, 23 Flags: net.FlagUp | net.FlagLoopback, 24 } 25 26 eth0 = net.Interface{ 27 Index: 3, 28 MTU: 1500, 29 Name: "eth0", 30 HardwareAddr: []byte{23, 44, 54, 67}, 31 Flags: net.FlagUp | net.FlagMulticast | net.FlagBroadcast, 32 } 33 34 eth1 = net.Interface{ 35 Index: 4, 36 MTU: 1500, 37 Name: "eth1", 38 HardwareAddr: []byte{23, 44, 54, 69}, 39 Flags: net.FlagMulticast | net.FlagBroadcast, 40 } 41 42 eth2 = net.Interface{ 43 Index: 4, 44 MTU: 1500, 45 Name: "eth2", 46 HardwareAddr: []byte{23, 44, 54, 70}, 47 Flags: net.FlagUp | net.FlagBroadcast | net.FlagMulticast, 48 } 49 ) 50 51 // A fake network detector which returns no devices 52 type NetworkIntefaceDetectorNoDevices struct { 53 } 54 55 func (f *NetworkIntefaceDetectorNoDevices) Interfaces() ([]net.Interface, error) { 56 return make([]net.Interface, 0), nil 57 } 58 59 func (f *NetworkIntefaceDetectorNoDevices) InterfaceByName(name string) (*net.Interface, error) { 60 return nil, fmt.Errorf("Device with name %s doesn't exist", name) 61 } 62 63 func (f *NetworkIntefaceDetectorNoDevices) Addrs(intf *net.Interface) ([]net.Addr, error) { 64 return nil, fmt.Errorf("No interfaces found for device %v", intf.Name) 65 } 66 67 // A fake network detector which returns only loopback 68 type NetworkInterfaceDetectorOnlyLo struct { 69 } 70 71 func (n *NetworkInterfaceDetectorOnlyLo) Interfaces() ([]net.Interface, error) { 72 return []net.Interface{lo}, nil 73 } 74 75 func (n *NetworkInterfaceDetectorOnlyLo) InterfaceByName(name string) (*net.Interface, error) { 76 if name == "lo" { 77 return &lo, nil 78 } 79 80 return nil, fmt.Errorf("No device with name %v found", name) 81 } 82 83 func (n *NetworkInterfaceDetectorOnlyLo) Addrs(intf *net.Interface) ([]net.Addr, error) { 84 if intf.Name == "lo" { 85 _, ipnet1, _ := net.ParseCIDR("127.0.0.1/8") 86 _, ipnet2, _ := net.ParseCIDR("2001:DB8::/48") 87 return []net.Addr{ipnet1, ipnet2}, nil 88 } 89 90 return nil, fmt.Errorf("Can't find addresses for device: %v", intf.Name) 91 } 92 93 // A fake network detector which simulates the presence of multiple interfaces 94 type NetworkInterfaceDetectorMultipleInterfaces struct { 95 } 96 97 func (n *NetworkInterfaceDetectorMultipleInterfaces) Interfaces() ([]net.Interface, error) { 98 return []net.Interface{lo, eth0, eth1, eth2}, nil 99 } 100 101 func (n *NetworkInterfaceDetectorMultipleInterfaces) InterfaceByName(name string) (*net.Interface, error) { 102 var intf *net.Interface 103 switch name { 104 case "lo": 105 intf = &lo 106 case "eth0": 107 intf = ð0 108 case "eth1": 109 intf = ð1 110 case "eth2": 111 intf = ð2 112 } 113 if intf != nil { 114 return intf, nil 115 } 116 117 return nil, fmt.Errorf("No device with name %v found", name) 118 } 119 120 func (n *NetworkInterfaceDetectorMultipleInterfaces) Addrs(intf *net.Interface) ([]net.Addr, error) { 121 if intf.Name == "lo" { 122 _, ipnet1, _ := net.ParseCIDR("127.0.0.1/8") 123 _, ipnet2, _ := net.ParseCIDR("2001:DB8::/48") 124 return []net.Addr{ipnet1, ipnet2}, nil 125 } 126 127 if intf.Name == "eth0" { 128 _, ipnet1, _ := net.ParseCIDR("100.64.0.11/10") 129 _, ipnet2, _ := net.ParseCIDR("2001:0db8:85a3:0000:0000:8a2e:0370:7334/64") 130 ipAddr, _ := net.ResolveIPAddr("ip6", "fe80::140c:9579:8037:f565") 131 return []net.Addr{ipnet1, ipnet2, ipAddr}, nil 132 } 133 134 if intf.Name == "eth1" { 135 _, ipnet1, _ := net.ParseCIDR("100.64.0.10/10") 136 _, ipnet2, _ := net.ParseCIDR("2003:DB8::/48") 137 return []net.Addr{ipnet1, ipnet2}, nil 138 } 139 140 if intf.Name == "eth2" { 141 return []net.Addr{}, nil 142 } 143 return nil, fmt.Errorf("Can't find addresses for device: %v", intf.Name) 144 } 145 146 func TestNetworkFingerprint_basic(t *testing.T) { 147 if v := os.Getenv(skipOnlineTestsEnvVar); v != "" { 148 t.Skipf("Environment variable %+q not empty, skipping test", skipOnlineTestsEnvVar) 149 } 150 151 f := &NetworkFingerprint{logger: testLogger(), interfaceDetector: &DefaultNetworkInterfaceDetector{}} 152 node := &structs.Node{ 153 Attributes: make(map[string]string), 154 } 155 cfg := &config.Config{NetworkSpeed: 101} 156 157 ok, err := f.Fingerprint(cfg, node) 158 if err != nil { 159 t.Fatalf("err: %v", err) 160 } 161 if !ok { 162 t.Fatalf("should apply (HINT: working offline? Set env %q=y", skipOnlineTestsEnvVar) 163 } 164 165 assertNodeAttributeContains(t, node, "unique.network.ip-address") 166 167 ip := node.Attributes["unique.network.ip-address"] 168 match := net.ParseIP(ip) 169 if match == nil { 170 t.Fatalf("Bad IP match: %s", ip) 171 } 172 173 if node.Resources == nil || len(node.Resources.Networks) == 0 { 174 t.Fatal("Expected to find Network Resources") 175 } 176 177 // Test at least the first Network Resource 178 net := node.Resources.Networks[0] 179 if net.IP == "" { 180 t.Fatal("Expected Network Resource to not be empty") 181 } 182 if net.CIDR == "" { 183 t.Fatal("Expected Network Resource to have a CIDR") 184 } 185 if net.Device == "" { 186 t.Fatal("Expected Network Resource to have a Device Name") 187 } 188 if net.MBits != 101 { 189 t.Fatalf("Expected Network Resource to have bandwith %d; got %d", 101, net.MBits) 190 } 191 } 192 193 func TestNetworkFingerprint_no_devices(t *testing.T) { 194 f := &NetworkFingerprint{logger: testLogger(), interfaceDetector: &NetworkIntefaceDetectorNoDevices{}} 195 node := &structs.Node{ 196 Attributes: make(map[string]string), 197 } 198 cfg := &config.Config{NetworkSpeed: 100} 199 200 ok, err := f.Fingerprint(cfg, node) 201 if err != nil { 202 t.Fatalf("err: %v", err) 203 } 204 205 if ok { 206 t.Fatalf("ok: %v", ok) 207 } 208 } 209 210 func TestNetworkFingerprint_default_device_absent(t *testing.T) { 211 f := &NetworkFingerprint{logger: testLogger(), interfaceDetector: &NetworkInterfaceDetectorOnlyLo{}} 212 node := &structs.Node{ 213 Attributes: make(map[string]string), 214 } 215 cfg := &config.Config{NetworkSpeed: 100, NetworkInterface: "eth0"} 216 217 ok, err := f.Fingerprint(cfg, node) 218 if err == nil { 219 t.Fatalf("err: %v", err) 220 } 221 222 if ok { 223 t.Fatalf("ok: %v", ok) 224 } 225 } 226 227 func TestNetworkFingerPrint_default_device(t *testing.T) { 228 f := &NetworkFingerprint{logger: testLogger(), interfaceDetector: &NetworkInterfaceDetectorOnlyLo{}} 229 node := &structs.Node{ 230 Attributes: make(map[string]string), 231 } 232 cfg := &config.Config{NetworkSpeed: 100, NetworkInterface: "lo"} 233 234 ok, err := f.Fingerprint(cfg, node) 235 if err != nil { 236 t.Fatalf("err: %v", err) 237 } 238 if !ok { 239 t.Fatalf("should apply") 240 } 241 242 assertNodeAttributeContains(t, node, "unique.network.ip-address") 243 244 ip := node.Attributes["unique.network.ip-address"] 245 match := net.ParseIP(ip) 246 if match == nil { 247 t.Fatalf("Bad IP match: %s", ip) 248 } 249 250 if node.Resources == nil || len(node.Resources.Networks) == 0 { 251 t.Fatal("Expected to find Network Resources") 252 } 253 254 // Test at least the first Network Resource 255 net := node.Resources.Networks[0] 256 if net.IP == "" { 257 t.Fatal("Expected Network Resource to not be empty") 258 } 259 if net.CIDR == "" { 260 t.Fatal("Expected Network Resource to have a CIDR") 261 } 262 if net.Device == "" { 263 t.Fatal("Expected Network Resource to have a Device Name") 264 } 265 if net.MBits == 0 { 266 t.Fatal("Expected Network Resource to have a non-zero bandwith") 267 } 268 } 269 270 func TestNetworkFingerPrint_excludelo_down_interfaces(t *testing.T) { 271 f := &NetworkFingerprint{logger: testLogger(), interfaceDetector: &NetworkInterfaceDetectorMultipleInterfaces{}} 272 node := &structs.Node{ 273 Attributes: make(map[string]string), 274 } 275 cfg := &config.Config{NetworkSpeed: 100} 276 277 ok, err := f.Fingerprint(cfg, node) 278 if err != nil { 279 t.Fatalf("err: %v", err) 280 } 281 if !ok { 282 t.Fatalf("should apply") 283 } 284 285 assertNodeAttributeContains(t, node, "unique.network.ip-address") 286 287 ip := node.Attributes["unique.network.ip-address"] 288 match := net.ParseIP(ip) 289 if match == nil { 290 t.Fatalf("Bad IP match: %s", ip) 291 } 292 293 if node.Resources == nil || len(node.Resources.Networks) == 0 { 294 t.Fatal("Expected to find Network Resources") 295 } 296 297 // Test at least the first Network Resource 298 net := node.Resources.Networks[0] 299 if net.IP == "" { 300 t.Fatal("Expected Network Resource to have an IP") 301 } 302 if net.CIDR == "" { 303 t.Fatal("Expected Network Resource to have a CIDR") 304 } 305 if net.Device != "eth0" { 306 t.Fatal("Expected Network Resource to be eth0. Actual: ", net.Device) 307 } 308 if net.MBits == 0 { 309 t.Fatal("Expected Network Resource to have a non-zero bandwith") 310 } 311 312 // Test the CIDR of the IPs 313 if node.Resources.Networks[0].CIDR != "100.64.0.0/32" { 314 t.Fatalf("bad CIDR: %v", node.Resources.Networks[0].CIDR) 315 } 316 if node.Resources.Networks[1].CIDR != "2001:db8:85a3::/128" { 317 t.Fatalf("bad CIDR: %v", node.Resources.Networks[1].CIDR) 318 } 319 // Ensure that the link local address isn't fingerprinted 320 if len(node.Resources.Networks) != 2 { 321 t.Fatalf("bad number of IPs %v", len(node.Resources.Networks)) 322 } 323 }