-
Notifications
You must be signed in to change notification settings - Fork 1
/
nodes.go
103 lines (81 loc) · 2.53 KB
/
nodes.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
package chef
import (
"context"
"encoding/json"
"errors"
"sort"
"dario.cat/mergo"
"github.com/go-chef/chef"
)
type NodeList struct {
Nodes []string `json:"nodes"`
}
type Node struct {
chef.Node
MergedAttributes map[string]interface{}
}
var ErrPathNotFound = errors.New("attribute not found at path")
func (s Service) GetNodes(ctx context.Context) (*NodeList, error) {
nodes, err := s.client.Nodes.List()
if err != nil {
return nil, err
}
var nl []string
for i := range nodes {
nl = append(nl, i)
}
sort.Strings(nl)
return &NodeList{Nodes: nl}, nil
}
func (s Service) SearchNodes(ctx context.Context, q string) (*NodeList, error) {
partial := map[string]interface{}{
"name": []string{"name"},
}
query, err := s.client.Search.PartialExecJSON("node", q, partial)
if err != nil {
return nil, err
}
var nodes NodeList
for _, i := range query.Rows {
var node Node
_ = json.Unmarshal(i.Data, &node)
nodes.Nodes = append(nodes.Nodes, node.Name)
}
sort.Strings(nodes.Nodes)
return &nodes, nil
}
func (s Service) GetNode(ctx context.Context, name string) (*Node, error) {
node, err := s.client.Nodes.Get(name)
if err != nil {
return nil, err
}
ret := &Node{Node: node}
ret.MergedAttributes = ret.MergeAttributes()
return ret, nil
}
// MergeAttributes returns the merged set of all node attributes taking attribute precedence into consideration.
// Ref: https://docs.chef.io/attribute_precedence/
func (s Node) MergeAttributes() map[string]interface{} {
var attrs map[string]interface{}
_ = mergo.Merge(&attrs, s.DefaultAttributes, mergo.WithOverride)
_ = mergo.Merge(&attrs, s.NormalAttributes, mergo.WithOverride)
_ = mergo.Merge(&attrs, s.OverrideAttributes, mergo.WithOverride)
_ = mergo.Merge(&attrs, s.AutomaticAttributes, mergo.WithOverride)
return attrs
}
// GetEffectiveAttributeValue returns the effective attribute value of a given path considering attribute precedence.
func (s Node) GetEffectiveAttributeValue(paths ...string) (interface{}, error) {
return lookupAttribute(s.MergedAttributes, paths...)
}
// lookupAttribute is a function from go-chef, but we use it differently here since all attributes
// are merged instead of just a single one when requested
func lookupAttribute(attrs map[string]interface{}, paths ...string) (interface{}, error) {
currentPath, remainingPaths := paths[0], paths[1:]
if attr, ok := attrs[currentPath]; ok {
if len(remainingPaths) <= 0 {
return attr, nil
}
return lookupAttribute(attr.(map[string]interface{}), remainingPaths...)
}
return nil, ErrPathNotFound
}