github.com/uchennaokeke444/nomad@v0.11.8/nomad/structs/node_class.go (about)

     1  package structs
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"github.com/mitchellh/hashstructure"
     8  )
     9  
    10  const (
    11  	// NodeUniqueNamespace is a prefix that can be appended to node meta or
    12  	// attribute keys to mark them for exclusion in computed node class.
    13  	NodeUniqueNamespace = "unique."
    14  )
    15  
    16  // UniqueNamespace takes a key and returns the key marked under the unique
    17  // namespace.
    18  func UniqueNamespace(key string) string {
    19  	return fmt.Sprintf("%s%s", NodeUniqueNamespace, key)
    20  }
    21  
    22  // IsUniqueNamespace returns whether the key is under the unique namespace.
    23  func IsUniqueNamespace(key string) bool {
    24  	return strings.HasPrefix(key, NodeUniqueNamespace)
    25  }
    26  
    27  // ComputeClass computes a derived class for the node based on its attributes.
    28  // ComputedClass is a unique id that identifies nodes with a common set of
    29  // attributes and capabilities. Thus, when calculating a node's computed class
    30  // we avoid including any uniquely identifying fields.
    31  func (n *Node) ComputeClass() error {
    32  	hash, err := hashstructure.Hash(n, nil)
    33  	if err != nil {
    34  		return err
    35  	}
    36  
    37  	n.ComputedClass = fmt.Sprintf("v1:%d", hash)
    38  	return nil
    39  }
    40  
    41  // HashInclude is used to blacklist uniquely identifying node fields from being
    42  // included in the computed node class.
    43  func (n Node) HashInclude(field string, v interface{}) (bool, error) {
    44  	switch field {
    45  	case "Datacenter", "Attributes", "Meta", "NodeClass", "NodeResources":
    46  		return true, nil
    47  	default:
    48  		return false, nil
    49  	}
    50  }
    51  
    52  // HashIncludeMap is used to blacklist uniquely identifying node map keys from being
    53  // included in the computed node class.
    54  func (n Node) HashIncludeMap(field string, k, v interface{}) (bool, error) {
    55  	key, ok := k.(string)
    56  	if !ok {
    57  		return false, fmt.Errorf("map key %v not a string", k)
    58  	}
    59  
    60  	switch field {
    61  	case "Meta", "Attributes":
    62  		return !IsUniqueNamespace(key), nil
    63  	default:
    64  		return false, fmt.Errorf("unexpected map field: %v", field)
    65  	}
    66  }
    67  
    68  // HashInclude is used to blacklist uniquely identifying node fields from being
    69  // included in the computed node class.
    70  func (n NodeResources) HashInclude(field string, v interface{}) (bool, error) {
    71  	switch field {
    72  	case "Devices":
    73  		return true, nil
    74  	default:
    75  		return false, nil
    76  	}
    77  }
    78  
    79  // HashInclude is used to blacklist uniquely identifying node fields from being
    80  // included in the computed node class.
    81  func (n NodeDeviceResource) HashInclude(field string, v interface{}) (bool, error) {
    82  	switch field {
    83  	case "Vendor", "Type", "Name", "Attributes":
    84  		return true, nil
    85  	default:
    86  		return false, nil
    87  	}
    88  }
    89  
    90  // HashIncludeMap is used to blacklist uniquely identifying node map keys from being
    91  // included in the computed node class.
    92  func (n NodeDeviceResource) HashIncludeMap(field string, k, v interface{}) (bool, error) {
    93  	key, ok := k.(string)
    94  	if !ok {
    95  		return false, fmt.Errorf("map key %v not a string", k)
    96  	}
    97  
    98  	switch field {
    99  	case "Attributes":
   100  		return !IsUniqueNamespace(key), nil
   101  	default:
   102  		return false, fmt.Errorf("unexpected map field: %v", field)
   103  	}
   104  }
   105  
   106  // EscapedConstraints takes a set of constraints and returns the set that
   107  // escapes computed node classes.
   108  func EscapedConstraints(constraints []*Constraint) []*Constraint {
   109  	var escaped []*Constraint
   110  	for _, c := range constraints {
   111  		if constraintTargetEscapes(c.LTarget) || constraintTargetEscapes(c.RTarget) {
   112  			escaped = append(escaped, c)
   113  		}
   114  	}
   115  
   116  	return escaped
   117  }
   118  
   119  // constraintTargetEscapes returns whether the target of a constraint escapes
   120  // computed node class optimization.
   121  func constraintTargetEscapes(target string) bool {
   122  	switch {
   123  	case strings.HasPrefix(target, "${node.unique."):
   124  		return true
   125  	case strings.HasPrefix(target, "${attr.unique."):
   126  		return true
   127  	case strings.HasPrefix(target, "${meta.unique."):
   128  		return true
   129  	default:
   130  		return false
   131  	}
   132  }