github.com/maier/nomad@v0.4.1-0.20161110003312-a9e3d0b8549d/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("2005:DB6::/48") 130 return []net.Addr{ipnet1, ipnet2}, nil 131 } 132 133 if intf.Name == "eth1" { 134 _, ipnet1, _ := net.ParseCIDR("100.64.0.10/10") 135 _, ipnet2, _ := net.ParseCIDR("2003:DB8::/48") 136 return []net.Addr{ipnet1, ipnet2}, nil 137 } 138 139 if intf.Name == "eth2" { 140 return []net.Addr{}, nil 141 } 142 return nil, fmt.Errorf("Can't find addresses for device: %v", intf.Name) 143 } 144 145 func TestNetworkFingerprint_basic(t *testing.T) { 146 if v := os.Getenv(skipOnlineTestsEnvVar); v != "" { 147 t.Skipf("Environment variable %+q not empty, skipping test", skipOnlineTestsEnvVar) 148 } 149 150 f := &NetworkFingerprint{logger: testLogger(), interfaceDetector: &DefaultNetworkInterfaceDetector{}} 151 node := &structs.Node{ 152 Attributes: make(map[string]string), 153 } 154 cfg := &config.Config{NetworkSpeed: 100} 155 156 ok, err := f.Fingerprint(cfg, node) 157 if err != nil { 158 t.Fatalf("err: %v", err) 159 } 160 if !ok { 161 t.Fatalf("should apply (HINT: working offline? Set env %q=y", skipOnlineTestsEnvVar) 162 } 163 164 assertNodeAttributeContains(t, node, "unique.network.ip-address") 165 166 ip := node.Attributes["unique.network.ip-address"] 167 match := net.ParseIP(ip) 168 if match == nil { 169 t.Fatalf("Bad IP match: %s", ip) 170 } 171 172 if node.Resources == nil || len(node.Resources.Networks) == 0 { 173 t.Fatal("Expected to find Network Resources") 174 } 175 176 // Test at least the first Network Resource 177 net := node.Resources.Networks[0] 178 if net.IP == "" { 179 t.Fatal("Expected Network Resource to not be empty") 180 } 181 if net.CIDR == "" { 182 t.Fatal("Expected Network Resource to have a CIDR") 183 } 184 if net.Device == "" { 185 t.Fatal("Expected Network Resource to have a Device Name") 186 } 187 if net.MBits == 0 { 188 t.Fatal("Expected Network Resource to have a non-zero bandwith") 189 } 190 } 191 192 func TestNetworkFingerprint_no_devices(t *testing.T) { 193 f := &NetworkFingerprint{logger: testLogger(), interfaceDetector: &NetworkIntefaceDetectorNoDevices{}} 194 node := &structs.Node{ 195 Attributes: make(map[string]string), 196 } 197 cfg := &config.Config{NetworkSpeed: 100} 198 199 ok, err := f.Fingerprint(cfg, node) 200 if err != nil { 201 t.Fatalf("err: %v", err) 202 } 203 204 if ok { 205 t.Fatalf("ok: %v", ok) 206 } 207 } 208 209 func TestNetworkFingerprint_default_device_absent(t *testing.T) { 210 f := &NetworkFingerprint{logger: testLogger(), interfaceDetector: &NetworkInterfaceDetectorOnlyLo{}} 211 node := &structs.Node{ 212 Attributes: make(map[string]string), 213 } 214 cfg := &config.Config{NetworkSpeed: 100, NetworkInterface: "eth0"} 215 216 ok, err := f.Fingerprint(cfg, node) 217 if err == nil { 218 t.Fatalf("err: %v", err) 219 } 220 221 if ok { 222 t.Fatalf("ok: %v", ok) 223 } 224 } 225 226 func TestNetworkFingerPrint_default_device(t *testing.T) { 227 f := &NetworkFingerprint{logger: testLogger(), interfaceDetector: &NetworkInterfaceDetectorOnlyLo{}} 228 node := &structs.Node{ 229 Attributes: make(map[string]string), 230 } 231 cfg := &config.Config{NetworkSpeed: 100, NetworkInterface: "lo"} 232 233 ok, err := f.Fingerprint(cfg, node) 234 if err != nil { 235 t.Fatalf("err: %v", err) 236 } 237 if !ok { 238 t.Fatalf("should apply") 239 } 240 241 assertNodeAttributeContains(t, node, "unique.network.ip-address") 242 243 ip := node.Attributes["unique.network.ip-address"] 244 match := net.ParseIP(ip) 245 if match == nil { 246 t.Fatalf("Bad IP match: %s", ip) 247 } 248 249 if node.Resources == nil || len(node.Resources.Networks) == 0 { 250 t.Fatal("Expected to find Network Resources") 251 } 252 253 // Test at least the first Network Resource 254 net := node.Resources.Networks[0] 255 if net.IP == "" { 256 t.Fatal("Expected Network Resource to not be empty") 257 } 258 if net.CIDR == "" { 259 t.Fatal("Expected Network Resource to have a CIDR") 260 } 261 if net.Device == "" { 262 t.Fatal("Expected Network Resource to have a Device Name") 263 } 264 if net.MBits == 0 { 265 t.Fatal("Expected Network Resource to have a non-zero bandwith") 266 } 267 } 268 269 func TestNetworkFingerPrint_excludelo_down_interfaces(t *testing.T) { 270 f := &NetworkFingerprint{logger: testLogger(), interfaceDetector: &NetworkInterfaceDetectorMultipleInterfaces{}} 271 node := &structs.Node{ 272 Attributes: make(map[string]string), 273 } 274 cfg := &config.Config{NetworkSpeed: 100} 275 276 ok, err := f.Fingerprint(cfg, node) 277 if err != nil { 278 t.Fatalf("err: %v", err) 279 } 280 if !ok { 281 t.Fatalf("should apply") 282 } 283 284 assertNodeAttributeContains(t, node, "unique.network.ip-address") 285 286 ip := node.Attributes["unique.network.ip-address"] 287 match := net.ParseIP(ip) 288 if match == nil { 289 t.Fatalf("Bad IP match: %s", ip) 290 } 291 292 if node.Resources == nil || len(node.Resources.Networks) == 0 { 293 t.Fatal("Expected to find Network Resources") 294 } 295 296 // Test at least the first Network Resource 297 net := node.Resources.Networks[0] 298 if net.IP == "" { 299 t.Fatal("Expected Network Resource to have an IP") 300 } 301 if net.CIDR == "" { 302 t.Fatal("Expected Network Resource to have a CIDR") 303 } 304 if net.Device != "eth0" { 305 t.Fatal("Expected Network Resource to be eth0. Actual: ", net.Device) 306 } 307 if net.MBits == 0 { 308 t.Fatal("Expected Network Resource to have a non-zero bandwith") 309 } 310 }