feat(ansible): support top-level inventory groups
Co-authored-by: Virgil <virgil@lethean.io>
This commit is contained in:
parent
e6be1e5f5a
commit
84451b2bd8
2 changed files with 135 additions and 0 deletions
|
|
@ -525,6 +525,41 @@ all:
|
|||
assert.Len(t, inv.All.Children["databases"].Hosts, 1)
|
||||
}
|
||||
|
||||
func TestParser_ParseInventory_Good_TopLevelGroups(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
path := joinPath(dir, "inventory.yml")
|
||||
|
||||
yaml := `---
|
||||
webservers:
|
||||
vars:
|
||||
tier: web
|
||||
hosts:
|
||||
web1:
|
||||
ansible_host: 10.0.0.1
|
||||
web2:
|
||||
ansible_host: 10.0.0.2
|
||||
databases:
|
||||
hosts:
|
||||
db1:
|
||||
ansible_host: 10.0.1.1
|
||||
`
|
||||
require.NoError(t, writeTestFile(path, []byte(yaml), 0644))
|
||||
|
||||
p := NewParser(dir)
|
||||
inv, err := p.ParseInventory(path)
|
||||
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, inv.All)
|
||||
require.NotNil(t, inv.All.Children["webservers"])
|
||||
require.NotNil(t, inv.All.Children["databases"])
|
||||
assert.Len(t, inv.All.Children["webservers"].Hosts, 2)
|
||||
assert.Len(t, inv.All.Children["databases"].Hosts, 1)
|
||||
assert.Equal(t, "web", inv.All.Children["webservers"].Vars["tier"])
|
||||
assert.ElementsMatch(t, []string{"web1", "web2", "db1"}, GetHosts(inv, "all"))
|
||||
assert.Equal(t, []string{"web1", "web2"}, GetHosts(inv, "webservers"))
|
||||
assert.Equal(t, "web", GetHostVars(inv, "web1")["tier"])
|
||||
}
|
||||
|
||||
func TestParser_ParseInventory_Good_WithVars(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
path := joinPath(dir, "inventory.yml")
|
||||
|
|
|
|||
100
types.go
100
types.go
|
|
@ -2,6 +2,9 @@ package ansible
|
|||
|
||||
import (
|
||||
"time"
|
||||
|
||||
coreerr "dappco.re/go/core/log"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// Playbook represents an Ansible playbook.
|
||||
|
|
@ -205,6 +208,103 @@ type Inventory struct {
|
|||
All *InventoryGroup `yaml:"all"`
|
||||
}
|
||||
|
||||
// UnmarshalYAML supports both the explicit `all:` root and inventories that
|
||||
// declare top-level groups directly.
|
||||
func (i *Inventory) UnmarshalYAML(unmarshal func(any) error) error {
|
||||
var raw map[string]any
|
||||
if err := unmarshal(&raw); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
root := &InventoryGroup{}
|
||||
rootInput := make(map[string]any)
|
||||
if all, ok := raw["all"]; ok {
|
||||
group, err := decodeInventoryGroupValue(all)
|
||||
if err != nil {
|
||||
return coreerr.E("Inventory.UnmarshalYAML", "decode all group", err)
|
||||
}
|
||||
root = group
|
||||
}
|
||||
|
||||
for name, value := range raw {
|
||||
if name == "all" {
|
||||
continue
|
||||
}
|
||||
|
||||
switch name {
|
||||
case "hosts", "children", "vars":
|
||||
rootInput[name] = value
|
||||
continue
|
||||
}
|
||||
|
||||
group, err := decodeInventoryGroupValue(value)
|
||||
if err != nil {
|
||||
return coreerr.E("Inventory.UnmarshalYAML", "decode group "+name, err)
|
||||
}
|
||||
|
||||
if root.Children == nil {
|
||||
root.Children = make(map[string]*InventoryGroup)
|
||||
}
|
||||
root.Children[name] = group
|
||||
}
|
||||
|
||||
if len(rootInput) > 0 {
|
||||
extra, err := decodeInventoryGroupValue(rootInput)
|
||||
if err != nil {
|
||||
return coreerr.E("Inventory.UnmarshalYAML", "decode root group", err)
|
||||
}
|
||||
mergeInventoryGroups(root, extra)
|
||||
}
|
||||
|
||||
i.All = root
|
||||
return nil
|
||||
}
|
||||
|
||||
func decodeInventoryGroupValue(value any) (*InventoryGroup, error) {
|
||||
if value == nil {
|
||||
return &InventoryGroup{}, nil
|
||||
}
|
||||
|
||||
data, err := yaml.Marshal(value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var group InventoryGroup
|
||||
if err := yaml.Unmarshal(data, &group); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &group, nil
|
||||
}
|
||||
|
||||
func mergeInventoryGroups(dst, src *InventoryGroup) {
|
||||
if dst == nil || src == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if dst.Hosts == nil && len(src.Hosts) > 0 {
|
||||
dst.Hosts = make(map[string]*Host, len(src.Hosts))
|
||||
}
|
||||
for name, host := range src.Hosts {
|
||||
dst.Hosts[name] = host
|
||||
}
|
||||
|
||||
if dst.Children == nil && len(src.Children) > 0 {
|
||||
dst.Children = make(map[string]*InventoryGroup, len(src.Children))
|
||||
}
|
||||
for name, child := range src.Children {
|
||||
dst.Children[name] = child
|
||||
}
|
||||
|
||||
if dst.Vars == nil && len(src.Vars) > 0 {
|
||||
dst.Vars = make(map[string]any, len(src.Vars))
|
||||
}
|
||||
for key, value := range src.Vars {
|
||||
dst.Vars[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
// InventoryGroup represents a group in inventory.
|
||||
//
|
||||
// Example:
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue