fix(ansible): implement include_vars loading
This commit is contained in:
parent
35b0cf03d9
commit
34229558fb
3 changed files with 161 additions and 9 deletions
|
|
@ -150,19 +150,31 @@ func TestExecutorExtra_ModuleSetFact_Good_SkipsCacheable(t *testing.T) {
|
|||
// --- moduleIncludeVars ---
|
||||
|
||||
func TestExecutorExtra_ModuleIncludeVars_Good_WithFile(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
path := joinPath(dir, "main.yml")
|
||||
require.NoError(t, writeTestFile(path, []byte("app_name: demo\n"), 0644))
|
||||
|
||||
e := NewExecutor("/tmp")
|
||||
result, err := e.moduleIncludeVars(map[string]any{"file": "vars/main.yml"})
|
||||
result, err := e.moduleIncludeVars(map[string]any{"file": path})
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.Contains(t, result.Msg, "vars/main.yml")
|
||||
assert.True(t, result.Changed)
|
||||
assert.Contains(t, result.Msg, path)
|
||||
assert.Equal(t, "demo", e.vars["app_name"])
|
||||
}
|
||||
|
||||
func TestExecutorExtra_ModuleIncludeVars_Good_WithRawParams(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
path := joinPath(dir, "defaults.yml")
|
||||
require.NoError(t, writeTestFile(path, []byte("app_port: 8080\n"), 0644))
|
||||
|
||||
e := NewExecutor("/tmp")
|
||||
result, err := e.moduleIncludeVars(map[string]any{"_raw_params": "defaults.yml"})
|
||||
result, err := e.moduleIncludeVars(map[string]any{"_raw_params": path})
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.Contains(t, result.Msg, "defaults.yml")
|
||||
assert.True(t, result.Changed)
|
||||
assert.Contains(t, result.Msg, path)
|
||||
assert.Equal(t, 8080, e.vars["app_port"])
|
||||
}
|
||||
|
||||
func TestExecutorExtra_ModuleIncludeVars_Good_Empty(t *testing.T) {
|
||||
|
|
|
|||
99
modules.go
99
modules.go
|
|
@ -4,10 +4,14 @@ import (
|
|||
"context"
|
||||
"encoding/base64"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strconv"
|
||||
|
||||
coreio "dappco.re/go/core/io"
|
||||
coreerr "dappco.re/go/core/log"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// executeModule dispatches to the appropriate module handler.
|
||||
|
|
@ -1261,14 +1265,99 @@ func (e *Executor) moduleIncludeVars(args map[string]any) (*TaskResult, error) {
|
|||
if file == "" {
|
||||
file = getStringArg(args, "_raw_params", "")
|
||||
}
|
||||
dir := getStringArg(args, "dir", "")
|
||||
name := getStringArg(args, "name", "")
|
||||
hashBehaviour := lower(getStringArg(args, "hash_behaviour", "replace"))
|
||||
|
||||
if file != "" {
|
||||
// Would need to read and parse the vars file
|
||||
// For now, just acknowledge
|
||||
return &TaskResult{Changed: false, Msg: "include_vars: " + file}, nil
|
||||
if file == "" && dir == "" {
|
||||
return &TaskResult{Changed: false}, nil
|
||||
}
|
||||
|
||||
return &TaskResult{Changed: false}, nil
|
||||
loaded := make(map[string]any)
|
||||
var sources []string
|
||||
loadFile := func(path string) error {
|
||||
data, err := coreio.Local.Read(path)
|
||||
if err != nil {
|
||||
return coreerr.E("Executor.moduleIncludeVars", "read vars file", err)
|
||||
}
|
||||
|
||||
var vars map[string]any
|
||||
if err := yaml.Unmarshal([]byte(data), &vars); err != nil {
|
||||
return coreerr.E("Executor.moduleIncludeVars", "parse vars file", err)
|
||||
}
|
||||
|
||||
mergeVars(loaded, vars, hashBehaviour == "merge")
|
||||
return nil
|
||||
}
|
||||
|
||||
if file != "" {
|
||||
sources = append(sources, file)
|
||||
if err := loadFile(file); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if dir != "" {
|
||||
entries, err := os.ReadDir(dir)
|
||||
if err != nil {
|
||||
return nil, coreerr.E("Executor.moduleIncludeVars", "read vars dir", err)
|
||||
}
|
||||
|
||||
var files []string
|
||||
for _, entry := range entries {
|
||||
if entry.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
ext := lower(filepath.Ext(entry.Name()))
|
||||
if ext == ".yml" || ext == ".yaml" {
|
||||
files = append(files, joinPath(dir, entry.Name()))
|
||||
}
|
||||
}
|
||||
sort.Strings(files)
|
||||
|
||||
for _, path := range files {
|
||||
sources = append(sources, path)
|
||||
if err := loadFile(path); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if name != "" {
|
||||
e.vars[name] = loaded
|
||||
} else {
|
||||
mergeVars(e.vars, loaded, hashBehaviour == "merge")
|
||||
}
|
||||
|
||||
msg := "include_vars"
|
||||
if len(sources) > 0 {
|
||||
msg += ": " + join(", ", sources)
|
||||
}
|
||||
|
||||
return &TaskResult{Changed: true, Msg: msg}, nil
|
||||
}
|
||||
|
||||
func mergeVars(dst, src map[string]any, mergeMaps bool) {
|
||||
if dst == nil || src == nil {
|
||||
return
|
||||
}
|
||||
|
||||
for key, val := range src {
|
||||
if !mergeMaps {
|
||||
dst[key] = val
|
||||
continue
|
||||
}
|
||||
|
||||
if existing, ok := dst[key].(map[string]any); ok {
|
||||
if next, ok := val.(map[string]any); ok {
|
||||
mergeVars(existing, next, true)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
dst[key] = val
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Executor) moduleMeta(args map[string]any) (*TaskResult, error) {
|
||||
|
|
|
|||
|
|
@ -702,6 +702,57 @@ func TestModulesAdv_ModuleUnarchive_Bad_LocalFileNotFound(t *testing.T) {
|
|||
assert.Contains(t, err.Error(), "read src")
|
||||
}
|
||||
|
||||
// --- include_vars module ---
|
||||
|
||||
func TestModulesAdv_ModuleIncludeVars_Good_LoadSingleFile(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
varsPath := joinPath(dir, "vars.yml")
|
||||
require.NoError(t, writeTestFile(varsPath, []byte("app_name: demo\napp_port: 8080\nnested:\n enabled: true\n"), 0644))
|
||||
|
||||
e := NewExecutor("/tmp")
|
||||
|
||||
result, err := e.moduleIncludeVars(map[string]any{
|
||||
"file": varsPath,
|
||||
})
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.True(t, result.Changed)
|
||||
assert.False(t, result.Failed)
|
||||
assert.Contains(t, result.Msg, varsPath)
|
||||
assert.Equal(t, "demo", e.vars["app_name"])
|
||||
assert.Equal(t, 8080, e.vars["app_port"])
|
||||
|
||||
nested, ok := e.vars["nested"].(map[string]any)
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, true, nested["enabled"])
|
||||
}
|
||||
|
||||
func TestModulesAdv_ModuleIncludeVars_Good_LoadDirectoryWithMerge(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
require.NoError(t, writeTestFile(joinPath(dir, "01-base.yml"), []byte("app_name: demo\nnested:\n a: 1\n"), 0644))
|
||||
require.NoError(t, writeTestFile(joinPath(dir, "02-override.yaml"), []byte("app_port: 8080\nnested:\n b: 2\n"), 0644))
|
||||
|
||||
e := NewExecutor("/tmp")
|
||||
|
||||
result, err := e.moduleIncludeVars(map[string]any{
|
||||
"dir": dir,
|
||||
"hash_behaviour": "merge",
|
||||
})
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.True(t, result.Changed)
|
||||
assert.False(t, result.Failed)
|
||||
assert.Contains(t, result.Msg, joinPath(dir, "01-base.yml"))
|
||||
assert.Contains(t, result.Msg, joinPath(dir, "02-override.yaml"))
|
||||
assert.Equal(t, "demo", e.vars["app_name"])
|
||||
assert.Equal(t, 8080, e.vars["app_port"])
|
||||
|
||||
nested, ok := e.vars["nested"].(map[string]any)
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, 1, nested["a"])
|
||||
assert.Equal(t, 2, nested["b"])
|
||||
}
|
||||
|
||||
// --- uri module ---
|
||||
|
||||
func TestModulesAdv_ModuleURI_Good_GetRequestDefault(t *testing.T) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue