github.com/anuvu/nomad@v0.8.7-atom1/nomad/structs/funcs_test.go (about)

     1  package structs
     2  
     3  import (
     4  	"encoding/base64"
     5  	"fmt"
     6  	"testing"
     7  
     8  	lru "github.com/hashicorp/golang-lru"
     9  	"github.com/hashicorp/nomad/helper/uuid"
    10  	"github.com/stretchr/testify/assert"
    11  )
    12  
    13  func TestRemoveAllocs(t *testing.T) {
    14  	l := []*Allocation{
    15  		{ID: "foo"},
    16  		{ID: "bar"},
    17  		{ID: "baz"},
    18  		{ID: "zip"},
    19  	}
    20  
    21  	out := RemoveAllocs(l, []*Allocation{l[1], l[3]})
    22  	if len(out) != 2 {
    23  		t.Fatalf("bad: %#v", out)
    24  	}
    25  	if out[0].ID != "foo" && out[1].ID != "baz" {
    26  		t.Fatalf("bad: %#v", out)
    27  	}
    28  }
    29  
    30  func TestFilterTerminalAllocs(t *testing.T) {
    31  	l := []*Allocation{
    32  		{
    33  			ID:            "bar",
    34  			Name:          "myname1",
    35  			DesiredStatus: AllocDesiredStatusEvict,
    36  		},
    37  		{ID: "baz", DesiredStatus: AllocDesiredStatusStop},
    38  		{
    39  			ID:            "foo",
    40  			DesiredStatus: AllocDesiredStatusRun,
    41  			ClientStatus:  AllocClientStatusPending,
    42  		},
    43  		{
    44  			ID:            "bam",
    45  			Name:          "myname",
    46  			DesiredStatus: AllocDesiredStatusRun,
    47  			ClientStatus:  AllocClientStatusComplete,
    48  			CreateIndex:   5,
    49  		},
    50  		{
    51  			ID:            "lol",
    52  			Name:          "myname",
    53  			DesiredStatus: AllocDesiredStatusRun,
    54  			ClientStatus:  AllocClientStatusComplete,
    55  			CreateIndex:   2,
    56  		},
    57  	}
    58  
    59  	out, terminalAllocs := FilterTerminalAllocs(l)
    60  	if len(out) != 1 {
    61  		t.Fatalf("bad: %#v", out)
    62  	}
    63  	if out[0].ID != "foo" {
    64  		t.Fatalf("bad: %#v", out)
    65  	}
    66  
    67  	if len(terminalAllocs) != 3 {
    68  		for _, o := range terminalAllocs {
    69  			fmt.Printf("%#v \n", o)
    70  		}
    71  
    72  		t.Fatalf("bad: %#v", terminalAllocs)
    73  	}
    74  
    75  	if terminalAllocs["myname"].ID != "bam" {
    76  		t.Fatalf("bad: %#v", terminalAllocs["myname"])
    77  	}
    78  }
    79  
    80  func TestAllocsFit_PortsOvercommitted(t *testing.T) {
    81  	n := &Node{
    82  		Resources: &Resources{
    83  			Networks: []*NetworkResource{
    84  				{
    85  					Device: "eth0",
    86  					CIDR:   "10.0.0.0/8",
    87  					MBits:  100,
    88  				},
    89  			},
    90  		},
    91  	}
    92  
    93  	a1 := &Allocation{
    94  		Job: &Job{
    95  			TaskGroups: []*TaskGroup{
    96  				{
    97  					Name:          "web",
    98  					EphemeralDisk: DefaultEphemeralDisk(),
    99  				},
   100  			},
   101  		},
   102  		TaskResources: map[string]*Resources{
   103  			"web": {
   104  				Networks: []*NetworkResource{
   105  					{
   106  						Device:        "eth0",
   107  						IP:            "10.0.0.1",
   108  						MBits:         50,
   109  						ReservedPorts: []Port{{"main", 8000}},
   110  					},
   111  				},
   112  			},
   113  		},
   114  	}
   115  
   116  	// Should fit one allocation
   117  	fit, dim, _, err := AllocsFit(n, []*Allocation{a1}, nil)
   118  	if err != nil {
   119  		t.Fatalf("err: %v", err)
   120  	}
   121  	if !fit {
   122  		t.Fatalf("Bad: %s", dim)
   123  	}
   124  
   125  	// Should not fit second allocation
   126  	fit, _, _, err = AllocsFit(n, []*Allocation{a1, a1}, nil)
   127  	if err != nil {
   128  		t.Fatalf("err: %v", err)
   129  	}
   130  	if fit {
   131  		t.Fatalf("Bad")
   132  	}
   133  }
   134  
   135  func TestAllocsFit(t *testing.T) {
   136  	n := &Node{
   137  		Resources: &Resources{
   138  			CPU:      2000,
   139  			MemoryMB: 2048,
   140  			DiskMB:   10000,
   141  			IOPS:     100,
   142  			Networks: []*NetworkResource{
   143  				{
   144  					Device: "eth0",
   145  					CIDR:   "10.0.0.0/8",
   146  					MBits:  100,
   147  				},
   148  			},
   149  		},
   150  		Reserved: &Resources{
   151  			CPU:      1000,
   152  			MemoryMB: 1024,
   153  			DiskMB:   5000,
   154  			IOPS:     50,
   155  			Networks: []*NetworkResource{
   156  				{
   157  					Device:        "eth0",
   158  					IP:            "10.0.0.1",
   159  					MBits:         50,
   160  					ReservedPorts: []Port{{"main", 80}},
   161  				},
   162  			},
   163  		},
   164  	}
   165  
   166  	a1 := &Allocation{
   167  		Resources: &Resources{
   168  			CPU:      1000,
   169  			MemoryMB: 1024,
   170  			DiskMB:   5000,
   171  			IOPS:     50,
   172  			Networks: []*NetworkResource{
   173  				{
   174  					Device:        "eth0",
   175  					IP:            "10.0.0.1",
   176  					MBits:         50,
   177  					ReservedPorts: []Port{{"main", 8000}},
   178  				},
   179  			},
   180  		},
   181  	}
   182  
   183  	// Should fit one allocation
   184  	fit, _, used, err := AllocsFit(n, []*Allocation{a1}, nil)
   185  	if err != nil {
   186  		t.Fatalf("err: %v", err)
   187  	}
   188  	if !fit {
   189  		t.Fatalf("Bad")
   190  	}
   191  
   192  	// Sanity check the used resources
   193  	if used.CPU != 2000 {
   194  		t.Fatalf("bad: %#v", used)
   195  	}
   196  	if used.MemoryMB != 2048 {
   197  		t.Fatalf("bad: %#v", used)
   198  	}
   199  
   200  	// Should not fit second allocation
   201  	fit, _, used, err = AllocsFit(n, []*Allocation{a1, a1}, nil)
   202  	if err != nil {
   203  		t.Fatalf("err: %v", err)
   204  	}
   205  	if fit {
   206  		t.Fatalf("Bad")
   207  	}
   208  
   209  	// Sanity check the used resources
   210  	if used.CPU != 3000 {
   211  		t.Fatalf("bad: %#v", used)
   212  	}
   213  	if used.MemoryMB != 3072 {
   214  		t.Fatalf("bad: %#v", used)
   215  	}
   216  
   217  }
   218  
   219  func TestAllocsFit_TerminalAlloc(t *testing.T) {
   220  	n := &Node{
   221  		Resources: &Resources{
   222  			CPU:      2000,
   223  			MemoryMB: 2048,
   224  			DiskMB:   10000,
   225  			IOPS:     100,
   226  			Networks: []*NetworkResource{
   227  				{
   228  					Device: "eth0",
   229  					CIDR:   "10.0.0.0/8",
   230  					MBits:  100,
   231  				},
   232  			},
   233  		},
   234  		Reserved: &Resources{
   235  			CPU:      1000,
   236  			MemoryMB: 1024,
   237  			DiskMB:   5000,
   238  			IOPS:     50,
   239  			Networks: []*NetworkResource{
   240  				{
   241  					Device:        "eth0",
   242  					IP:            "10.0.0.1",
   243  					MBits:         50,
   244  					ReservedPorts: []Port{{"main", 80}},
   245  				},
   246  			},
   247  		},
   248  	}
   249  
   250  	a1 := &Allocation{
   251  		Resources: &Resources{
   252  			CPU:      1000,
   253  			MemoryMB: 1024,
   254  			DiskMB:   5000,
   255  			IOPS:     50,
   256  			Networks: []*NetworkResource{
   257  				{
   258  					Device:        "eth0",
   259  					IP:            "10.0.0.1",
   260  					MBits:         50,
   261  					ReservedPorts: []Port{{"main", 8000}},
   262  				},
   263  			},
   264  		},
   265  	}
   266  
   267  	// Should fit one allocation
   268  	fit, _, used, err := AllocsFit(n, []*Allocation{a1}, nil)
   269  	if err != nil {
   270  		t.Fatalf("err: %v", err)
   271  	}
   272  	if !fit {
   273  		t.Fatalf("Bad")
   274  	}
   275  
   276  	// Sanity check the used resources
   277  	if used.CPU != 2000 {
   278  		t.Fatalf("bad: %#v", used)
   279  	}
   280  	if used.MemoryMB != 2048 {
   281  		t.Fatalf("bad: %#v", used)
   282  	}
   283  
   284  	// Should fit second allocation since it is terminal
   285  	a2 := a1.Copy()
   286  	a2.DesiredStatus = AllocDesiredStatusStop
   287  	fit, _, used, err = AllocsFit(n, []*Allocation{a1, a2}, nil)
   288  	if err != nil {
   289  		t.Fatalf("err: %v", err)
   290  	}
   291  	if !fit {
   292  		t.Fatalf("Bad")
   293  	}
   294  
   295  	// Sanity check the used resources
   296  	if used.CPU != 2000 {
   297  		t.Fatalf("bad: %#v", used)
   298  	}
   299  	if used.MemoryMB != 2048 {
   300  		t.Fatalf("bad: %#v", used)
   301  	}
   302  }
   303  
   304  func TestScoreFit(t *testing.T) {
   305  	node := &Node{}
   306  	node.Resources = &Resources{
   307  		CPU:      4096,
   308  		MemoryMB: 8192,
   309  	}
   310  	node.Reserved = &Resources{
   311  		CPU:      2048,
   312  		MemoryMB: 4096,
   313  	}
   314  
   315  	// Test a perfect fit
   316  	util := &Resources{
   317  		CPU:      2048,
   318  		MemoryMB: 4096,
   319  	}
   320  	score := ScoreFit(node, util)
   321  	if score != 18.0 {
   322  		t.Fatalf("bad: %v", score)
   323  	}
   324  
   325  	// Test the worst fit
   326  	util = &Resources{
   327  		CPU:      0,
   328  		MemoryMB: 0,
   329  	}
   330  	score = ScoreFit(node, util)
   331  	if score != 0.0 {
   332  		t.Fatalf("bad: %v", score)
   333  	}
   334  
   335  	// Test a mid-case scenario
   336  	util = &Resources{
   337  		CPU:      1024,
   338  		MemoryMB: 2048,
   339  	}
   340  	score = ScoreFit(node, util)
   341  	if score < 10.0 || score > 16.0 {
   342  		t.Fatalf("bad: %v", score)
   343  	}
   344  }
   345  
   346  func TestACLPolicyListHash(t *testing.T) {
   347  	h1 := ACLPolicyListHash(nil)
   348  	assert.NotEqual(t, "", h1)
   349  
   350  	p1 := &ACLPolicy{
   351  		Name:        fmt.Sprintf("policy-%s", uuid.Generate()),
   352  		Description: "Super cool policy!",
   353  		Rules: `
   354  		namespace "default" {
   355  			policy = "write"
   356  		}
   357  		node {
   358  			policy = "read"
   359  		}
   360  		agent {
   361  			policy = "read"
   362  		}
   363  		`,
   364  		CreateIndex: 10,
   365  		ModifyIndex: 20,
   366  	}
   367  
   368  	h2 := ACLPolicyListHash([]*ACLPolicy{p1})
   369  	assert.NotEqual(t, "", h2)
   370  	assert.NotEqual(t, h1, h2)
   371  
   372  	// Create P2 as copy of P1 with new name
   373  	p2 := &ACLPolicy{}
   374  	*p2 = *p1
   375  	p2.Name = fmt.Sprintf("policy-%s", uuid.Generate())
   376  
   377  	h3 := ACLPolicyListHash([]*ACLPolicy{p1, p2})
   378  	assert.NotEqual(t, "", h3)
   379  	assert.NotEqual(t, h2, h3)
   380  
   381  	h4 := ACLPolicyListHash([]*ACLPolicy{p2})
   382  	assert.NotEqual(t, "", h4)
   383  	assert.NotEqual(t, h3, h4)
   384  
   385  	// ModifyIndex should change the hash
   386  	p2.ModifyIndex++
   387  	h5 := ACLPolicyListHash([]*ACLPolicy{p2})
   388  	assert.NotEqual(t, "", h5)
   389  	assert.NotEqual(t, h4, h5)
   390  }
   391  
   392  func TestCompileACLObject(t *testing.T) {
   393  	p1 := &ACLPolicy{
   394  		Name:        fmt.Sprintf("policy-%s", uuid.Generate()),
   395  		Description: "Super cool policy!",
   396  		Rules: `
   397  		namespace "default" {
   398  			policy = "write"
   399  		}
   400  		node {
   401  			policy = "read"
   402  		}
   403  		agent {
   404  			policy = "read"
   405  		}
   406  		`,
   407  		CreateIndex: 10,
   408  		ModifyIndex: 20,
   409  	}
   410  
   411  	// Create P2 as copy of P1 with new name
   412  	p2 := &ACLPolicy{}
   413  	*p2 = *p1
   414  	p2.Name = fmt.Sprintf("policy-%s", uuid.Generate())
   415  
   416  	// Create a small cache
   417  	cache, err := lru.New2Q(16)
   418  	assert.Nil(t, err)
   419  
   420  	// Test compilation
   421  	aclObj, err := CompileACLObject(cache, []*ACLPolicy{p1})
   422  	assert.Nil(t, err)
   423  	assert.NotNil(t, aclObj)
   424  
   425  	// Should get the same object
   426  	aclObj2, err := CompileACLObject(cache, []*ACLPolicy{p1})
   427  	assert.Nil(t, err)
   428  	if aclObj != aclObj2 {
   429  		t.Fatalf("expected the same object")
   430  	}
   431  
   432  	// Should get another object
   433  	aclObj3, err := CompileACLObject(cache, []*ACLPolicy{p1, p2})
   434  	assert.Nil(t, err)
   435  	assert.NotNil(t, aclObj3)
   436  	if aclObj == aclObj3 {
   437  		t.Fatalf("unexpected same object")
   438  	}
   439  
   440  	// Should be order independent
   441  	aclObj4, err := CompileACLObject(cache, []*ACLPolicy{p2, p1})
   442  	assert.Nil(t, err)
   443  	assert.NotNil(t, aclObj4)
   444  	if aclObj3 != aclObj4 {
   445  		t.Fatalf("expected same object")
   446  	}
   447  }
   448  
   449  // TestGenerateMigrateToken asserts the migrate token is valid for use in HTTP
   450  // headers and CompareMigrateToken works as expected.
   451  func TestGenerateMigrateToken(t *testing.T) {
   452  	assert := assert.New(t)
   453  	allocID := uuid.Generate()
   454  	nodeSecret := uuid.Generate()
   455  	token, err := GenerateMigrateToken(allocID, nodeSecret)
   456  	assert.Nil(err)
   457  	_, err = base64.URLEncoding.DecodeString(token)
   458  	assert.Nil(err)
   459  
   460  	assert.True(CompareMigrateToken(allocID, nodeSecret, token))
   461  	assert.False(CompareMigrateToken("x", nodeSecret, token))
   462  	assert.False(CompareMigrateToken(allocID, "x", token))
   463  	assert.False(CompareMigrateToken(allocID, nodeSecret, "x"))
   464  
   465  	token2, err := GenerateMigrateToken("x", nodeSecret)
   466  	assert.Nil(err)
   467  	assert.False(CompareMigrateToken(allocID, nodeSecret, token2))
   468  	assert.True(CompareMigrateToken("x", nodeSecret, token2))
   469  }