Fix include task variable inheritance

This commit is contained in:
Virgil 2026-04-01 22:00:12 +00:00
parent c77a32f24f
commit 3a4118ada8
2 changed files with 92 additions and 2 deletions

View file

@ -1093,7 +1093,9 @@ func (e *Executor) runIncludeTasks(ctx context.Context, hosts []string, task *Ta
}
for _, t := range tasks {
if err := e.runTaskOnHosts(ctx, hostsByPath[resolvedPath], &t, play); err != nil {
effectiveTask := t
effectiveTask.Vars = mergeTaskVars(task.Vars, t.Vars)
if err := e.runTaskOnHosts(ctx, hostsByPath[resolvedPath], &effectiveTask, play); err != nil {
return err
}
}
@ -1120,12 +1122,28 @@ func (e *Executor) runIncludeRole(ctx context.Context, hosts []string, task *Tas
roleRef := &RoleRef{
Role: roleName,
TasksFrom: tasksFrom,
Vars: roleVars,
Vars: mergeTaskVars(roleVars, task.Vars),
}
return e.runRole(ctx, hosts, roleRef, play)
}
// mergeTaskVars combines include-task vars with child task vars.
func mergeTaskVars(parent, child map[string]any) map[string]any {
if len(parent) == 0 && len(child) == 0 {
return nil
}
merged := make(map[string]any, len(parent)+len(child))
for k, v := range parent {
merged[k] = v
}
for k, v := range child {
merged[k] = v
}
return merged
}
// getHosts returns hosts matching the pattern.
func (e *Executor) getHosts(pattern string) []string {
if e.inventory == nil {

View file

@ -657,6 +657,37 @@ func TestExecutorExtra_RunIncludeTasks_Good_RelativePath(t *testing.T) {
assert.Contains(t, started, "localhost:Included second task")
}
func TestExecutorExtra_RunIncludeTasks_Good_InheritsTaskVars(t *testing.T) {
dir := t.TempDir()
includedPath := joinPath(dir, "included-vars.yml")
yaml := `- name: Included var task
debug:
msg: "{{ include_message }}"
register: included_result
`
require.NoError(t, writeTestFile(includedPath, []byte(yaml), 0644))
gatherFacts := false
play := &Play{
Name: "Include vars",
Hosts: "localhost",
GatherFacts: &gatherFacts,
Tasks: []Task{
{
Name: "Load included tasks",
IncludeTasks: "included-vars.yml",
Vars: map[string]any{"include_message": "hello from include"},
},
},
}
e := NewExecutor(dir)
require.NoError(t, e.runPlay(context.Background(), play))
require.NotNil(t, e.results["localhost"]["included_result"])
assert.Equal(t, "hello from include", e.results["localhost"]["included_result"].Msg)
}
func TestExecutorExtra_RunIncludeTasks_Good_HostSpecificTemplate(t *testing.T) {
dir := t.TempDir()
@ -711,6 +742,47 @@ func TestExecutorExtra_RunIncludeTasks_Good_HostSpecificTemplate(t *testing.T) {
assert.Contains(t, started, "db1:DB included task")
}
func TestExecutorExtra_RunIncludeRole_Good_InheritsTaskVars(t *testing.T) {
dir := t.TempDir()
require.NoError(t, writeTestFile(joinPath(dir, "roles", "demo", "tasks", "main.yml"), []byte(`---
- name: Role var task
debug:
msg: "{{ role_message }}"
register: role_result
`), 0644))
e := NewExecutor(dir)
e.SetInventoryDirect(&Inventory{
All: &InventoryGroup{
Hosts: map[string]*Host{
"localhost": {},
},
},
})
gatherFacts := false
play := &Play{
Hosts: "localhost",
Connection: "local",
GatherFacts: &gatherFacts,
}
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: "demo",
},
Vars: map[string]any{"role_message": "hello from role"},
}, play))
require.NotNil(t, e.results["localhost"]["role_result"])
assert.Equal(t, "hello from role", e.results["localhost"]["role_result"].Msg)
}
func TestExecutorExtra_GetHostsIter_Good(t *testing.T) {
inv := &Inventory{
All: &InventoryGroup{