open-nomad/nomad/structs/node_class.go

95 lines
2.6 KiB
Go
Raw Normal View History

2016-01-21 01:30:02 +00:00
package structs
import (
"fmt"
"strings"
"github.com/mitchellh/hashstructure"
)
const (
// NodeUniqueNamespace is a prefix that can be appended to node meta or
// attribute keys to mark them for exclusion in computed node class.
NodeUniqueNamespace = "unique."
2016-01-21 01:30:02 +00:00
)
2016-01-23 02:12:16 +00:00
// UniqueNamespace takes a key and returns the key marked under the unique
// namespace.
func UniqueNamespace(key string) string {
return fmt.Sprintf("%s%s", NodeUniqueNamespace, key)
}
// IsUniqueNamespace returns whether the key is under the unique namespace.
func IsUniqueNamespace(key string) bool {
return strings.HasPrefix(key, NodeUniqueNamespace)
}
2016-01-21 01:30:02 +00:00
// ComputeClass computes a derived class for the node based on its attributes.
// ComputedClass is a unique id that identifies nodes with a common set of
// attributes and capabilities. Thus, when calculating a node's computed class
// we avoid including any uniquely identifing fields.
func (n *Node) ComputeClass() error {
hash, err := hashstructure.Hash(n, nil)
if err != nil {
return err
}
n.ComputedClass = fmt.Sprintf("v1:%d", hash)
2016-01-21 01:30:02 +00:00
return nil
}
// HashInclude is used to blacklist uniquely identifying node fields from being
// included in the computed node class.
func (n Node) HashInclude(field string, v interface{}) (bool, error) {
switch field {
2016-01-26 22:55:38 +00:00
case "Datacenter", "Attributes", "Meta", "NodeClass":
2016-01-21 01:30:02 +00:00
return true, nil
2016-01-26 22:55:38 +00:00
default:
return false, nil
2016-01-21 01:30:02 +00:00
}
}
// HashIncludeMap is used to blacklist uniquely identifying node map keys from being
// included in the computed node class.
func (n Node) HashIncludeMap(field string, k, v interface{}) (bool, error) {
key, ok := k.(string)
if !ok {
2016-01-27 17:23:57 +00:00
return false, fmt.Errorf("map key %v not a string", k)
2016-01-21 01:30:02 +00:00
}
switch field {
case "Meta", "Attributes":
2016-01-23 02:12:16 +00:00
return !IsUniqueNamespace(key), nil
2016-01-21 01:30:02 +00:00
default:
return false, fmt.Errorf("unexpected map field: %v", field)
}
}
2016-01-25 19:45:48 +00:00
// EscapedConstraints takes a set of constraints and returns the set that
// escapes computed node classes.
func EscapedConstraints(constraints []*Constraint) []*Constraint {
var escaped []*Constraint
for _, c := range constraints {
if constraintTargetEscapes(c.LTarget) || constraintTargetEscapes(c.RTarget) {
escaped = append(escaped, c)
}
}
return escaped
}
// constraintTargetEscapes returns whether the target of a constraint escapes
// computed node class optimization.
func constraintTargetEscapes(target string) bool {
switch {
case strings.HasPrefix(target, "$node.unique."):
2016-01-25 19:45:48 +00:00
return true
2016-01-27 00:43:42 +00:00
case strings.HasPrefix(target, "$attr.unique."):
return true
case strings.HasPrefix(target, "$meta.unique."):
return true
2016-01-25 19:45:48 +00:00
default:
return false
}
}