github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/nomad/structs/network_test.go (about)

     1  package structs
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  	"reflect"
     7  	"testing"
     8  
     9  	"github.com/hashicorp/nomad/ci"
    10  	"github.com/stretchr/testify/assert"
    11  	"github.com/stretchr/testify/require"
    12  )
    13  
    14  func TestNetworkIndex_Copy(t *testing.T) {
    15  	ci.Parallel(t)
    16  
    17  	n := &Node{
    18  		NodeResources: &NodeResources{
    19  			Networks: []*NetworkResource{
    20  				{
    21  					Device: "eth0",
    22  					CIDR:   "192.168.0.100/32",
    23  					IP:     "192.168.0.100",
    24  					MBits:  1000,
    25  				},
    26  			},
    27  			NodeNetworks: []*NodeNetworkResource{
    28  				{
    29  					Mode:   "host",
    30  					Device: "eth0",
    31  					Speed:  1000,
    32  					Addresses: []NodeNetworkAddress{
    33  						{
    34  							Alias:   "default",
    35  							Address: "192.168.0.100",
    36  							Family:  NodeNetworkAF_IPv4,
    37  						},
    38  					},
    39  				},
    40  			},
    41  		},
    42  		Reserved: &Resources{
    43  			Networks: []*NetworkResource{
    44  				{
    45  					Device:        "eth0",
    46  					IP:            "192.168.0.100",
    47  					ReservedPorts: []Port{{Label: "ssh", Value: 22}},
    48  					MBits:         1,
    49  				},
    50  			},
    51  		},
    52  		ReservedResources: &NodeReservedResources{
    53  			Networks: NodeReservedNetworkResources{
    54  				ReservedHostPorts: "22",
    55  			},
    56  		},
    57  	}
    58  
    59  	allocs := []*Allocation{
    60  		{
    61  			AllocatedResources: &AllocatedResources{
    62  				Tasks: map[string]*AllocatedTaskResources{
    63  					"web": {
    64  						Networks: []*NetworkResource{
    65  							{
    66  								Device:        "eth0",
    67  								IP:            "192.168.0.100",
    68  								MBits:         20,
    69  								ReservedPorts: []Port{{"one", 8000, 0, ""}, {"two", 9000, 0, ""}},
    70  							},
    71  						},
    72  					},
    73  				},
    74  			},
    75  		},
    76  		{
    77  			AllocatedResources: &AllocatedResources{
    78  				Tasks: map[string]*AllocatedTaskResources{
    79  					"api": {
    80  						Networks: []*NetworkResource{
    81  							{
    82  								Device:        "eth0",
    83  								IP:            "192.168.0.100",
    84  								MBits:         50,
    85  								ReservedPorts: []Port{{"one", 10000, 0, ""}},
    86  							},
    87  						},
    88  					},
    89  				},
    90  			},
    91  		},
    92  	}
    93  
    94  	netIdx := NewNetworkIndex()
    95  	netIdx.SetNode(n)
    96  	netIdx.AddAllocs(allocs)
    97  
    98  	// Copy must be equal.
    99  	netIdxCopy := netIdx.Copy()
   100  	require.Equal(t, netIdx, netIdxCopy)
   101  
   102  	// Modifying copy should not affect original value.
   103  	n.NodeResources.Networks[0].Device = "eth1"
   104  	n.ReservedResources.Networks.ReservedHostPorts = "22,80"
   105  	allocs = append(allocs, &Allocation{
   106  		AllocatedResources: &AllocatedResources{
   107  			Tasks: map[string]*AllocatedTaskResources{
   108  				"db": {
   109  					Networks: []*NetworkResource{
   110  						{
   111  							Device:        "eth1",
   112  							IP:            "192.168.0.104",
   113  							MBits:         50,
   114  							ReservedPorts: []Port{{"one", 4567, 0, ""}},
   115  						},
   116  					},
   117  				},
   118  			},
   119  		},
   120  	})
   121  	netIdxCopy.SetNode(n)
   122  	netIdxCopy.AddAllocs(allocs)
   123  	netIdxCopy.MinDynamicPort = 1000
   124  	netIdxCopy.MaxDynamicPort = 2000
   125  	require.NotEqual(t, netIdx, netIdxCopy)
   126  }
   127  
   128  func TestNetworkIndex_Overcommitted(t *testing.T) {
   129  	t.Skip()
   130  	ci.Parallel(t)
   131  	idx := NewNetworkIndex()
   132  
   133  	// Consume some network
   134  	reserved := &NetworkResource{
   135  		Device:        "eth0",
   136  		IP:            "192.168.0.100",
   137  		MBits:         505,
   138  		ReservedPorts: []Port{{"one", 8000, 0, ""}, {"two", 9000, 0, ""}},
   139  	}
   140  	collide, reasons := idx.AddReserved(reserved)
   141  	if collide || len(reasons) != 0 {
   142  		t.Fatalf("bad")
   143  	}
   144  	if !idx.Overcommitted() {
   145  		t.Fatalf("have no resources")
   146  	}
   147  
   148  	// Add resources
   149  	n := &Node{
   150  		NodeResources: &NodeResources{
   151  			Networks: []*NetworkResource{
   152  				{
   153  					Device: "eth0",
   154  					CIDR:   "192.168.0.100/32",
   155  					MBits:  1000,
   156  				},
   157  			},
   158  		},
   159  	}
   160  	idx.SetNode(n)
   161  	if idx.Overcommitted() {
   162  		t.Fatalf("have resources")
   163  	}
   164  
   165  	// Double up our usage
   166  	idx.AddReserved(reserved)
   167  	if !idx.Overcommitted() {
   168  		t.Fatalf("should be overcommitted")
   169  	}
   170  }
   171  
   172  func TestNetworkIndex_SetNode(t *testing.T) {
   173  	ci.Parallel(t)
   174  
   175  	idx := NewNetworkIndex()
   176  	n := &Node{
   177  		NodeResources: &NodeResources{
   178  			Networks: []*NetworkResource{
   179  				{
   180  					Device: "eth0",
   181  					CIDR:   "192.168.0.100/32",
   182  					IP:     "192.168.0.100",
   183  					MBits:  1000,
   184  				},
   185  			},
   186  		},
   187  		ReservedResources: &NodeReservedResources{
   188  			Networks: NodeReservedNetworkResources{
   189  				ReservedHostPorts: "22",
   190  			},
   191  		},
   192  	}
   193  	require.NoError(t, idx.SetNode(n))
   194  	require.Len(t, idx.TaskNetworks, 1)
   195  	require.Equal(t, 1000, idx.AvailBandwidth["eth0"])
   196  	require.True(t, idx.UsedPorts["192.168.0.100"].Check(22))
   197  }
   198  
   199  func TestNetworkIndex_AddAllocs(t *testing.T) {
   200  	ci.Parallel(t)
   201  
   202  	idx := NewNetworkIndex()
   203  	allocs := []*Allocation{
   204  		{
   205  			ClientStatus:  AllocClientStatusRunning,
   206  			DesiredStatus: AllocDesiredStatusRun,
   207  			AllocatedResources: &AllocatedResources{
   208  				Tasks: map[string]*AllocatedTaskResources{
   209  					"web": {
   210  						Networks: []*NetworkResource{
   211  							{
   212  								Device:        "eth0",
   213  								IP:            "192.168.0.100",
   214  								MBits:         20,
   215  								ReservedPorts: []Port{{"one", 8000, 0, ""}, {"two", 9000, 0, ""}},
   216  							},
   217  						},
   218  					},
   219  				},
   220  			},
   221  		},
   222  		{
   223  			ClientStatus:  AllocClientStatusRunning,
   224  			DesiredStatus: AllocDesiredStatusRun,
   225  			AllocatedResources: &AllocatedResources{
   226  				Tasks: map[string]*AllocatedTaskResources{
   227  					"api": {
   228  						Networks: []*NetworkResource{
   229  							{
   230  								Device:        "eth0",
   231  								IP:            "192.168.0.100",
   232  								MBits:         50,
   233  								ReservedPorts: []Port{{"one", 10000, 0, ""}},
   234  							},
   235  						},
   236  					},
   237  				},
   238  			},
   239  		},
   240  		{
   241  			// Allocations running on clients should have their
   242  			// ports counted even if their DesiredStatus=stop
   243  			ClientStatus:  AllocClientStatusRunning,
   244  			DesiredStatus: AllocDesiredStatusStop,
   245  			AllocatedResources: &AllocatedResources{
   246  				Tasks: map[string]*AllocatedTaskResources{
   247  					"api": {
   248  						Networks: []*NetworkResource{
   249  							{
   250  								Device:        "eth0",
   251  								IP:            "192.168.0.100",
   252  								MBits:         50,
   253  								ReservedPorts: []Port{{"one", 10001, 0, ""}},
   254  							},
   255  						},
   256  					},
   257  				},
   258  			},
   259  		},
   260  		{
   261  			// Allocations *not* running on clients should *not*
   262  			// have their ports counted even if their
   263  			// DesiredStatus=run
   264  			ClientStatus:  AllocClientStatusFailed,
   265  			DesiredStatus: AllocDesiredStatusRun,
   266  			AllocatedResources: &AllocatedResources{
   267  				Tasks: map[string]*AllocatedTaskResources{
   268  					"api": {
   269  						Networks: []*NetworkResource{
   270  							{
   271  								Device:        "eth0",
   272  								IP:            "192.168.0.100",
   273  								MBits:         50,
   274  								ReservedPorts: []Port{{"one", 10001, 0, ""}},
   275  							},
   276  						},
   277  					},
   278  				},
   279  			},
   280  		},
   281  	}
   282  	collide, reason := idx.AddAllocs(allocs)
   283  	assert.False(t, collide)
   284  	assert.Empty(t, reason)
   285  
   286  	assert.True(t, idx.UsedPorts["192.168.0.100"].Check(8000))
   287  	assert.True(t, idx.UsedPorts["192.168.0.100"].Check(9000))
   288  	assert.True(t, idx.UsedPorts["192.168.0.100"].Check(10000))
   289  	assert.True(t, idx.UsedPorts["192.168.0.100"].Check(10001))
   290  }
   291  
   292  func TestNetworkIndex_AddReserved(t *testing.T) {
   293  	ci.Parallel(t)
   294  
   295  	idx := NewNetworkIndex()
   296  
   297  	reserved := &NetworkResource{
   298  		Device:        "eth0",
   299  		IP:            "192.168.0.100",
   300  		MBits:         20,
   301  		ReservedPorts: []Port{{"one", 8000, 0, ""}, {"two", 9000, 0, ""}},
   302  	}
   303  	collide, reasons := idx.AddReserved(reserved)
   304  	if collide || len(reasons) > 0 {
   305  		t.Fatalf("bad")
   306  	}
   307  
   308  	if idx.UsedBandwidth["eth0"] != 20 {
   309  		t.Fatalf("Bad")
   310  	}
   311  	if !idx.UsedPorts["192.168.0.100"].Check(8000) {
   312  		t.Fatalf("Bad")
   313  	}
   314  	if !idx.UsedPorts["192.168.0.100"].Check(9000) {
   315  		t.Fatalf("Bad")
   316  	}
   317  
   318  	// Try to reserve the same network
   319  	collide, reasons = idx.AddReserved(reserved)
   320  	if !collide || len(reasons) == 0 {
   321  		t.Fatalf("bad")
   322  	}
   323  }
   324  
   325  // XXX Reserving ports doesn't work when yielding from a CIDR block. This is
   326  // okay for now since we do not actually fingerprint CIDR blocks.
   327  func TestNetworkIndex_yieldIP(t *testing.T) {
   328  	ci.Parallel(t)
   329  
   330  	idx := NewNetworkIndex()
   331  	n := &Node{
   332  		NodeResources: &NodeResources{
   333  			Networks: []*NetworkResource{
   334  				{
   335  					Device: "eth0",
   336  					CIDR:   "192.168.0.100/30",
   337  					MBits:  1000,
   338  				},
   339  			},
   340  		},
   341  	}
   342  	idx.SetNode(n)
   343  
   344  	var out []string
   345  	idx.yieldIP(func(n *NetworkResource, ip net.IP) (stop bool) {
   346  		out = append(out, ip.String())
   347  		return
   348  	})
   349  
   350  	expect := []string{"192.168.0.100", "192.168.0.101",
   351  		"192.168.0.102", "192.168.0.103"}
   352  	if !reflect.DeepEqual(out, expect) {
   353  		t.Fatalf("bad: %v", out)
   354  	}
   355  }
   356  
   357  func TestNetworkIndex_AssignTaskNetwork(t *testing.T) {
   358  	ci.Parallel(t)
   359  	idx := NewNetworkIndex()
   360  	n := &Node{
   361  		NodeResources: &NodeResources{
   362  			Networks: []*NetworkResource{
   363  				{
   364  					Device: "eth0",
   365  					CIDR:   "192.168.0.100/30",
   366  					MBits:  1000,
   367  				},
   368  			},
   369  		},
   370  	}
   371  	idx.SetNode(n)
   372  
   373  	allocs := []*Allocation{
   374  		{
   375  			TaskResources: map[string]*Resources{
   376  				"web": {
   377  					Networks: []*NetworkResource{
   378  						{
   379  							Device:        "eth0",
   380  							IP:            "192.168.0.100",
   381  							MBits:         20,
   382  							ReservedPorts: []Port{{"one", 8000, 0, ""}, {"two", 9000, 0, ""}},
   383  						},
   384  					},
   385  				},
   386  			},
   387  		},
   388  		{
   389  			TaskResources: map[string]*Resources{
   390  				"api": {
   391  					Networks: []*NetworkResource{
   392  						{
   393  							Device:        "eth0",
   394  							IP:            "192.168.0.100",
   395  							MBits:         50,
   396  							ReservedPorts: []Port{{"main", 10000, 0, ""}},
   397  						},
   398  					},
   399  				},
   400  			},
   401  		},
   402  	}
   403  	idx.AddAllocs(allocs)
   404  
   405  	// Ask for a reserved port
   406  	ask := &NetworkResource{
   407  		ReservedPorts: []Port{{"main", 8000, 0, ""}},
   408  	}
   409  	offer, err := idx.AssignTaskNetwork(ask)
   410  	require.NoError(t, err)
   411  	require.NotNil(t, offer)
   412  	require.Equal(t, "192.168.0.101", offer.IP)
   413  	rp := Port{"main", 8000, 0, ""}
   414  	require.Len(t, offer.ReservedPorts, 1)
   415  	require.Exactly(t, rp, offer.ReservedPorts[0])
   416  
   417  	// Ask for dynamic ports
   418  	ask = &NetworkResource{
   419  		DynamicPorts: []Port{{"http", 0, 80, ""}, {"https", 0, 443, ""}, {"admin", 0, -1, ""}},
   420  	}
   421  	offer, err = idx.AssignTaskNetwork(ask)
   422  	require.NoError(t, err)
   423  	require.NotNil(t, offer)
   424  	require.Equal(t, "192.168.0.100", offer.IP)
   425  	require.Len(t, offer.DynamicPorts, 3)
   426  	var adminPort Port
   427  	for _, port := range offer.DynamicPorts {
   428  		require.NotZero(t, port.Value)
   429  		if port.Label == "admin" {
   430  			adminPort = port
   431  		}
   432  	}
   433  	require.Equal(t, adminPort.Value, adminPort.To)
   434  
   435  	// Ask for reserved + dynamic ports
   436  	ask = &NetworkResource{
   437  		ReservedPorts: []Port{{"main", 2345, 0, ""}},
   438  		DynamicPorts:  []Port{{"http", 0, 80, ""}, {"https", 0, 443, ""}, {"admin", 0, 8080, ""}},
   439  	}
   440  	offer, err = idx.AssignTaskNetwork(ask)
   441  	require.NoError(t, err)
   442  	require.NotNil(t, offer)
   443  	require.Equal(t, "192.168.0.100", offer.IP)
   444  
   445  	rp = Port{"main", 2345, 0, ""}
   446  	require.Len(t, offer.ReservedPorts, 1)
   447  	require.Exactly(t, rp, offer.ReservedPorts[0])
   448  
   449  	// Ask for too much bandwidth
   450  	ask = &NetworkResource{
   451  		MBits: 1000,
   452  	}
   453  	offer, err = idx.AssignTaskNetwork(ask)
   454  	require.Error(t, err)
   455  	require.Equal(t, "bandwidth exceeded", err.Error())
   456  	require.Nil(t, offer)
   457  }
   458  
   459  // This test ensures that even with a small domain of available ports we are
   460  // able to make a dynamic port allocation.
   461  func TestNetworkIndex_AssignTaskNetwork_Dynamic_Contention(t *testing.T) {
   462  	ci.Parallel(t)
   463  
   464  	// Create a node that only has one free port
   465  	idx := NewNetworkIndex()
   466  	n := &Node{
   467  		NodeResources: &NodeResources{
   468  			Networks: []*NetworkResource{
   469  				{
   470  					Device: "eth0",
   471  					CIDR:   "192.168.0.100/32",
   472  					IP:     "192.168.0.100",
   473  					MBits:  1000,
   474  				},
   475  			},
   476  		},
   477  		ReservedResources: &NodeReservedResources{
   478  			Networks: NodeReservedNetworkResources{
   479  				ReservedHostPorts: fmt.Sprintf("%d-%d", idx.MinDynamicPort, idx.MaxDynamicPort-1),
   480  			},
   481  		},
   482  	}
   483  	idx.SetNode(n)
   484  
   485  	// Ask for dynamic ports
   486  	ask := &NetworkResource{
   487  		DynamicPorts: []Port{{"http", 0, 80, ""}},
   488  	}
   489  	offer, err := idx.AssignTaskNetwork(ask)
   490  	if err != nil {
   491  		t.Fatalf("err: %v", err)
   492  	}
   493  	if offer == nil {
   494  		t.Fatalf("bad")
   495  	}
   496  	if offer.IP != "192.168.0.100" {
   497  		t.Fatalf("bad: %#v", offer)
   498  	}
   499  	if len(offer.DynamicPorts) != 1 {
   500  		t.Fatalf("There should be one dynamic ports")
   501  	}
   502  	if p := offer.DynamicPorts[0].Value; p != idx.MaxDynamicPort {
   503  		t.Fatalf("Dynamic Port: should have been assigned %d; got %d", p, idx.MaxDynamicPort)
   504  	}
   505  }
   506  
   507  // COMPAT(0.11): Remove in 0.11
   508  func TestNetworkIndex_SetNode_Old(t *testing.T) {
   509  	ci.Parallel(t)
   510  
   511  	idx := NewNetworkIndex()
   512  	n := &Node{
   513  		Resources: &Resources{
   514  			Networks: []*NetworkResource{
   515  				{
   516  					Device: "eth0",
   517  					CIDR:   "192.168.0.100/32",
   518  					MBits:  1000,
   519  				},
   520  			},
   521  		},
   522  		Reserved: &Resources{
   523  			Networks: []*NetworkResource{
   524  				{
   525  					Device:        "eth0",
   526  					IP:            "192.168.0.100",
   527  					ReservedPorts: []Port{{"ssh", 22, 0, ""}},
   528  					MBits:         1,
   529  				},
   530  			},
   531  		},
   532  	}
   533  	require.NoError(t, idx.SetNode(n))
   534  	require.Len(t, idx.TaskNetworks, 1)
   535  	require.Equal(t, 1000, idx.AvailBandwidth["eth0"])
   536  	require.Equal(t, 1, idx.UsedBandwidth["eth0"])
   537  	require.True(t, idx.UsedPorts["192.168.0.100"].Check(22))
   538  }
   539  
   540  // COMPAT(0.11): Remove in 0.11
   541  func TestNetworkIndex_AddAllocs_Old(t *testing.T) {
   542  	ci.Parallel(t)
   543  
   544  	idx := NewNetworkIndex()
   545  	allocs := []*Allocation{
   546  		{
   547  			TaskResources: map[string]*Resources{
   548  				"web": {
   549  					Networks: []*NetworkResource{
   550  						{
   551  							Device:        "eth0",
   552  							IP:            "192.168.0.100",
   553  							MBits:         20,
   554  							ReservedPorts: []Port{{"one", 8000, 0, ""}, {"two", 9000, 0, ""}},
   555  						},
   556  					},
   557  				},
   558  			},
   559  		},
   560  		{
   561  			TaskResources: map[string]*Resources{
   562  				"api": {
   563  					Networks: []*NetworkResource{
   564  						{
   565  							Device:        "eth0",
   566  							IP:            "192.168.0.100",
   567  							MBits:         50,
   568  							ReservedPorts: []Port{{"one", 10000, 0, ""}},
   569  						},
   570  					},
   571  				},
   572  			},
   573  		},
   574  	}
   575  	collide, reason := idx.AddAllocs(allocs)
   576  	if collide || reason != "" {
   577  		t.Fatalf("bad")
   578  	}
   579  
   580  	if idx.UsedBandwidth["eth0"] != 70 {
   581  		t.Fatalf("Bad")
   582  	}
   583  	if !idx.UsedPorts["192.168.0.100"].Check(8000) {
   584  		t.Fatalf("Bad")
   585  	}
   586  	if !idx.UsedPorts["192.168.0.100"].Check(9000) {
   587  		t.Fatalf("Bad")
   588  	}
   589  	if !idx.UsedPorts["192.168.0.100"].Check(10000) {
   590  		t.Fatalf("Bad")
   591  	}
   592  }
   593  
   594  // COMPAT(0.11): Remove in 0.11
   595  func TestNetworkIndex_yieldIP_Old(t *testing.T) {
   596  	ci.Parallel(t)
   597  
   598  	idx := NewNetworkIndex()
   599  	n := &Node{
   600  		Resources: &Resources{
   601  			Networks: []*NetworkResource{
   602  				{
   603  					Device: "eth0",
   604  					CIDR:   "192.168.0.100/30",
   605  					MBits:  1000,
   606  				},
   607  			},
   608  		},
   609  		Reserved: &Resources{
   610  			Networks: []*NetworkResource{
   611  				{
   612  					Device:        "eth0",
   613  					IP:            "192.168.0.100",
   614  					ReservedPorts: []Port{{"ssh", 22, 0, ""}},
   615  					MBits:         1,
   616  				},
   617  			},
   618  		},
   619  	}
   620  	idx.SetNode(n)
   621  
   622  	var out []string
   623  	idx.yieldIP(func(n *NetworkResource, ip net.IP) (stop bool) {
   624  		out = append(out, ip.String())
   625  		return
   626  	})
   627  
   628  	expect := []string{"192.168.0.100", "192.168.0.101",
   629  		"192.168.0.102", "192.168.0.103"}
   630  	if !reflect.DeepEqual(out, expect) {
   631  		t.Fatalf("bad: %v", out)
   632  	}
   633  }
   634  
   635  // COMPAT(0.11): Remove in 0.11
   636  func TestNetworkIndex_AssignTaskNetwork_Old(t *testing.T) {
   637  	ci.Parallel(t)
   638  
   639  	idx := NewNetworkIndex()
   640  	n := &Node{
   641  		Resources: &Resources{
   642  			Networks: []*NetworkResource{
   643  				{
   644  					Device: "eth0",
   645  					CIDR:   "192.168.0.100/30",
   646  					MBits:  1000,
   647  				},
   648  			},
   649  		},
   650  		Reserved: &Resources{
   651  			Networks: []*NetworkResource{
   652  				{
   653  					Device:        "eth0",
   654  					IP:            "192.168.0.100",
   655  					ReservedPorts: []Port{{"ssh", 22, 0, ""}},
   656  					MBits:         1,
   657  				},
   658  			},
   659  		},
   660  	}
   661  	idx.SetNode(n)
   662  
   663  	allocs := []*Allocation{
   664  		{
   665  			TaskResources: map[string]*Resources{
   666  				"web": {
   667  					Networks: []*NetworkResource{
   668  						{
   669  							Device:        "eth0",
   670  							IP:            "192.168.0.100",
   671  							MBits:         20,
   672  							ReservedPorts: []Port{{"one", 8000, 0, ""}, {"two", 9000, 0, ""}},
   673  						},
   674  					},
   675  				},
   676  			},
   677  		},
   678  		{
   679  			TaskResources: map[string]*Resources{
   680  				"api": {
   681  					Networks: []*NetworkResource{
   682  						{
   683  							Device:        "eth0",
   684  							IP:            "192.168.0.100",
   685  							MBits:         50,
   686  							ReservedPorts: []Port{{"main", 10000, 0, ""}},
   687  						},
   688  					},
   689  				},
   690  			},
   691  		},
   692  	}
   693  	idx.AddAllocs(allocs)
   694  
   695  	// Ask for a reserved port
   696  	ask := &NetworkResource{
   697  		ReservedPorts: []Port{{"main", 8000, 0, ""}},
   698  	}
   699  	offer, err := idx.AssignTaskNetwork(ask)
   700  	if err != nil {
   701  		t.Fatalf("err: %v", err)
   702  	}
   703  	if offer == nil {
   704  		t.Fatalf("bad")
   705  	}
   706  	if offer.IP != "192.168.0.101" {
   707  		t.Fatalf("bad: %#v", offer)
   708  	}
   709  	rp := Port{"main", 8000, 0, ""}
   710  	if len(offer.ReservedPorts) != 1 || offer.ReservedPorts[0] != rp {
   711  		t.Fatalf("bad: %#v", offer)
   712  	}
   713  
   714  	// Ask for dynamic ports
   715  	ask = &NetworkResource{
   716  		DynamicPorts: []Port{{"http", 0, 80, ""}, {"https", 0, 443, ""}, {"admin", 0, 8080, ""}},
   717  	}
   718  	offer, err = idx.AssignTaskNetwork(ask)
   719  	if err != nil {
   720  		t.Fatalf("err: %v", err)
   721  	}
   722  	if offer == nil {
   723  		t.Fatalf("bad")
   724  	}
   725  	if offer.IP != "192.168.0.100" {
   726  		t.Fatalf("bad: %#v", offer)
   727  	}
   728  	if len(offer.DynamicPorts) != 3 {
   729  		t.Fatalf("There should be three dynamic ports")
   730  	}
   731  	for _, port := range offer.DynamicPorts {
   732  		if port.Value == 0 {
   733  			t.Fatalf("Dynamic Port: %v should have been assigned a host port", port.Label)
   734  		}
   735  	}
   736  
   737  	// Ask for reserved + dynamic ports
   738  	ask = &NetworkResource{
   739  		ReservedPorts: []Port{{"main", 2345, 0, ""}},
   740  		DynamicPorts:  []Port{{"http", 0, 80, ""}, {"https", 0, 443, ""}, {"admin", 0, 8080, ""}},
   741  	}
   742  	offer, err = idx.AssignTaskNetwork(ask)
   743  	if err != nil {
   744  		t.Fatalf("err: %v", err)
   745  	}
   746  	if offer == nil {
   747  		t.Fatalf("bad")
   748  	}
   749  	if offer.IP != "192.168.0.100" {
   750  		t.Fatalf("bad: %#v", offer)
   751  	}
   752  
   753  	rp = Port{"main", 2345, 0, ""}
   754  	if len(offer.ReservedPorts) != 1 || offer.ReservedPorts[0] != rp {
   755  		t.Fatalf("bad: %#v", offer)
   756  	}
   757  
   758  	// Ask for too much bandwidth
   759  	ask = &NetworkResource{
   760  		MBits: 1000,
   761  	}
   762  	offer, err = idx.AssignTaskNetwork(ask)
   763  	if err.Error() != "bandwidth exceeded" {
   764  		t.Fatalf("err: %v", err)
   765  	}
   766  	if offer != nil {
   767  		t.Fatalf("bad")
   768  	}
   769  }
   770  
   771  // COMPAT(0.11): Remove in 0.11
   772  // This test ensures that even with a small domain of available ports we are
   773  // able to make a dynamic port allocation.
   774  func TestNetworkIndex_AssignTaskNetwork_Dynamic_Contention_Old(t *testing.T) {
   775  	ci.Parallel(t)
   776  
   777  	// Create a node that only has one free port
   778  	idx := NewNetworkIndex()
   779  	n := &Node{
   780  		Resources: &Resources{
   781  			Networks: []*NetworkResource{
   782  				{
   783  					Device: "eth0",
   784  					CIDR:   "192.168.0.100/32",
   785  					MBits:  1000,
   786  				},
   787  			},
   788  		},
   789  		Reserved: &Resources{
   790  			Networks: []*NetworkResource{
   791  				{
   792  					Device: "eth0",
   793  					IP:     "192.168.0.100",
   794  					MBits:  1,
   795  				},
   796  			},
   797  		},
   798  	}
   799  	for i := idx.MinDynamicPort; i < idx.MaxDynamicPort; i++ {
   800  		n.Reserved.Networks[0].ReservedPorts = append(n.Reserved.Networks[0].ReservedPorts, Port{Value: i})
   801  	}
   802  
   803  	idx.SetNode(n)
   804  
   805  	// Ask for dynamic ports
   806  	ask := &NetworkResource{
   807  		DynamicPorts: []Port{{"http", 0, 80, ""}},
   808  	}
   809  	offer, err := idx.AssignTaskNetwork(ask)
   810  	if err != nil {
   811  		t.Fatalf("err: %v", err)
   812  	}
   813  	if offer == nil {
   814  		t.Fatalf("bad")
   815  	}
   816  	if offer.IP != "192.168.0.100" {
   817  		t.Fatalf("bad: %#v", offer)
   818  	}
   819  	if len(offer.DynamicPorts) != 1 {
   820  		t.Fatalf("There should be three dynamic ports")
   821  	}
   822  	if p := offer.DynamicPorts[0].Value; p != idx.MaxDynamicPort {
   823  		t.Fatalf("Dynamic Port: should have been assigned %d; got %d", p, idx.MaxDynamicPort)
   824  	}
   825  }
   826  
   827  func TestIntContains(t *testing.T) {
   828  	ci.Parallel(t)
   829  
   830  	l := []int{1, 2, 10, 20}
   831  	if isPortReserved(l, 50) {
   832  		t.Fatalf("bad")
   833  	}
   834  	if !isPortReserved(l, 20) {
   835  		t.Fatalf("bad")
   836  	}
   837  	if !isPortReserved(l, 1) {
   838  		t.Fatalf("bad")
   839  	}
   840  }
   841  
   842  func TestNetworkIndex_SetNode_HostNets(t *testing.T) {
   843  	ci.Parallel(t)
   844  
   845  	idx := NewNetworkIndex()
   846  	n := &Node{
   847  		NodeResources: &NodeResources{
   848  			Networks: []*NetworkResource{
   849  				// As of Nomad v1.3 bridge networks get
   850  				// registered with only their mode set.
   851  				{
   852  					Mode: "bridge",
   853  				},
   854  
   855  				// Localhost (agent interface)
   856  				{
   857  					CIDR:   "127.0.0.1/32",
   858  					Device: "lo",
   859  					IP:     "127.0.0.1",
   860  					MBits:  1000,
   861  					Mode:   "host",
   862  				},
   863  				{
   864  					CIDR:   "::1/128",
   865  					Device: "lo",
   866  					IP:     "::1",
   867  					MBits:  1000,
   868  					Mode:   "host",
   869  				},
   870  
   871  				// Node.NodeResources.Networks does *not*
   872  				// contain host_networks.
   873  			},
   874  			NodeNetworks: []*NodeNetworkResource{
   875  				// As of Nomad v1.3 bridge networks get
   876  				// registered with only their mode set.
   877  				{
   878  					Mode: "bridge",
   879  				},
   880  				{
   881  					Addresses: []NodeNetworkAddress{
   882  						{
   883  							Address: "127.0.0.1",
   884  							Alias:   "default",
   885  							Family:  "ipv4",
   886  						},
   887  						{
   888  							Address: "::1",
   889  							Alias:   "default",
   890  							Family:  "ipv6",
   891  						},
   892  					},
   893  					Device: "lo",
   894  					Mode:   "host",
   895  					Speed:  1000,
   896  				},
   897  				{
   898  					Addresses: []NodeNetworkAddress{
   899  						{
   900  							Address:       "192.168.0.1",
   901  							Alias:         "eth0",
   902  							Family:        "ipv4",
   903  							ReservedPorts: "22",
   904  						},
   905  					},
   906  					Device:     "enxaaaaaaaaaaaa",
   907  					MacAddress: "aa:aa:aa:aa:aa:aa",
   908  					Mode:       "host",
   909  					Speed:      1000,
   910  				},
   911  				{
   912  					Addresses: []NodeNetworkAddress{
   913  						{
   914  							Address:       "192.168.1.1",
   915  							Alias:         "eth1",
   916  							Family:        "ipv4",
   917  							ReservedPorts: "80",
   918  						},
   919  					},
   920  					Device:     "enxbbbbbbbbbbbb",
   921  					MacAddress: "bb:bb:bb:bb:bb:bb",
   922  					Mode:       "host",
   923  					Speed:      1000,
   924  				},
   925  			},
   926  		},
   927  		ReservedResources: &NodeReservedResources{
   928  			Networks: NodeReservedNetworkResources{
   929  				ReservedHostPorts: "22",
   930  			},
   931  		},
   932  	}
   933  
   934  	require.NoError(t, idx.SetNode(n))
   935  
   936  	// TaskNetworks should only contain the bridge and agent network
   937  	require.Len(t, idx.TaskNetworks, 2)
   938  
   939  	// Ports should be used across all 4 IPs
   940  	require.Equal(t, 4, len(idx.UsedPorts))
   941  
   942  	// 22 should be reserved on all IPs
   943  	require.True(t, idx.UsedPorts["127.0.0.1"].Check(22))
   944  	require.True(t, idx.UsedPorts["::1"].Check(22))
   945  	require.True(t, idx.UsedPorts["192.168.0.1"].Check(22))
   946  	require.True(t, idx.UsedPorts["192.168.1.1"].Check(22))
   947  
   948  	// 80 should only be reserved on eth1's address
   949  	require.False(t, idx.UsedPorts["127.0.0.1"].Check(80))
   950  	require.False(t, idx.UsedPorts["::1"].Check(80))
   951  	require.False(t, idx.UsedPorts["192.168.0.1"].Check(80))
   952  	require.True(t, idx.UsedPorts["192.168.1.1"].Check(80))
   953  }