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 }