github.com/Ilhicas/nomad@v1.0.4-0.20210304152020-e86851182bc3/nomad/structs/network_test.go (about)

     1  package structs
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  	"reflect"
     7  	"testing"
     8  
     9  	"github.com/stretchr/testify/require"
    10  )
    11  
    12  func TestNetworkIndex_Overcommitted(t *testing.T) {
    13  	t.Skip()
    14  	idx := NewNetworkIndex()
    15  
    16  	// Consume some network
    17  	reserved := &NetworkResource{
    18  		Device:        "eth0",
    19  		IP:            "192.168.0.100",
    20  		MBits:         505,
    21  		ReservedPorts: []Port{{"one", 8000, 0, ""}, {"two", 9000, 0, ""}},
    22  	}
    23  	collide := idx.AddReserved(reserved)
    24  	if collide {
    25  		t.Fatalf("bad")
    26  	}
    27  	if !idx.Overcommitted() {
    28  		t.Fatalf("have no resources")
    29  	}
    30  
    31  	// Add resources
    32  	n := &Node{
    33  		NodeResources: &NodeResources{
    34  			Networks: []*NetworkResource{
    35  				{
    36  					Device: "eth0",
    37  					CIDR:   "192.168.0.100/32",
    38  					MBits:  1000,
    39  				},
    40  			},
    41  		},
    42  	}
    43  	idx.SetNode(n)
    44  	if idx.Overcommitted() {
    45  		t.Fatalf("have resources")
    46  	}
    47  
    48  	// Double up our usage
    49  	idx.AddReserved(reserved)
    50  	if !idx.Overcommitted() {
    51  		t.Fatalf("should be overcommitted")
    52  	}
    53  }
    54  
    55  func TestNetworkIndex_SetNode(t *testing.T) {
    56  	idx := NewNetworkIndex()
    57  	n := &Node{
    58  		NodeResources: &NodeResources{
    59  			Networks: []*NetworkResource{
    60  				{
    61  					Device: "eth0",
    62  					CIDR:   "192.168.0.100/32",
    63  					IP:     "192.168.0.100",
    64  					MBits:  1000,
    65  				},
    66  			},
    67  		},
    68  		ReservedResources: &NodeReservedResources{
    69  			Networks: NodeReservedNetworkResources{
    70  				ReservedHostPorts: "22",
    71  			},
    72  		},
    73  	}
    74  	collide := idx.SetNode(n)
    75  	if collide {
    76  		t.Fatalf("bad")
    77  	}
    78  
    79  	if len(idx.AvailNetworks) != 1 {
    80  		t.Fatalf("Bad")
    81  	}
    82  	if idx.AvailBandwidth["eth0"] != 1000 {
    83  		t.Fatalf("Bad")
    84  	}
    85  	if !idx.UsedPorts["192.168.0.100"].Check(22) {
    86  		t.Fatalf("Bad")
    87  	}
    88  }
    89  
    90  func TestNetworkIndex_AddAllocs(t *testing.T) {
    91  	idx := NewNetworkIndex()
    92  	allocs := []*Allocation{
    93  		{
    94  			AllocatedResources: &AllocatedResources{
    95  				Tasks: map[string]*AllocatedTaskResources{
    96  					"web": {
    97  						Networks: []*NetworkResource{
    98  							{
    99  								Device:        "eth0",
   100  								IP:            "192.168.0.100",
   101  								MBits:         20,
   102  								ReservedPorts: []Port{{"one", 8000, 0, ""}, {"two", 9000, 0, ""}},
   103  							},
   104  						},
   105  					},
   106  				},
   107  			},
   108  		},
   109  		{
   110  			AllocatedResources: &AllocatedResources{
   111  				Tasks: map[string]*AllocatedTaskResources{
   112  					"api": {
   113  						Networks: []*NetworkResource{
   114  							{
   115  								Device:        "eth0",
   116  								IP:            "192.168.0.100",
   117  								MBits:         50,
   118  								ReservedPorts: []Port{{"one", 10000, 0, ""}},
   119  							},
   120  						},
   121  					},
   122  				},
   123  			},
   124  		},
   125  	}
   126  	collide := idx.AddAllocs(allocs)
   127  	if collide {
   128  		t.Fatalf("bad")
   129  	}
   130  
   131  	if idx.UsedBandwidth["eth0"] != 70 {
   132  		t.Fatalf("Bad")
   133  	}
   134  	if !idx.UsedPorts["192.168.0.100"].Check(8000) {
   135  		t.Fatalf("Bad")
   136  	}
   137  	if !idx.UsedPorts["192.168.0.100"].Check(9000) {
   138  		t.Fatalf("Bad")
   139  	}
   140  	if !idx.UsedPorts["192.168.0.100"].Check(10000) {
   141  		t.Fatalf("Bad")
   142  	}
   143  }
   144  
   145  func TestNetworkIndex_AddReserved(t *testing.T) {
   146  	idx := NewNetworkIndex()
   147  
   148  	reserved := &NetworkResource{
   149  		Device:        "eth0",
   150  		IP:            "192.168.0.100",
   151  		MBits:         20,
   152  		ReservedPorts: []Port{{"one", 8000, 0, ""}, {"two", 9000, 0, ""}},
   153  	}
   154  	collide := idx.AddReserved(reserved)
   155  	if collide {
   156  		t.Fatalf("bad")
   157  	}
   158  
   159  	if idx.UsedBandwidth["eth0"] != 20 {
   160  		t.Fatalf("Bad")
   161  	}
   162  	if !idx.UsedPorts["192.168.0.100"].Check(8000) {
   163  		t.Fatalf("Bad")
   164  	}
   165  	if !idx.UsedPorts["192.168.0.100"].Check(9000) {
   166  		t.Fatalf("Bad")
   167  	}
   168  
   169  	// Try to reserve the same network
   170  	collide = idx.AddReserved(reserved)
   171  	if !collide {
   172  		t.Fatalf("bad")
   173  	}
   174  }
   175  
   176  // XXX Reserving ports doesn't work when yielding from a CIDR block. This is
   177  // okay for now since we do not actually fingerprint CIDR blocks.
   178  func TestNetworkIndex_yieldIP(t *testing.T) {
   179  	idx := NewNetworkIndex()
   180  	n := &Node{
   181  		NodeResources: &NodeResources{
   182  			Networks: []*NetworkResource{
   183  				{
   184  					Device: "eth0",
   185  					CIDR:   "192.168.0.100/30",
   186  					MBits:  1000,
   187  				},
   188  			},
   189  		},
   190  	}
   191  	idx.SetNode(n)
   192  
   193  	var out []string
   194  	idx.yieldIP(func(n *NetworkResource, ip net.IP) (stop bool) {
   195  		out = append(out, ip.String())
   196  		return
   197  	})
   198  
   199  	expect := []string{"192.168.0.100", "192.168.0.101",
   200  		"192.168.0.102", "192.168.0.103"}
   201  	if !reflect.DeepEqual(out, expect) {
   202  		t.Fatalf("bad: %v", out)
   203  	}
   204  }
   205  
   206  func TestNetworkIndex_AssignNetwork(t *testing.T) {
   207  	idx := NewNetworkIndex()
   208  	n := &Node{
   209  		NodeResources: &NodeResources{
   210  			Networks: []*NetworkResource{
   211  				{
   212  					Device: "eth0",
   213  					CIDR:   "192.168.0.100/30",
   214  					MBits:  1000,
   215  				},
   216  			},
   217  		},
   218  	}
   219  	idx.SetNode(n)
   220  
   221  	allocs := []*Allocation{
   222  		{
   223  			TaskResources: map[string]*Resources{
   224  				"web": {
   225  					Networks: []*NetworkResource{
   226  						{
   227  							Device:        "eth0",
   228  							IP:            "192.168.0.100",
   229  							MBits:         20,
   230  							ReservedPorts: []Port{{"one", 8000, 0, ""}, {"two", 9000, 0, ""}},
   231  						},
   232  					},
   233  				},
   234  			},
   235  		},
   236  		{
   237  			TaskResources: map[string]*Resources{
   238  				"api": {
   239  					Networks: []*NetworkResource{
   240  						{
   241  							Device:        "eth0",
   242  							IP:            "192.168.0.100",
   243  							MBits:         50,
   244  							ReservedPorts: []Port{{"main", 10000, 0, ""}},
   245  						},
   246  					},
   247  				},
   248  			},
   249  		},
   250  	}
   251  	idx.AddAllocs(allocs)
   252  
   253  	// Ask for a reserved port
   254  	ask := &NetworkResource{
   255  		ReservedPorts: []Port{{"main", 8000, 0, ""}},
   256  	}
   257  	offer, err := idx.AssignNetwork(ask)
   258  	require.NoError(t, err)
   259  	require.NotNil(t, offer)
   260  	require.Equal(t, "192.168.0.101", offer.IP)
   261  	rp := Port{"main", 8000, 0, ""}
   262  	require.Len(t, offer.ReservedPorts, 1)
   263  	require.Exactly(t, rp, offer.ReservedPorts[0])
   264  
   265  	// Ask for dynamic ports
   266  	ask = &NetworkResource{
   267  		DynamicPorts: []Port{{"http", 0, 80, ""}, {"https", 0, 443, ""}, {"admin", 0, -1, ""}},
   268  	}
   269  	offer, err = idx.AssignNetwork(ask)
   270  	require.NoError(t, err)
   271  	require.NotNil(t, offer)
   272  	require.Equal(t, "192.168.0.100", offer.IP)
   273  	require.Len(t, offer.DynamicPorts, 3)
   274  	var adminPort Port
   275  	for _, port := range offer.DynamicPorts {
   276  		require.NotZero(t, port.Value)
   277  		if port.Label == "admin" {
   278  			adminPort = port
   279  		}
   280  	}
   281  	require.Equal(t, adminPort.Value, adminPort.To)
   282  
   283  	// Ask for reserved + dynamic ports
   284  	ask = &NetworkResource{
   285  		ReservedPorts: []Port{{"main", 2345, 0, ""}},
   286  		DynamicPorts:  []Port{{"http", 0, 80, ""}, {"https", 0, 443, ""}, {"admin", 0, 8080, ""}},
   287  	}
   288  	offer, err = idx.AssignNetwork(ask)
   289  	require.NoError(t, err)
   290  	require.NotNil(t, offer)
   291  	require.Equal(t, "192.168.0.100", offer.IP)
   292  
   293  	rp = Port{"main", 2345, 0, ""}
   294  	require.Len(t, offer.ReservedPorts, 1)
   295  	require.Exactly(t, rp, offer.ReservedPorts[0])
   296  
   297  	// Ask for too much bandwidth
   298  	ask = &NetworkResource{
   299  		MBits: 1000,
   300  	}
   301  	offer, err = idx.AssignNetwork(ask)
   302  	require.Error(t, err)
   303  	require.Equal(t, "bandwidth exceeded", err.Error())
   304  	require.Nil(t, offer)
   305  }
   306  
   307  // This test ensures that even with a small domain of available ports we are
   308  // able to make a dynamic port allocation.
   309  func TestNetworkIndex_AssignNetwork_Dynamic_Contention(t *testing.T) {
   310  
   311  	// Create a node that only has one free port
   312  	idx := NewNetworkIndex()
   313  	n := &Node{
   314  		NodeResources: &NodeResources{
   315  			Networks: []*NetworkResource{
   316  				{
   317  					Device: "eth0",
   318  					CIDR:   "192.168.0.100/32",
   319  					IP:     "192.168.0.100",
   320  					MBits:  1000,
   321  				},
   322  			},
   323  		},
   324  		ReservedResources: &NodeReservedResources{
   325  			Networks: NodeReservedNetworkResources{
   326  				ReservedHostPorts: fmt.Sprintf("%d-%d", MinDynamicPort, MaxDynamicPort-1),
   327  			},
   328  		},
   329  	}
   330  	idx.SetNode(n)
   331  
   332  	// Ask for dynamic ports
   333  	ask := &NetworkResource{
   334  		DynamicPorts: []Port{{"http", 0, 80, ""}},
   335  	}
   336  	offer, err := idx.AssignNetwork(ask)
   337  	if err != nil {
   338  		t.Fatalf("err: %v", err)
   339  	}
   340  	if offer == nil {
   341  		t.Fatalf("bad")
   342  	}
   343  	if offer.IP != "192.168.0.100" {
   344  		t.Fatalf("bad: %#v", offer)
   345  	}
   346  	if len(offer.DynamicPorts) != 1 {
   347  		t.Fatalf("There should be one dynamic ports")
   348  	}
   349  	if p := offer.DynamicPorts[0].Value; p != MaxDynamicPort {
   350  		t.Fatalf("Dynamic Port: should have been assigned %d; got %d", p, MaxDynamicPort)
   351  	}
   352  }
   353  
   354  // COMPAT(0.11): Remove in 0.11
   355  func TestNetworkIndex_SetNode_Old(t *testing.T) {
   356  	idx := NewNetworkIndex()
   357  	n := &Node{
   358  		Resources: &Resources{
   359  			Networks: []*NetworkResource{
   360  				{
   361  					Device: "eth0",
   362  					CIDR:   "192.168.0.100/32",
   363  					MBits:  1000,
   364  				},
   365  			},
   366  		},
   367  		Reserved: &Resources{
   368  			Networks: []*NetworkResource{
   369  				{
   370  					Device:        "eth0",
   371  					IP:            "192.168.0.100",
   372  					ReservedPorts: []Port{{"ssh", 22, 0, ""}},
   373  					MBits:         1,
   374  				},
   375  			},
   376  		},
   377  	}
   378  	collide := idx.SetNode(n)
   379  	if collide {
   380  		t.Fatalf("bad")
   381  	}
   382  
   383  	if len(idx.AvailNetworks) != 1 {
   384  		t.Fatalf("Bad")
   385  	}
   386  	if idx.AvailBandwidth["eth0"] != 1000 {
   387  		t.Fatalf("Bad")
   388  	}
   389  	if idx.UsedBandwidth["eth0"] != 1 {
   390  		t.Fatalf("Bad")
   391  	}
   392  	if !idx.UsedPorts["192.168.0.100"].Check(22) {
   393  		t.Fatalf("Bad")
   394  	}
   395  }
   396  
   397  // COMPAT(0.11): Remove in 0.11
   398  func TestNetworkIndex_AddAllocs_Old(t *testing.T) {
   399  	idx := NewNetworkIndex()
   400  	allocs := []*Allocation{
   401  		{
   402  			TaskResources: map[string]*Resources{
   403  				"web": {
   404  					Networks: []*NetworkResource{
   405  						{
   406  							Device:        "eth0",
   407  							IP:            "192.168.0.100",
   408  							MBits:         20,
   409  							ReservedPorts: []Port{{"one", 8000, 0, ""}, {"two", 9000, 0, ""}},
   410  						},
   411  					},
   412  				},
   413  			},
   414  		},
   415  		{
   416  			TaskResources: map[string]*Resources{
   417  				"api": {
   418  					Networks: []*NetworkResource{
   419  						{
   420  							Device:        "eth0",
   421  							IP:            "192.168.0.100",
   422  							MBits:         50,
   423  							ReservedPorts: []Port{{"one", 10000, 0, ""}},
   424  						},
   425  					},
   426  				},
   427  			},
   428  		},
   429  	}
   430  	collide := idx.AddAllocs(allocs)
   431  	if collide {
   432  		t.Fatalf("bad")
   433  	}
   434  
   435  	if idx.UsedBandwidth["eth0"] != 70 {
   436  		t.Fatalf("Bad")
   437  	}
   438  	if !idx.UsedPorts["192.168.0.100"].Check(8000) {
   439  		t.Fatalf("Bad")
   440  	}
   441  	if !idx.UsedPorts["192.168.0.100"].Check(9000) {
   442  		t.Fatalf("Bad")
   443  	}
   444  	if !idx.UsedPorts["192.168.0.100"].Check(10000) {
   445  		t.Fatalf("Bad")
   446  	}
   447  }
   448  
   449  // COMPAT(0.11): Remove in 0.11
   450  func TestNetworkIndex_yieldIP_Old(t *testing.T) {
   451  	idx := NewNetworkIndex()
   452  	n := &Node{
   453  		Resources: &Resources{
   454  			Networks: []*NetworkResource{
   455  				{
   456  					Device: "eth0",
   457  					CIDR:   "192.168.0.100/30",
   458  					MBits:  1000,
   459  				},
   460  			},
   461  		},
   462  		Reserved: &Resources{
   463  			Networks: []*NetworkResource{
   464  				{
   465  					Device:        "eth0",
   466  					IP:            "192.168.0.100",
   467  					ReservedPorts: []Port{{"ssh", 22, 0, ""}},
   468  					MBits:         1,
   469  				},
   470  			},
   471  		},
   472  	}
   473  	idx.SetNode(n)
   474  
   475  	var out []string
   476  	idx.yieldIP(func(n *NetworkResource, ip net.IP) (stop bool) {
   477  		out = append(out, ip.String())
   478  		return
   479  	})
   480  
   481  	expect := []string{"192.168.0.100", "192.168.0.101",
   482  		"192.168.0.102", "192.168.0.103"}
   483  	if !reflect.DeepEqual(out, expect) {
   484  		t.Fatalf("bad: %v", out)
   485  	}
   486  }
   487  
   488  // COMPAT(0.11): Remove in 0.11
   489  func TestNetworkIndex_AssignNetwork_Old(t *testing.T) {
   490  	idx := NewNetworkIndex()
   491  	n := &Node{
   492  		Resources: &Resources{
   493  			Networks: []*NetworkResource{
   494  				{
   495  					Device: "eth0",
   496  					CIDR:   "192.168.0.100/30",
   497  					MBits:  1000,
   498  				},
   499  			},
   500  		},
   501  		Reserved: &Resources{
   502  			Networks: []*NetworkResource{
   503  				{
   504  					Device:        "eth0",
   505  					IP:            "192.168.0.100",
   506  					ReservedPorts: []Port{{"ssh", 22, 0, ""}},
   507  					MBits:         1,
   508  				},
   509  			},
   510  		},
   511  	}
   512  	idx.SetNode(n)
   513  
   514  	allocs := []*Allocation{
   515  		{
   516  			TaskResources: map[string]*Resources{
   517  				"web": {
   518  					Networks: []*NetworkResource{
   519  						{
   520  							Device:        "eth0",
   521  							IP:            "192.168.0.100",
   522  							MBits:         20,
   523  							ReservedPorts: []Port{{"one", 8000, 0, ""}, {"two", 9000, 0, ""}},
   524  						},
   525  					},
   526  				},
   527  			},
   528  		},
   529  		{
   530  			TaskResources: map[string]*Resources{
   531  				"api": {
   532  					Networks: []*NetworkResource{
   533  						{
   534  							Device:        "eth0",
   535  							IP:            "192.168.0.100",
   536  							MBits:         50,
   537  							ReservedPorts: []Port{{"main", 10000, 0, ""}},
   538  						},
   539  					},
   540  				},
   541  			},
   542  		},
   543  	}
   544  	idx.AddAllocs(allocs)
   545  
   546  	// Ask for a reserved port
   547  	ask := &NetworkResource{
   548  		ReservedPorts: []Port{{"main", 8000, 0, ""}},
   549  	}
   550  	offer, err := idx.AssignNetwork(ask)
   551  	if err != nil {
   552  		t.Fatalf("err: %v", err)
   553  	}
   554  	if offer == nil {
   555  		t.Fatalf("bad")
   556  	}
   557  	if offer.IP != "192.168.0.101" {
   558  		t.Fatalf("bad: %#v", offer)
   559  	}
   560  	rp := Port{"main", 8000, 0, ""}
   561  	if len(offer.ReservedPorts) != 1 || offer.ReservedPorts[0] != rp {
   562  		t.Fatalf("bad: %#v", offer)
   563  	}
   564  
   565  	// Ask for dynamic ports
   566  	ask = &NetworkResource{
   567  		DynamicPorts: []Port{{"http", 0, 80, ""}, {"https", 0, 443, ""}, {"admin", 0, 8080, ""}},
   568  	}
   569  	offer, err = idx.AssignNetwork(ask)
   570  	if err != nil {
   571  		t.Fatalf("err: %v", err)
   572  	}
   573  	if offer == nil {
   574  		t.Fatalf("bad")
   575  	}
   576  	if offer.IP != "192.168.0.100" {
   577  		t.Fatalf("bad: %#v", offer)
   578  	}
   579  	if len(offer.DynamicPorts) != 3 {
   580  		t.Fatalf("There should be three dynamic ports")
   581  	}
   582  	for _, port := range offer.DynamicPorts {
   583  		if port.Value == 0 {
   584  			t.Fatalf("Dynamic Port: %v should have been assigned a host port", port.Label)
   585  		}
   586  	}
   587  
   588  	// Ask for reserved + dynamic ports
   589  	ask = &NetworkResource{
   590  		ReservedPorts: []Port{{"main", 2345, 0, ""}},
   591  		DynamicPorts:  []Port{{"http", 0, 80, ""}, {"https", 0, 443, ""}, {"admin", 0, 8080, ""}},
   592  	}
   593  	offer, err = idx.AssignNetwork(ask)
   594  	if err != nil {
   595  		t.Fatalf("err: %v", err)
   596  	}
   597  	if offer == nil {
   598  		t.Fatalf("bad")
   599  	}
   600  	if offer.IP != "192.168.0.100" {
   601  		t.Fatalf("bad: %#v", offer)
   602  	}
   603  
   604  	rp = Port{"main", 2345, 0, ""}
   605  	if len(offer.ReservedPorts) != 1 || offer.ReservedPorts[0] != rp {
   606  		t.Fatalf("bad: %#v", offer)
   607  	}
   608  
   609  	// Ask for too much bandwidth
   610  	ask = &NetworkResource{
   611  		MBits: 1000,
   612  	}
   613  	offer, err = idx.AssignNetwork(ask)
   614  	if err.Error() != "bandwidth exceeded" {
   615  		t.Fatalf("err: %v", err)
   616  	}
   617  	if offer != nil {
   618  		t.Fatalf("bad")
   619  	}
   620  }
   621  
   622  // COMPAT(0.11): Remove in 0.11
   623  // This test ensures that even with a small domain of available ports we are
   624  // able to make a dynamic port allocation.
   625  func TestNetworkIndex_AssignNetwork_Dynamic_Contention_Old(t *testing.T) {
   626  
   627  	// Create a node that only has one free port
   628  	idx := NewNetworkIndex()
   629  	n := &Node{
   630  		Resources: &Resources{
   631  			Networks: []*NetworkResource{
   632  				{
   633  					Device: "eth0",
   634  					CIDR:   "192.168.0.100/32",
   635  					MBits:  1000,
   636  				},
   637  			},
   638  		},
   639  		Reserved: &Resources{
   640  			Networks: []*NetworkResource{
   641  				{
   642  					Device: "eth0",
   643  					IP:     "192.168.0.100",
   644  					MBits:  1,
   645  				},
   646  			},
   647  		},
   648  	}
   649  	for i := MinDynamicPort; i < MaxDynamicPort; i++ {
   650  		n.Reserved.Networks[0].ReservedPorts = append(n.Reserved.Networks[0].ReservedPorts, Port{Value: i})
   651  	}
   652  
   653  	idx.SetNode(n)
   654  
   655  	// Ask for dynamic ports
   656  	ask := &NetworkResource{
   657  		DynamicPorts: []Port{{"http", 0, 80, ""}},
   658  	}
   659  	offer, err := idx.AssignNetwork(ask)
   660  	if err != nil {
   661  		t.Fatalf("err: %v", err)
   662  	}
   663  	if offer == nil {
   664  		t.Fatalf("bad")
   665  	}
   666  	if offer.IP != "192.168.0.100" {
   667  		t.Fatalf("bad: %#v", offer)
   668  	}
   669  	if len(offer.DynamicPorts) != 1 {
   670  		t.Fatalf("There should be three dynamic ports")
   671  	}
   672  	if p := offer.DynamicPorts[0].Value; p != MaxDynamicPort {
   673  		t.Fatalf("Dynamic Port: should have been assigned %d; got %d", p, MaxDynamicPort)
   674  	}
   675  }
   676  
   677  func TestIntContains(t *testing.T) {
   678  	l := []int{1, 2, 10, 20}
   679  	if isPortReserved(l, 50) {
   680  		t.Fatalf("bad")
   681  	}
   682  	if !isPortReserved(l, 20) {
   683  		t.Fatalf("bad")
   684  	}
   685  	if !isPortReserved(l, 1) {
   686  		t.Fatalf("bad")
   687  	}
   688  }