github.com/anuvu/nomad@v0.8.7-atom1/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": 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 // EscapedConstraints takes a set of constraints and returns the set that 69 // escapes computed node classes. 70 func EscapedConstraints(constraints []*Constraint) []*Constraint { 71 var escaped []*Constraint 72 for _, c := range constraints { 73 if constraintTargetEscapes(c.LTarget) || constraintTargetEscapes(c.RTarget) { 74 escaped = append(escaped, c) 75 } 76 } 77 78 return escaped 79 } 80 81 // constraintTargetEscapes returns whether the target of a constraint escapes 82 // computed node class optimization. 83 func constraintTargetEscapes(target string) bool { 84 switch { 85 case strings.HasPrefix(target, "${node.unique."): 86 return true 87 case strings.HasPrefix(target, "${attr.unique."): 88 return true 89 case strings.HasPrefix(target, "${meta.unique."): 90 return true 91 default: 92 return false 93 } 94 }