feat(ansible): honour check mode for mutating tasks
This commit is contained in:
parent
acf0a16349
commit
6fb5ebe920
2 changed files with 78 additions and 0 deletions
49
executor.go
49
executor.go
|
|
@ -338,6 +338,18 @@ func (e *Executor) runTaskOnHost(ctx context.Context, host string, task *Task, p
|
|||
}
|
||||
}
|
||||
|
||||
// Honour check mode for tasks that would mutate state.
|
||||
if e.CheckMode && !isCheckModeSafeTask(task) {
|
||||
result := &TaskResult{Skipped: true, Msg: "Skipped in check mode"}
|
||||
if task.Register != "" {
|
||||
e.results[host][task.Register] = result
|
||||
}
|
||||
if e.OnTaskEnd != nil {
|
||||
e.OnTaskEnd(host, task, result)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get SSH client
|
||||
client, err := e.getClient(host, play)
|
||||
if err != nil {
|
||||
|
|
@ -454,6 +466,43 @@ func (e *Executor) runLoop(ctx context.Context, host string, client *SSHClient,
|
|||
return nil
|
||||
}
|
||||
|
||||
// isCheckModeSafeTask reports whether a task can run without changing state
|
||||
// during check mode.
|
||||
func isCheckModeSafeTask(task *Task) bool {
|
||||
if task == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
if len(task.Block) > 0 || len(task.Rescue) > 0 || len(task.Always) > 0 {
|
||||
return true
|
||||
}
|
||||
if task.IncludeTasks != "" || task.ImportTasks != "" {
|
||||
return true
|
||||
}
|
||||
if task.IncludeRole != nil || task.ImportRole != nil {
|
||||
return true
|
||||
}
|
||||
|
||||
switch NormalizeModule(task.Module) {
|
||||
case "ansible.builtin.debug",
|
||||
"ansible.builtin.fail",
|
||||
"ansible.builtin.assert",
|
||||
"ansible.builtin.pause",
|
||||
"ansible.builtin.wait_for",
|
||||
"ansible.builtin.stat",
|
||||
"ansible.builtin.slurp",
|
||||
"ansible.builtin.include_vars",
|
||||
"ansible.builtin.meta",
|
||||
"ansible.builtin.set_fact",
|
||||
"ansible.builtin.add_host",
|
||||
"ansible.builtin.group_by",
|
||||
"ansible.builtin.setup":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// runBlock handles block/rescue/always.
|
||||
func (e *Executor) runBlock(ctx context.Context, hosts []string, task *Task, play *Play) error {
|
||||
var blockErr error
|
||||
|
|
|
|||
|
|
@ -206,6 +206,35 @@ func TestExecutor_RunTaskOnHosts_Good_RunOnceSharesRegisteredResult(t *testing.T
|
|||
assert.Equal(t, "hello", e.results["host2"]["debug_result"].Msg)
|
||||
}
|
||||
|
||||
// --- check mode ---
|
||||
|
||||
func TestExecutor_RunTaskOnHost_Good_CheckModeSkipsMutatingTask(t *testing.T) {
|
||||
e := NewExecutor("/tmp")
|
||||
e.CheckMode = true
|
||||
|
||||
var ended *TaskResult
|
||||
task := &Task{
|
||||
Name: "Run a shell command",
|
||||
Module: "shell",
|
||||
Args: map[string]any{"_raw_params": "echo hello"},
|
||||
Register: "shell_result",
|
||||
}
|
||||
|
||||
e.OnTaskEnd = func(_ string, _ *Task, result *TaskResult) {
|
||||
ended = result
|
||||
}
|
||||
|
||||
err := e.runTaskOnHost(context.Background(), "host1", task, &Play{})
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NotNil(t, ended)
|
||||
assert.True(t, ended.Skipped)
|
||||
assert.False(t, ended.Changed)
|
||||
assert.Equal(t, "Skipped in check mode", ended.Msg)
|
||||
require.NotNil(t, e.results["host1"]["shell_result"])
|
||||
assert.True(t, e.results["host1"]["shell_result"].Skipped)
|
||||
}
|
||||
|
||||
// --- normalizeConditions ---
|
||||
|
||||
func TestExecutor_NormalizeConditions_Good_String(t *testing.T) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue