File: inventory.go

package info (click to toggle)
golang-github-relex-aini 1.6.0-1~exp1
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 204 kB
  • sloc: makefile: 15
file content (139 lines) | stat: -rw-r--r-- 4,248 bytes parent folder | download
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
}