diff --git a/executor.go b/executor.go index b8319b2..f1ebe83 100644 --- a/executor.go +++ b/executor.go @@ -414,6 +414,10 @@ func (e *Executor) runLoop(ctx context.Context, host string, client *SSHClient, if result.Failed && !task.IgnoreErrors { break } + + if task.LoopControl != nil && task.LoopControl.Pause > 0 && i < len(items)-1 { + time.Sleep(time.Duration(task.LoopControl.Pause) * time.Second) + } } // Restore loop variables diff --git a/executor_test.go b/executor_test.go index 8dfe40e..002af3f 100644 --- a/executor_test.go +++ b/executor_test.go @@ -3,6 +3,7 @@ package ansible import ( "context" "testing" + "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -137,6 +138,25 @@ func TestExecutor_RunPlay_Good_SerialBatchesHosts(t *testing.T) { }, gathered) } +func TestExecutor_RunTaskOnHost_Good_LoopControlPause(t *testing.T) { + e := NewExecutor("/tmp") + task := &Task{ + Name: "pause loop", + Module: "debug", + Args: map[string]any{"msg": "{{ item }}"}, + Loop: []any{"one", "two"}, + LoopControl: &LoopControl{ + Pause: 1, + }, + } + play := &Play{} + + start := time.Now() + require.NoError(t, e.runTaskOnHost(context.Background(), "localhost", task, play)) + + assert.GreaterOrEqual(t, time.Since(start), 900*time.Millisecond) +} + // --- matchesTags --- func TestExecutor_MatchesTags_Good_NoTagsFilter(t *testing.T) { diff --git a/parser.go b/parser.go index b3ee17c..33b7458 100644 --- a/parser.go +++ b/parser.go @@ -415,11 +415,11 @@ func getAllHosts(group *InventoryGroup) []string { } var hosts []string - for name := range group.Hosts { + for _, name := range slices.Sorted(maps.Keys(group.Hosts)) { hosts = append(hosts, name) } - for _, child := range group.Children { - hosts = append(hosts, getAllHosts(child)...) + for _, name := range slices.Sorted(maps.Keys(group.Children)) { + hosts = append(hosts, getAllHosts(group.Children[name])...) } return hosts }