Support custom role defaults and vars files
This commit is contained in:
parent
187f157435
commit
2e54726977
6 changed files with 111 additions and 24 deletions
16
executor.go
16
executor.go
|
|
@ -431,7 +431,7 @@ func (e *Executor) runRole(ctx context.Context, hosts []string, roleRef *RoleRef
|
|||
oldVars[k] = v
|
||||
}
|
||||
|
||||
tasks, defaults, roleVars, err := e.parser.loadRoleData(roleRef.Role, roleRef.TasksFrom)
|
||||
tasks, defaults, roleVars, err := e.parser.loadRoleData(roleRef.Role, roleRef.TasksFrom, roleRef.DefaultsFrom, roleRef.VarsFrom)
|
||||
if err != nil {
|
||||
e.vars = oldVars
|
||||
return coreerr.E("executor.runRole", sprintf("parse role %s", roleRef.Role), err)
|
||||
|
|
@ -1448,23 +1448,29 @@ func (e *Executor) runIncludeTasks(ctx context.Context, hosts []string, task *Ta
|
|||
|
||||
// runIncludeRole handles include_role/import_role.
|
||||
func (e *Executor) runIncludeRole(ctx context.Context, hosts []string, task *Task, play *Play) error {
|
||||
var roleName, tasksFrom string
|
||||
var roleName, tasksFrom, defaultsFrom, varsFrom string
|
||||
var roleVars map[string]any
|
||||
|
||||
if task.IncludeRole != nil {
|
||||
roleName = task.IncludeRole.Name
|
||||
tasksFrom = task.IncludeRole.TasksFrom
|
||||
defaultsFrom = task.IncludeRole.DefaultsFrom
|
||||
varsFrom = task.IncludeRole.VarsFrom
|
||||
roleVars = task.IncludeRole.Vars
|
||||
} else {
|
||||
roleName = task.ImportRole.Name
|
||||
tasksFrom = task.ImportRole.TasksFrom
|
||||
defaultsFrom = task.ImportRole.DefaultsFrom
|
||||
varsFrom = task.ImportRole.VarsFrom
|
||||
roleVars = task.ImportRole.Vars
|
||||
}
|
||||
|
||||
roleRef := &RoleRef{
|
||||
Role: roleName,
|
||||
TasksFrom: tasksFrom,
|
||||
Vars: mergeTaskVars(roleVars, task.Vars),
|
||||
Role: roleName,
|
||||
TasksFrom: tasksFrom,
|
||||
DefaultsFrom: defaultsFrom,
|
||||
VarsFrom: varsFrom,
|
||||
Vars: mergeTaskVars(roleVars, task.Vars),
|
||||
}
|
||||
|
||||
return e.runRole(ctx, hosts, roleRef, play)
|
||||
|
|
|
|||
|
|
@ -770,9 +770,11 @@ func TestExecutorExtra_RunIncludeRole_Good_InheritsTaskVars(t *testing.T) {
|
|||
require.NoError(t, e.runTaskOnHosts(context.Background(), []string{"localhost"}, &Task{
|
||||
Name: "Load role",
|
||||
IncludeRole: &struct {
|
||||
Name string `yaml:"name"`
|
||||
TasksFrom string `yaml:"tasks_from,omitempty"`
|
||||
Vars map[string]any `yaml:"vars,omitempty"`
|
||||
Name string `yaml:"name"`
|
||||
TasksFrom string `yaml:"tasks_from,omitempty"`
|
||||
DefaultsFrom string `yaml:"defaults_from,omitempty"`
|
||||
VarsFrom string `yaml:"vars_from,omitempty"`
|
||||
Vars map[string]any `yaml:"vars,omitempty"`
|
||||
}{
|
||||
Name: "demo",
|
||||
},
|
||||
|
|
|
|||
|
|
@ -527,6 +527,52 @@ role_value: vars-value
|
|||
assert.False(t, leaked)
|
||||
}
|
||||
|
||||
func TestExecutor_RunRole_Good_UsesCustomRoleDefaultsAndVarsFiles(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
|
||||
require.NoError(t, writeTestFile(joinPath(dir, "roles", "webserver", "tasks", "main.yml"), []byte(`---
|
||||
- name: role file selector task
|
||||
debug:
|
||||
msg: "{{ role_value }}|{{ role_param }}"
|
||||
register: role_result
|
||||
`), 0644))
|
||||
require.NoError(t, writeTestFile(joinPath(dir, "roles", "webserver", "defaults", "main.yml"), []byte(`---
|
||||
role_value: default-main
|
||||
`), 0644))
|
||||
require.NoError(t, writeTestFile(joinPath(dir, "roles", "webserver", "defaults", "custom.yml"), []byte(`---
|
||||
role_value: default-custom
|
||||
`), 0644))
|
||||
require.NoError(t, writeTestFile(joinPath(dir, "roles", "webserver", "vars", "main.yml"), []byte(`---
|
||||
role_value: vars-main
|
||||
`), 0644))
|
||||
require.NoError(t, writeTestFile(joinPath(dir, "roles", "webserver", "vars", "custom.yml"), []byte(`---
|
||||
role_value: vars-custom
|
||||
`), 0644))
|
||||
|
||||
e := NewExecutor(dir)
|
||||
e.SetInventoryDirect(&Inventory{
|
||||
All: &InventoryGroup{
|
||||
Hosts: map[string]*Host{
|
||||
"host1": {},
|
||||
},
|
||||
},
|
||||
})
|
||||
e.clients["host1"] = NewMockSSHClient()
|
||||
|
||||
err := e.runRole(context.Background(), []string{"host1"}, &RoleRef{
|
||||
Role: "webserver",
|
||||
DefaultsFrom: "custom.yml",
|
||||
VarsFrom: "custom.yml",
|
||||
Vars: map[string]any{
|
||||
"role_param": "include-value",
|
||||
},
|
||||
}, &Play{Connection: "local"})
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NotNil(t, e.results["host1"]["role_result"])
|
||||
assert.Equal(t, "vars-custom|include-value", e.results["host1"]["role_result"].Msg)
|
||||
}
|
||||
|
||||
func TestExecutor_RunPlay_Good_AppliesPlayTagsToTasks(t *testing.T) {
|
||||
e := NewExecutor("/tmp")
|
||||
e.Tags = []string{"deploy"}
|
||||
|
|
|
|||
14
parser.go
14
parser.go
|
|
@ -191,14 +191,20 @@ func (p *Parser) ParseTasksIter(path string) (iter.Seq[Task], error) {
|
|||
//
|
||||
// tasks, err := parser.ParseRole("nginx", "main.yml")
|
||||
func (p *Parser) ParseRole(name string, tasksFrom string) ([]Task, error) {
|
||||
tasks, _, _, err := p.loadRoleData(name, tasksFrom)
|
||||
tasks, _, _, err := p.loadRoleData(name, tasksFrom, "", "")
|
||||
return tasks, err
|
||||
}
|
||||
|
||||
func (p *Parser) loadRoleData(name string, tasksFrom string) ([]Task, map[string]any, map[string]any, error) {
|
||||
func (p *Parser) loadRoleData(name string, tasksFrom string, defaultsFrom string, varsFrom string) ([]Task, map[string]any, map[string]any, error) {
|
||||
if tasksFrom == "" {
|
||||
tasksFrom = "main.yml"
|
||||
}
|
||||
if defaultsFrom == "" {
|
||||
defaultsFrom = "main.yml"
|
||||
}
|
||||
if varsFrom == "" {
|
||||
varsFrom = "main.yml"
|
||||
}
|
||||
|
||||
// Search paths for roles (in order of precedence)
|
||||
searchPaths := []string{
|
||||
|
|
@ -230,7 +236,7 @@ func (p *Parser) loadRoleData(name string, tasksFrom string) ([]Task, map[string
|
|||
|
||||
defaults := make(map[string]any)
|
||||
// Load role defaults
|
||||
defaultsPath := joinPath(pathDir(pathDir(tasksPath)), "defaults", "main.yml")
|
||||
defaultsPath := joinPath(pathDir(pathDir(tasksPath)), "defaults", defaultsFrom)
|
||||
if data, err := coreio.Local.Read(defaultsPath); err == nil {
|
||||
if yaml.Unmarshal([]byte(data), &defaults) != nil {
|
||||
defaults = make(map[string]any)
|
||||
|
|
@ -239,7 +245,7 @@ func (p *Parser) loadRoleData(name string, tasksFrom string) ([]Task, map[string
|
|||
|
||||
roleVars := make(map[string]any)
|
||||
// Load role vars
|
||||
varsPath := joinPath(pathDir(pathDir(tasksPath)), "vars", "main.yml")
|
||||
varsPath := joinPath(pathDir(pathDir(tasksPath)), "vars", varsFrom)
|
||||
if data, err := coreio.Local.Read(varsPath); err == nil {
|
||||
if yaml.Unmarshal([]byte(data), &roleVars) != nil {
|
||||
roleVars = make(map[string]any)
|
||||
|
|
|
|||
30
types.go
30
types.go
|
|
@ -45,12 +45,14 @@ type Play struct {
|
|||
//
|
||||
// role := RoleRef{Role: "nginx", TasksFrom: "install.yml"}
|
||||
type RoleRef struct {
|
||||
Role string `yaml:"role,omitempty"`
|
||||
Name string `yaml:"name,omitempty"` // Alternative to role
|
||||
TasksFrom string `yaml:"tasks_from,omitempty"`
|
||||
Vars map[string]any `yaml:"vars,omitempty"`
|
||||
When any `yaml:"when,omitempty"`
|
||||
Tags []string `yaml:"tags,omitempty"`
|
||||
Role string `yaml:"role,omitempty"`
|
||||
Name string `yaml:"name,omitempty"` // Alternative to role
|
||||
TasksFrom string `yaml:"tasks_from,omitempty"`
|
||||
DefaultsFrom string `yaml:"defaults_from,omitempty"`
|
||||
VarsFrom string `yaml:"vars_from,omitempty"`
|
||||
Vars map[string]any `yaml:"vars,omitempty"`
|
||||
When any `yaml:"when,omitempty"`
|
||||
Tags []string `yaml:"tags,omitempty"`
|
||||
}
|
||||
|
||||
// UnmarshalYAML handles both string and struct role refs.
|
||||
|
|
@ -120,14 +122,18 @@ type Task struct {
|
|||
WithFileGlob any `yaml:"with_fileglob,omitempty"`
|
||||
WithSequence any `yaml:"with_sequence,omitempty"`
|
||||
IncludeRole *struct {
|
||||
Name string `yaml:"name"`
|
||||
TasksFrom string `yaml:"tasks_from,omitempty"`
|
||||
Vars map[string]any `yaml:"vars,omitempty"`
|
||||
Name string `yaml:"name"`
|
||||
TasksFrom string `yaml:"tasks_from,omitempty"`
|
||||
DefaultsFrom string `yaml:"defaults_from,omitempty"`
|
||||
VarsFrom string `yaml:"vars_from,omitempty"`
|
||||
Vars map[string]any `yaml:"vars,omitempty"`
|
||||
} `yaml:"include_role,omitempty"`
|
||||
ImportRole *struct {
|
||||
Name string `yaml:"name"`
|
||||
TasksFrom string `yaml:"tasks_from,omitempty"`
|
||||
Vars map[string]any `yaml:"vars,omitempty"`
|
||||
Name string `yaml:"name"`
|
||||
TasksFrom string `yaml:"tasks_from,omitempty"`
|
||||
DefaultsFrom string `yaml:"defaults_from,omitempty"`
|
||||
VarsFrom string `yaml:"vars_from,omitempty"`
|
||||
Vars map[string]any `yaml:"vars,omitempty"`
|
||||
} `yaml:"import_role,omitempty"`
|
||||
|
||||
// Raw YAML for module extraction
|
||||
|
|
|
|||
|
|
@ -63,6 +63,23 @@ when: ansible_os_family == "Debian"
|
|||
assert.NotNil(t, ref.When)
|
||||
}
|
||||
|
||||
func TestTypes_RoleRef_UnmarshalYAML_Good_CustomRoleFiles(t *testing.T) {
|
||||
input := `
|
||||
name: web
|
||||
tasks_from: setup.yml
|
||||
defaults_from: custom-defaults.yml
|
||||
vars_from: custom-vars.yml
|
||||
`
|
||||
var ref RoleRef
|
||||
err := yaml.Unmarshal([]byte(input), &ref)
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "web", ref.Role)
|
||||
assert.Equal(t, "setup.yml", ref.TasksFrom)
|
||||
assert.Equal(t, "custom-defaults.yml", ref.DefaultsFrom)
|
||||
assert.Equal(t, "custom-vars.yml", ref.VarsFrom)
|
||||
}
|
||||
|
||||
// --- Task UnmarshalYAML ---
|
||||
|
||||
func TestTypes_Task_UnmarshalYAML_Good_ModuleWithArgs(t *testing.T) {
|
||||
|
|
@ -446,6 +463,8 @@ name: Include role
|
|||
include_role:
|
||||
name: common
|
||||
tasks_from: setup.yml
|
||||
defaults_from: defaults.yml
|
||||
vars_from: vars.yml
|
||||
`
|
||||
var task Task
|
||||
err := yaml.Unmarshal([]byte(input), &task)
|
||||
|
|
@ -454,6 +473,8 @@ include_role:
|
|||
require.NotNil(t, task.IncludeRole)
|
||||
assert.Equal(t, "common", task.IncludeRole.Name)
|
||||
assert.Equal(t, "setup.yml", task.IncludeRole.TasksFrom)
|
||||
assert.Equal(t, "defaults.yml", task.IncludeRole.DefaultsFrom)
|
||||
assert.Equal(t, "vars.yml", task.IncludeRole.VarsFrom)
|
||||
}
|
||||
|
||||
func TestTypes_Task_UnmarshalYAML_Good_BecomeFields(t *testing.T) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue