diff --git a/executor.go b/executor.go index cb992d9..3a7f3d6 100644 --- a/executor.go +++ b/executor.go @@ -1720,6 +1720,9 @@ func (e *Executor) handleMetaAction(ctx context.Context, host string, hosts []st case "clear_facts": e.clearFacts(hosts) return nil + case "clear_host_errors": + e.clearHostErrors() + return nil case "end_play": return errEndPlay case "end_host": @@ -1743,6 +1746,15 @@ func (e *Executor) clearFacts(hosts []string) { } } +// clearHostErrors resets the current batch failure tracking so later tasks can +// proceed after a meta clear_host_errors action. +func (e *Executor) clearHostErrors() { + e.mu.Lock() + defer e.mu.Unlock() + + e.batchFailedHosts = make(map[string]bool) +} + // markHostEnded records that a host should be skipped for the rest of the play. func (e *Executor) markHostEnded(host string) { if host == "" { diff --git a/executor_test.go b/executor_test.go index 5035050..2790649 100644 --- a/executor_test.go +++ b/executor_test.go @@ -532,6 +532,21 @@ func TestExecutor_RunTaskOnHosts_Good_MetaFlushesHandlers(t *testing.T) { assert.Equal(t, []string{"change config", "flush handlers", "restart app"}, executed) } +func TestExecutor_HandleMetaAction_Good_ClearHostErrors(t *testing.T) { + e := NewExecutor("/tmp") + e.batchFailedHosts = map[string]bool{ + "host1": true, + "host2": true, + } + + result := &TaskResult{ + Data: map[string]any{"action": "clear_host_errors"}, + } + + require.NoError(t, e.handleMetaAction(context.Background(), "host1", []string{"host1", "host2"}, &Play{}, result)) + assert.Empty(t, e.batchFailedHosts) +} + func TestExecutor_RunPlay_Good_MetaEndPlayStopsRemainingTasks(t *testing.T) { e := NewExecutor("/tmp") e.SetInventoryDirect(&Inventory{