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

     1  package structs
     2  
     3  import (
     4  	"reflect"
     5  	"testing"
     6  
     7  	"github.com/hashicorp/nomad/ci"
     8  	"github.com/hashicorp/nomad/helper/uuid"
     9  	psstructs "github.com/hashicorp/nomad/plugins/shared/structs"
    10  	"github.com/stretchr/testify/require"
    11  )
    12  
    13  // TODO Test
    14  func testNode() *Node {
    15  	return &Node{
    16  		ID:         uuid.Generate(),
    17  		Datacenter: "dc1",
    18  		Name:       "foobar",
    19  		Attributes: map[string]string{
    20  			"kernel.name": "linux",
    21  			"arch":        "x86",
    22  			"version":     "0.1.0",
    23  			"driver.exec": "1",
    24  		},
    25  		NodeResources: &NodeResources{
    26  			Cpu: NodeCpuResources{
    27  				CpuShares: 4000,
    28  			},
    29  			Memory: NodeMemoryResources{
    30  				MemoryMB: 8192,
    31  			},
    32  			Disk: NodeDiskResources{
    33  				DiskMB: 100 * 1024,
    34  			},
    35  			Networks: []*NetworkResource{
    36  				{
    37  					Device: "eth0",
    38  					CIDR:   "192.168.0.100/32",
    39  					IP:     "192.168.0.100",
    40  					MBits:  1000,
    41  				},
    42  			},
    43  		},
    44  		Links: map[string]string{
    45  			"consul": "foobar.dc1",
    46  		},
    47  		Meta: map[string]string{
    48  			"pci-dss": "true",
    49  		},
    50  		NodeClass: "linux-medium-pci",
    51  		Status:    NodeStatusReady,
    52  	}
    53  }
    54  
    55  func TestNode_ComputedClass(t *testing.T) {
    56  	ci.Parallel(t)
    57  
    58  	require := require.New(t)
    59  
    60  	// Create a node and gets it computed class
    61  	n := testNode()
    62  	require.NoError(n.ComputeClass())
    63  	require.NotEmpty(n.ComputedClass)
    64  	old := n.ComputedClass
    65  
    66  	// Compute again to ensure determinism
    67  	require.NoError(n.ComputeClass())
    68  	require.Equal(n.ComputedClass, old)
    69  
    70  	// Modify a field and compute the class again.
    71  	n.Datacenter = "New DC"
    72  	require.NoError(n.ComputeClass())
    73  	require.NotEqual(n.ComputedClass, old)
    74  	old = n.ComputedClass
    75  
    76  	// Add a device
    77  	n.NodeResources.Devices = append(n.NodeResources.Devices, &NodeDeviceResource{
    78  		Vendor: "foo",
    79  		Type:   "gpu",
    80  		Name:   "bam",
    81  	})
    82  	require.NoError(n.ComputeClass())
    83  	require.NotEqual(n.ComputedClass, old)
    84  }
    85  
    86  func TestNode_ComputedClass_Ignore(t *testing.T) {
    87  	ci.Parallel(t)
    88  
    89  	require := require.New(t)
    90  
    91  	// Create a node and gets it computed class
    92  	n := testNode()
    93  	require.NoError(n.ComputeClass())
    94  	require.NotEmpty(n.ComputedClass)
    95  	old := n.ComputedClass
    96  
    97  	// Modify an ignored field and compute the class again.
    98  	n.ID = "New ID"
    99  	require.NoError(n.ComputeClass())
   100  	require.NotEmpty(n.ComputedClass)
   101  	require.Equal(n.ComputedClass, old)
   102  
   103  }
   104  
   105  func TestNode_ComputedClass_Device_Attr(t *testing.T) {
   106  	ci.Parallel(t)
   107  
   108  	require := require.New(t)
   109  
   110  	// Create a node and gets it computed class
   111  	n := testNode()
   112  	d := &NodeDeviceResource{
   113  		Vendor: "foo",
   114  		Type:   "gpu",
   115  		Name:   "bam",
   116  		Attributes: map[string]*psstructs.Attribute{
   117  			"foo": psstructs.NewBoolAttribute(true),
   118  		},
   119  	}
   120  	n.NodeResources.Devices = append(n.NodeResources.Devices, d)
   121  	require.NoError(n.ComputeClass())
   122  	require.NotEmpty(n.ComputedClass)
   123  	old := n.ComputedClass
   124  
   125  	// Update the attributes to be have a unique value
   126  	d.Attributes["unique.bar"] = psstructs.NewBoolAttribute(false)
   127  	require.NoError(n.ComputeClass())
   128  	require.Equal(n.ComputedClass, old)
   129  }
   130  
   131  func TestNode_ComputedClass_Attr(t *testing.T) {
   132  	ci.Parallel(t)
   133  
   134  	// Create a node and gets it computed class
   135  	n := testNode()
   136  	if err := n.ComputeClass(); err != nil {
   137  		t.Fatalf("ComputeClass() failed: %v", err)
   138  	}
   139  	if n.ComputedClass == "" {
   140  		t.Fatal("ComputeClass() didn't set computed class")
   141  	}
   142  	old := n.ComputedClass
   143  
   144  	// Add a unique addr and compute the class again
   145  	n.Attributes["unique.foo"] = "bar"
   146  	if err := n.ComputeClass(); err != nil {
   147  		t.Fatalf("ComputeClass() failed: %v", err)
   148  	}
   149  	if old != n.ComputedClass {
   150  		t.Fatal("ComputeClass() didn't ignore unique attr suffix")
   151  	}
   152  
   153  	// Modify an attribute and compute the class again.
   154  	n.Attributes["version"] = "New Version"
   155  	if err := n.ComputeClass(); err != nil {
   156  		t.Fatalf("ComputeClass() failed: %v", err)
   157  	}
   158  	if n.ComputedClass == "" {
   159  		t.Fatal("ComputeClass() didn't set computed class")
   160  	}
   161  	if old == n.ComputedClass {
   162  		t.Fatal("ComputeClass() ignored attribute change")
   163  	}
   164  
   165  	// Remove and attribute and compute the class again.
   166  	old = n.ComputedClass
   167  	delete(n.Attributes, "driver.exec")
   168  	if err := n.ComputeClass(); err != nil {
   169  		t.Fatalf("ComputedClass() failed: %v", err)
   170  	}
   171  	if n.ComputedClass == "" {
   172  		t.Fatal("ComputeClass() didn't set computed class")
   173  	}
   174  	if old == n.ComputedClass {
   175  		t.Fatalf("ComputedClass() ignored removal of attribute key")
   176  	}
   177  }
   178  
   179  func TestNode_ComputedClass_Meta(t *testing.T) {
   180  	ci.Parallel(t)
   181  
   182  	// Create a node and gets it computed class
   183  	n := testNode()
   184  	if err := n.ComputeClass(); err != nil {
   185  		t.Fatalf("ComputeClass() failed: %v", err)
   186  	}
   187  	if n.ComputedClass == "" {
   188  		t.Fatal("ComputeClass() didn't set computed class")
   189  	}
   190  	old := n.ComputedClass
   191  
   192  	// Modify a meta key and compute the class again.
   193  	n.Meta["pci-dss"] = "false"
   194  	if err := n.ComputeClass(); err != nil {
   195  		t.Fatalf("ComputeClass() failed: %v", err)
   196  	}
   197  	if n.ComputedClass == "" {
   198  		t.Fatal("ComputeClass() didn't set computed class")
   199  	}
   200  	if old == n.ComputedClass {
   201  		t.Fatal("ComputeClass() ignored meta change")
   202  	}
   203  	old = n.ComputedClass
   204  
   205  	// Add a unique meta key and compute the class again.
   206  	n.Meta["unique.foo"] = "ignore"
   207  	if err := n.ComputeClass(); err != nil {
   208  		t.Fatalf("ComputeClass() failed: %v", err)
   209  	}
   210  	if n.ComputedClass == "" {
   211  		t.Fatal("ComputeClass() didn't set computed class")
   212  	}
   213  	if old != n.ComputedClass {
   214  		t.Fatal("ComputeClass() didn't ignore unique meta key")
   215  	}
   216  }
   217  
   218  func TestNode_EscapedConstraints(t *testing.T) {
   219  	ci.Parallel(t)
   220  
   221  	// Non-escaped constraints
   222  	ne1 := &Constraint{
   223  		LTarget: "${attr.kernel.name}",
   224  		RTarget: "linux",
   225  		Operand: "=",
   226  	}
   227  	ne2 := &Constraint{
   228  		LTarget: "${meta.key_foo}",
   229  		RTarget: "linux",
   230  		Operand: "<",
   231  	}
   232  	ne3 := &Constraint{
   233  		LTarget: "${node.dc}",
   234  		RTarget: "test",
   235  		Operand: "!=",
   236  	}
   237  
   238  	// Escaped constraints
   239  	e1 := &Constraint{
   240  		LTarget: "${attr.unique.kernel.name}",
   241  		RTarget: "linux",
   242  		Operand: "=",
   243  	}
   244  	e2 := &Constraint{
   245  		LTarget: "${meta.unique.key_foo}",
   246  		RTarget: "linux",
   247  		Operand: "<",
   248  	}
   249  	e3 := &Constraint{
   250  		LTarget: "${unique.node.id}",
   251  		RTarget: "test",
   252  		Operand: "!=",
   253  	}
   254  	constraints := []*Constraint{ne1, ne2, ne3, e1, e2, e3}
   255  	expected := []*Constraint{ne1, ne2, ne3}
   256  	if act := EscapedConstraints(constraints); reflect.DeepEqual(act, expected) {
   257  		t.Fatalf("EscapedConstraints(%v) returned %v; want %v", constraints, act, expected)
   258  	}
   259  }