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 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
|
package aini
import (
"bufio"
"bytes"
"io"
"os"
"path"
"sort"
"strings"
)
// InventoryData contains parsed inventory representation
// Note: Groups and Hosts fields contain all the groups and hosts, not only top-level
type InventoryData struct {
Groups map[string]*Group
Hosts map[string]*Host
}
// Group represents ansible group
type Group struct {
Name string
Vars map[string]string
Hosts map[string]*Host
Children map[string]*Group
Parents map[string]*Group
DirectParents map[string]*Group
// Vars set in inventory
InventoryVars map[string]string
// Vars set in group_vars
FileVars map[string]string
// Projection of all parent inventory variables
AllInventoryVars map[string]string
// Projection of all parent group_vars variables
AllFileVars map[string]string
}
// Host represents ansible host
type Host struct {
Name string
Port int
Vars map[string]string
Groups map[string]*Group
DirectGroups map[string]*Group
// Vars set in inventory
InventoryVars map[string]string
// Vars set in host_vars
FileVars map[string]string
}
// ParseFile parses Inventory represented as a file
func ParseFile(f string) (*InventoryData, error) {
bs, err := os.ReadFile(f)
if err != nil {
return &InventoryData{}, err
}
return Parse(bytes.NewReader(bs))
}
// ParseString parses Inventory represented as a string
func ParseString(input string) (*InventoryData, error) {
return Parse(strings.NewReader(input))
}
// Parse using some Reader
func Parse(r io.Reader) (*InventoryData, error) {
input := bufio.NewReader(r)
inventory := &InventoryData{}
err := inventory.parse(input)
if err != nil {
return inventory, err
}
inventory.Reconcile()
return inventory, nil
}
// Match looks for hosts that match the pattern
// Deprecated: Use `MatchHosts`, which does proper error handling
func (inventory *InventoryData) Match(pattern string) []*Host {
matchedHosts := make([]*Host, 0)
for _, host := range inventory.Hosts {
if m, err := path.Match(pattern, host.Name); err == nil && m {
matchedHosts = append(matchedHosts, host)
}
}
return matchedHosts
}
// GroupMapListValues transforms map of Groups into Group list in lexical order
func GroupMapListValues(mymap map[string]*Group) []*Group {
values := make([]*Group, len(mymap))
i := 0
for _, v := range mymap {
values[i] = v
i++
}
sort.Slice(values, func(i, j int) bool {
return values[i].Name < values[j].Name
})
return values
}
// HostMapListValues transforms map of Hosts into Host list in lexical order
func HostMapListValues(mymap map[string]*Host) []*Host {
values := make([]*Host, len(mymap))
i := 0
for _, v := range mymap {
values[i] = v
i++
}
sort.Slice(values, func(i, j int) bool {
return values[i].Name < values[j].Name
})
return values
}
// HostsToLower transforms all host names to lowercase
func (inventory *InventoryData) HostsToLower() {
inventory.Hosts = hostMapToLower(inventory.Hosts, false)
for _, group := range inventory.Groups {
group.Hosts = hostMapToLower(group.Hosts, true)
}
}
func hostMapToLower(hosts map[string]*Host, keysOnly bool) map[string]*Host {
newHosts := make(map[string]*Host, len(hosts))
for hostname, host := range hosts {
hostname = strings.ToLower(hostname)
if !keysOnly {
host.Name = hostname
}
newHosts[hostname] = host
}
return newHosts
}
// GroupsToLower transforms all group names to lowercase
func (inventory *InventoryData) GroupsToLower() {
inventory.Groups = groupMapToLower(inventory.Groups, false)
for _, host := range inventory.Hosts {
host.DirectGroups = groupMapToLower(host.DirectGroups, true)
host.Groups = groupMapToLower(host.Groups, true)
}
}
func (group Group) String() string {
return group.Name
}
func (host Host) String() string {
return host.Name
}
func groupMapToLower(groups map[string]*Group, keysOnly bool) map[string]*Group {
newGroups := make(map[string]*Group, len(groups))
for groupname, group := range groups {
groupname = strings.ToLower(groupname)
if !keysOnly {
group.Name = groupname
group.DirectParents = groupMapToLower(group.DirectParents, true)
group.Parents = groupMapToLower(group.Parents, true)
group.Children = groupMapToLower(group.Children, true)
}
newGroups[groupname] = group
}
return newGroups
}
|