feat(ansible): accept inventory directories

Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
Virgil 2026-04-02 03:15:52 +00:00
parent 2c0b68627d
commit d1682f6345
3 changed files with 64 additions and 0 deletions

View file

@ -2,6 +2,7 @@ package ansible
import (
"context"
"os"
"testing"
"github.com/stretchr/testify/assert"
@ -594,6 +595,27 @@ func TestExecutorExtra_SetInventory_Good(t *testing.T) {
assert.Len(t, e.inventory.All.Hosts, 2)
}
func TestExecutorExtra_SetInventory_Good_Directory(t *testing.T) {
dir := t.TempDir()
inventoryDir := joinPath(dir, "inventory")
require.NoError(t, os.MkdirAll(inventoryDir, 0755))
invPath := joinPath(inventoryDir, "inventory.yml")
yaml := `all:
hosts:
web1:
ansible_host: 10.0.0.1
`
require.NoError(t, writeTestFile(invPath, []byte(yaml), 0644))
e := NewExecutor(dir)
err := e.SetInventory(inventoryDir)
require.NoError(t, err)
assert.NotNil(t, e.inventory)
assert.Contains(t, e.inventory.All.Hosts, "web1")
}
func TestExecutorExtra_SetInventory_Bad_FileNotFound(t *testing.T) {
e := NewExecutor("/tmp")
err := e.SetInventory("/nonexistent/inventory.yml")

View file

@ -109,6 +109,8 @@ func (p *Parser) ParsePlaybookIter(path string) (iter.Seq[Play], error) {
//
// inv, err := parser.ParseInventory("/workspace/inventory.yml")
func (p *Parser) ParseInventory(path string) (*Inventory, error) {
path = p.resolveInventoryPath(path)
data, err := coreio.Local.Read(path)
if err != nil {
return nil, coreerr.E("Parser.ParseInventory", "read inventory", err)
@ -122,6 +124,23 @@ func (p *Parser) ParseInventory(path string) (*Inventory, error) {
return &inv, nil
}
// resolveInventoryPath resolves inventory directories to a concrete file.
func (p *Parser) resolveInventoryPath(path string) string {
path = p.resolvePath(path)
if path == "" || !coreio.Local.Exists(path) || !coreio.Local.IsDir(path) {
return path
}
for _, name := range []string{"inventory.yml", "hosts.yml", "inventory.yaml", "hosts.yaml"} {
candidate := joinPath(path, name)
if coreio.Local.Exists(candidate) {
return candidate
}
}
return path
}
// ParseTasks parses a tasks file (used by include_tasks).
//
// Example:

View file

@ -495,6 +495,29 @@ all:
assert.Equal(t, "192.168.1.11", inv.All.Hosts["web2"].AnsibleHost)
}
func TestParser_ParseInventory_Good_DirectoryInventory(t *testing.T) {
dir := t.TempDir()
inventoryDir := joinPath(dir, "inventory")
require.NoError(t, os.MkdirAll(inventoryDir, 0755))
path := joinPath(inventoryDir, "hosts.yml")
yaml := `---
all:
hosts:
web1:
ansible_host: 192.168.1.10
`
require.NoError(t, writeTestFile(path, []byte(yaml), 0644))
p := NewParser(dir)
inv, err := p.ParseInventory(inventoryDir)
require.NoError(t, err)
require.NotNil(t, inv.All)
require.Contains(t, inv.All.Hosts, "web1")
assert.Equal(t, "192.168.1.10", inv.All.Hosts["web1"].AnsibleHost)
}
func TestParser_ParseInventory_Good_WithGroups(t *testing.T) {
dir := t.TempDir()
path := joinPath(dir, "inventory.yml")