open-nomad/nomad/structs/node_class.go
Alex Dadgar 4ee603c382 Device hook and devices affect computed node class
This PR introduces a device hook that retrieves the device mount
information for an allocation. It also updates the computed node class
computation to take into account devices.

TODO Fix the task runner unit test. The environment variable is being
lost even though it is being properly set in the prestart hook.
2018-11-27 17:25:33 -08:00

133 lines
3.6 KiB
Go

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."
)
// 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)
}
// 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 identifying fields.
func (n *Node) ComputeClass() error {
hash, err := hashstructure.Hash(n, nil)
if err != nil {
return err
}
n.ComputedClass = fmt.Sprintf("v1:%d", hash)
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 {
case "Datacenter", "Attributes", "Meta", "NodeClass", "NodeResources":
return true, nil
default:
return false, nil
}
}
// 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 {
return false, fmt.Errorf("map key %v not a string", k)
}
switch field {
case "Meta", "Attributes":
return !IsUniqueNamespace(key), nil
default:
return false, fmt.Errorf("unexpected map field: %v", field)
}
}
// HashInclude is used to blacklist uniquely identifying node fields from being
// included in the computed node class.
func (n NodeResources) HashInclude(field string, v interface{}) (bool, error) {
switch field {
case "Devices":
return true, nil
default:
return false, nil
}
}
// HashInclude is used to blacklist uniquely identifying node fields from being
// included in the computed node class.
func (n NodeDeviceResource) HashInclude(field string, v interface{}) (bool, error) {
switch field {
case "Vendor", "Type", "Name", "Attributes":
return true, nil
default:
return false, nil
}
}
// HashIncludeMap is used to blacklist uniquely identifying node map keys from being
// included in the computed node class.
func (n NodeDeviceResource) HashIncludeMap(field string, k, v interface{}) (bool, error) {
key, ok := k.(string)
if !ok {
return false, fmt.Errorf("map key %v not a string", k)
}
switch field {
case "Attributes":
return !IsUniqueNamespace(key), nil
default:
return false, fmt.Errorf("unexpected map field: %v", field)
}
}
// 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."):
return true
case strings.HasPrefix(target, "${attr.unique."):
return true
case strings.HasPrefix(target, "${meta.unique."):
return true
default:
return false
}
}