Templated include task paths per host
This commit is contained in:
parent
87cd890ea1
commit
c77a32f24f
2 changed files with 81 additions and 9 deletions
36
executor.go
36
executor.go
|
|
@ -1067,17 +1067,35 @@ func (e *Executor) runIncludeTasks(ctx context.Context, hosts []string, task *Ta
|
|||
path = task.ImportTasks
|
||||
}
|
||||
|
||||
// Resolve path relative to playbook
|
||||
path = e.templateString(path, "", nil)
|
||||
|
||||
tasks, err := e.parser.ParseTasks(path)
|
||||
if err != nil {
|
||||
return coreerr.E("Executor.runIncludeTasks", "include_tasks "+path, err)
|
||||
if path == "" || len(hosts) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, t := range tasks {
|
||||
if err := e.runTaskOnHosts(ctx, hosts, &t, play); err != nil {
|
||||
return err
|
||||
// Resolve the include path per host so host-specific vars can select a
|
||||
// different task file for each target.
|
||||
hostsByPath := make(map[string][]string)
|
||||
pathOrder := make([]string, 0, len(hosts))
|
||||
for _, host := range hosts {
|
||||
resolvedPath := e.templateString(path, host, task)
|
||||
if resolvedPath == "" {
|
||||
continue
|
||||
}
|
||||
if _, ok := hostsByPath[resolvedPath]; !ok {
|
||||
pathOrder = append(pathOrder, resolvedPath)
|
||||
}
|
||||
hostsByPath[resolvedPath] = append(hostsByPath[resolvedPath], host)
|
||||
}
|
||||
|
||||
for _, resolvedPath := range pathOrder {
|
||||
tasks, err := e.parser.ParseTasks(resolvedPath)
|
||||
if err != nil {
|
||||
return coreerr.E("Executor.runIncludeTasks", "include_tasks "+resolvedPath, err)
|
||||
}
|
||||
|
||||
for _, t := range tasks {
|
||||
if err := e.runTaskOnHosts(ctx, hostsByPath[resolvedPath], &t, play); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -657,6 +657,60 @@ func TestExecutorExtra_RunIncludeTasks_Good_RelativePath(t *testing.T) {
|
|||
assert.Contains(t, started, "localhost:Included second task")
|
||||
}
|
||||
|
||||
func TestExecutorExtra_RunIncludeTasks_Good_HostSpecificTemplate(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
|
||||
require.NoError(t, writeTestFile(joinPath(dir, "web.yml"), []byte(`- name: Web included task
|
||||
debug:
|
||||
msg: web
|
||||
`), 0644))
|
||||
require.NoError(t, writeTestFile(joinPath(dir, "db.yml"), []byte(`- name: DB included task
|
||||
debug:
|
||||
msg: db
|
||||
`), 0644))
|
||||
|
||||
gatherFacts := false
|
||||
play := &Play{
|
||||
Name: "Include host-specific tasks",
|
||||
Hosts: "all",
|
||||
Connection: "local",
|
||||
GatherFacts: &gatherFacts,
|
||||
}
|
||||
|
||||
e := NewExecutor(dir)
|
||||
e.SetInventoryDirect(&Inventory{
|
||||
All: &InventoryGroup{
|
||||
Hosts: map[string]*Host{
|
||||
"web1": {
|
||||
AnsibleConnection: "local",
|
||||
Vars: map[string]any{
|
||||
"include_file": "web.yml",
|
||||
},
|
||||
},
|
||||
"db1": {
|
||||
AnsibleConnection: "local",
|
||||
Vars: map[string]any{
|
||||
"include_file": "db.yml",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
var started []string
|
||||
e.OnTaskStart = func(host string, task *Task) {
|
||||
started = append(started, host+":"+task.Name)
|
||||
}
|
||||
|
||||
require.NoError(t, e.runTaskOnHosts(context.Background(), []string{"web1", "db1"}, &Task{
|
||||
Name: "Load host-specific tasks",
|
||||
IncludeTasks: "{{ include_file }}",
|
||||
}, play))
|
||||
|
||||
assert.Contains(t, started, "web1:Web included task")
|
||||
assert.Contains(t, started, "db1:DB included task")
|
||||
}
|
||||
|
||||
func TestExecutorExtra_GetHostsIter_Good(t *testing.T) {
|
||||
inv := &Inventory{
|
||||
All: &InventoryGroup{
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue