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 = &eth0
   108  	case "eth1":
   109  		intf = &eth1
   110  	case "eth2":
   111  		intf = &eth2
   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  }