feat(ansible): support meta end_role
Some checks are pending
CI / test (push) Waiting to run
CI / auto-fix (push) Waiting to run
CI / auto-merge (push) Waiting to run

This commit is contained in:
Virgil 2026-04-03 10:39:45 +00:00
parent 7d71ff21a4
commit 8f6bd48cf8
2 changed files with 50 additions and 0 deletions

View file

@ -25,6 +25,7 @@ import (
var errEndPlay = errors.New("end play")
var errEndHost = errors.New("end host")
var errEndBatch = errors.New("end batch")
var errEndRole = errors.New("end role")
var errTaskFailed = errors.New("task failed")
// sshExecutorClient is the client contract used by the executor.
@ -754,6 +755,10 @@ func (e *Executor) runRole(ctx context.Context, hosts []string, roleRef *RoleRef
effectiveTask.When = mergeConditions(inheritedWhen, effectiveTask.When)
}
if err := e.runTaskOnHosts(ctx, eligibleHosts, &effectiveTask, play); err != nil {
if errors.Is(err, errEndRole) {
e.vars = oldVars
return nil
}
// Restore vars
e.vars = oldVars
return err
@ -3629,6 +3634,8 @@ func (e *Executor) handleMetaAction(ctx context.Context, host string, hosts []st
case "reset_connection":
e.resetConnection(host)
return nil
case "end_role":
return errEndRole
default:
return nil
}

View file

@ -648,6 +648,49 @@ func TestExecutor_RunRole_Good_AppliesRoleTagsToTasks(t *testing.T) {
assert.Equal(t, "role ran", e.results["host1"]["role_result"].Msg)
}
func TestExecutor_RunRole_Good_MetaEndRoleStopsRemainingRoleTasks(t *testing.T) {
dir := t.TempDir()
roleTasks := `---
- name: before end_role
debug:
msg: before
register: before_result
- name: stop role
meta: end_role
- name: after end_role
debug:
msg: after
register: after_result
`
require.NoError(t, writeTestFile(joinPath(dir, "roles", "deploy", "tasks", "main.yml"), []byte(roleTasks), 0644))
e := NewExecutor(dir)
e.SetInventoryDirect(&Inventory{
All: &InventoryGroup{
Hosts: map[string]*Host{
"host1": {},
},
},
})
play := &Play{Connection: "local"}
var executed []string
e.OnTaskEnd = func(_ string, task *Task, _ *TaskResult) {
executed = append(executed, task.Name)
}
err := e.runRole(context.Background(), []string{"host1"}, &RoleRef{
Role: "deploy",
}, play, nil)
require.NoError(t, err)
assert.Equal(t, []string{"before end_role", "stop role"}, executed)
require.NotNil(t, e.results["host1"]["before_result"])
_, hasAfter := e.results["host1"]["after_result"]
assert.False(t, hasAfter)
}
func TestExecutor_RunRole_Good_AppliesRoleDefaultsAndVars(t *testing.T) {
dir := t.TempDir()