-
Notifications
You must be signed in to change notification settings - Fork 13
/
inventory.go
139 lines (125 loc) · 4.15 KB
/
inventory.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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package aini
// Inventory-related helper methods
// Reconcile ensures inventory basic rules, run after updates.
// After initial inventory file processing, only direct relationships are set.
//
// This method:
// * (re)sets Children and Parents for hosts and groups
// * ensures that mandatory groups exist
// * calculates variables for hosts and groups
func (inventory *InventoryData) Reconcile() {
// Clear all computed data
for _, host := range inventory.Hosts {
host.clearData()
}
// a group can be empty (with no hosts in it), so the previous method will not clean it
// on the other hand, a group could have been attached to a host by a user, but not added to the inventory.Groups map
// so it's safer just to clean everything
for _, group := range inventory.Groups {
group.clearData(make(map[string]struct{}, len(inventory.Groups)))
}
allGroup := inventory.getOrCreateGroup("all")
ungroupedGroup := inventory.getOrCreateGroup("ungrouped")
ungroupedGroup.DirectParents[allGroup.Name] = allGroup
// First, ensure that inventory.Groups contains all the groups
for _, host := range inventory.Hosts {
for _, group := range host.DirectGroups {
inventory.Groups[group.Name] = group
for _, ancestor := range group.ListParentGroupsOrdered() {
inventory.Groups[ancestor.Name] = ancestor
}
}
}
// Calculate intergroup relationships
for _, group := range inventory.Groups {
group.DirectParents[allGroup.Name] = allGroup
for _, ancestor := range group.ListParentGroupsOrdered() {
group.Parents[ancestor.Name] = ancestor
ancestor.Children[group.Name] = group
}
}
// Now set hosts for groups and groups for hosts
for _, host := range inventory.Hosts {
host.Groups[allGroup.Name] = allGroup
for _, group := range host.DirectGroups {
group.Hosts[host.Name] = host
host.Groups[group.Name] = group
for _, parent := range group.Parents {
group.Parents[parent.Name] = parent
parent.Children[group.Name] = group
parent.Hosts[host.Name] = host
host.Groups[parent.Name] = parent
}
}
}
inventory.reconcileVars()
}
func (host *Host) clearData() {
host.Groups = make(map[string]*Group)
host.Vars = make(map[string]string)
for _, group := range host.DirectGroups {
group.clearData(make(map[string]struct{}, len(host.Groups)))
}
}
func (group *Group) clearData(visited map[string]struct{}) {
if _, ok := visited[group.Name]; ok {
return
}
group.Hosts = make(map[string]*Host)
group.Parents = make(map[string]*Group)
group.Children = make(map[string]*Group)
group.Vars = make(map[string]string)
group.AllInventoryVars = nil
group.AllFileVars = nil
visited[group.Name] = struct{}{}
for _, parent := range group.DirectParents {
parent.clearData(visited)
}
}
// getOrCreateGroup return group from inventory if exists or creates empty Group with given name
func (inventory *InventoryData) getOrCreateGroup(groupName string) *Group {
if group, ok := inventory.Groups[groupName]; ok {
return group
}
g := &Group{
Name: groupName,
Hosts: make(map[string]*Host),
Vars: make(map[string]string),
Children: make(map[string]*Group),
Parents: make(map[string]*Group),
DirectParents: make(map[string]*Group),
InventoryVars: make(map[string]string),
FileVars: make(map[string]string),
}
inventory.Groups[groupName] = g
return g
}
// getOrCreateHost return host from inventory if exists or creates empty Host with given name
func (inventory *InventoryData) getOrCreateHost(hostName string) *Host {
if host, ok := inventory.Hosts[hostName]; ok {
return host
}
h := &Host{
Name: hostName,
Port: 22,
Groups: make(map[string]*Group),
Vars: make(map[string]string),
DirectGroups: make(map[string]*Group),
InventoryVars: make(map[string]string),
FileVars: make(map[string]string),
}
inventory.Hosts[hostName] = h
return h
}
// addValues fills `to` map with values from `from` map
func addValues(to map[string]string, from map[string]string) {
for k, v := range from {
to[k] = v
}
}
// copyStringMap creates a non-deep copy of the map
func copyStringMap(from map[string]string) map[string]string {
result := make(map[string]string, len(from))
addValues(result, from)
return result
}