Skip to content

Commit

Permalink
execute multiple task through the command-line options
Browse files Browse the repository at this point in the history
  • Loading branch information
bakurin committed Jul 25, 2023
1 parent b3891e4 commit d9ebe8c
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 25 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ Spot supports the following command-line options:

- `-p`, `--playbook=`: Specifies the playbook file to be used. Defaults to `spot.yml`. You can also set the environment
variable `$SPOT_PLAYBOOK` to define the playbook file path.
- `--task=`: Specifies the task name to execute. The task should be defined in the playbook file.
- `--task=`: Specifies task names to execute. The task should be defined in the playbook file. Several tasks can be executed by providing the `--task` flag multiple times, e.g., `--task copy_files --task warmup_cache`.
If not specified all the tasks will be executed.
- `-t`, `--target=`: Specifies the target name to use for the task execution. The target should be defined in the playbook file and can represent remote hosts, inventory files, or inventory URLs. If not specified the `default` target will be used. User can pass a host name, group name, tag or IP instead of the target name for a quick override. Providing the `-t`, `--target` flag multiple times with different targets sets multiple destination targets or multiple hosts, e.g., `-t prod -t dev` or `-t example1.com -t example2.com`.
- `-c`, `--concurrent=`: Sets the number of concurrent hosts to execute tasks. Defaults to `1`, which means hosts will be handled sequentially.
Expand Down
23 changes: 14 additions & 9 deletions cmd/spot/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ type options struct {
} `positional-args:"yes" positional-optional:"yes"`

PlaybookFile string `short:"p" long:"playbook" env:"SPOT_PLAYBOOK" description:"playbook file" default:"spot.yml"`
TaskName string `long:"task" description:"task name"`
TaskNames []string `long:"task" description:"task name"`
Targets []string `short:"t" long:"target" description:"target name" default:"default"`
Concurrent int `short:"c" long:"concurrent" description:"concurrent tasks" default:"1"`
SSHTimeout time.Duration `long:"timeout" env:"SPOT_TIMEOUT" description:"ssh timeout" default:"30s"`
Expand Down Expand Up @@ -154,7 +154,7 @@ func run(opts options) error {
return runGen(opts, r)
}

if err := runTasks(ctx, opts.TaskName, opts.Targets, r); err != nil {
if err := runTasks(ctx, opts.TaskNames, opts.Targets, r); err != nil {
return err
}

Expand All @@ -163,12 +163,14 @@ func run(opts options) error {
}

// runTasks runs all tasks in playbook by default or a single task if specified in command line
func runTasks(ctx context.Context, taskName string, targets []string, r *runner.Process) error {
// run a single task if specified
if taskName != "" {
for _, targetName := range targetsForTask(targets, taskName, r.Playbook) {
if err := runTaskForTarget(ctx, r, taskName, targetName); err != nil {
return err
func runTasks(ctx context.Context, taskNames, targets []string, r *runner.Process) error {
// run specified tasks if there is any
if len(taskNames) > 0 {
for _, taskName := range taskNames {
for _, targetName := range targetsForTask(targets, taskName, r.Playbook) {
if err := runTaskForTarget(ctx, r, taskName, targetName); err != nil {
return err
}
}
}
return nil
Expand Down Expand Up @@ -198,7 +200,10 @@ func runAdHoc(ctx context.Context, targets []string, r *runner.Process) error {

// runGen generates a destination report for the task's targets
func runGen(opts options, r *runner.Process) (err error) {
targets := targetsForTask(opts.Targets, opts.TaskName, r.Playbook)
var targets []string
for _, taskName := range opts.TaskNames {
targets = append(targets, targetsForTask(opts.Targets, taskName, r.Playbook)...)
}

var fh io.ReadCloser
if opts.GenTemplate != "" && opts.GenTemplate != "json" {
Expand Down
57 changes: 42 additions & 15 deletions cmd/spot/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func Test_runCompleted(t *testing.T) {
SSHUser: "test",
SSHKey: "testdata/test_ssh_key",
PlaybookFile: "testdata/conf.yml",
TaskName: "task1",
TaskNames: []string{"task1"},
Targets: []string{hostAndPort},
Only: []string{"wait"},
SecretsProvider: SecretsProvider{
Expand All @@ -61,7 +61,7 @@ func Test_runCompleted(t *testing.T) {
SSHUser: "test",
SSHKey: "testdata/test_ssh_key",
PlaybookFile: "testdata/conf.yml",
TaskName: "task1",
TaskNames: []string{"task1"},
Targets: []string{hostAndPort},
Only: []string{"copy configuration", "some command"},
SecretsProvider: SecretsProvider{
Expand All @@ -86,7 +86,7 @@ func Test_runCompleted(t *testing.T) {
SSHUser: "test",
SSHKey: "testdata/test_ssh_key",
PlaybookFile: "testdata/conf.yml",
TaskName: "task1",
TaskNames: []string{"task1"},
Targets: []string{hostAndPort},
Only: []string{"wait"},
Dry: true,
Expand Down Expand Up @@ -156,6 +156,33 @@ func Test_runAdhoc(t *testing.T) {
require.NoError(t, err)
}

func Test_runCompletedSeveralTasks(t *testing.T) {
hostAndPort, teardown := startTestContainer(t)
defer teardown()

opts := options{
SSHUser: "test",
SSHKey: "testdata/test_ssh_key",
PlaybookFile: "testdata/conf3.yml",
TaskNames: []string{"task1", "task2"},
Targets: []string{hostAndPort},
Dbg: true,
}
setupLog(true)

wr := &bytes.Buffer{}
log.SetOutput(wr)

st := time.Now()
err := run(opts)
t.Log("dbg: ", wr.String())
require.NoError(t, err)
assert.True(t, time.Since(st) >= 1*time.Second)
assert.Contains(t, wr.String(), "task 1 command 1")
assert.Contains(t, wr.String(), "task 2 command 1")
assert.NotContains(t, wr.String(), "task 3 command 1")
}

func Test_runCompletedAllTasks(t *testing.T) {
hostAndPort, teardown := startTestContainer(t)
defer teardown()
Expand Down Expand Up @@ -193,7 +220,7 @@ func Test_runCanceled(t *testing.T) {
SSHUser: "test",
SSHKey: "testdata/test_ssh_key",
PlaybookFile: "testdata/conf.yml",
TaskName: "task1",
TaskNames: []string{"task1"},
Targets: []string{hostAndPort},
Only: []string{"wait"},
SecretsProvider: SecretsProvider{
Expand Down Expand Up @@ -222,7 +249,7 @@ func Test_runFailed(t *testing.T) {
SSHUser: "test",
SSHKey: "testdata/test_ssh_key",
PlaybookFile: "testdata/conf-local-failed.yml",
TaskName: "default",
TaskNames: []string{"default"},
Targets: []string{hostAndPort},
}
setupLog(true)
Expand All @@ -235,7 +262,7 @@ func Test_runNoConfig(t *testing.T) {
SSHUser: "test",
SSHKey: "testdata/test_ssh_key",
PlaybookFile: "testdata/conf-not-found.yml",
TaskName: "task1",
TaskNames: []string{"task1"},
Targets: []string{"localhost"},
Only: []string{"wait"},
}
Expand All @@ -249,7 +276,7 @@ func Test_runGen_goTmplFile(t *testing.T) {
SSHUser: "test",
SSHKey: "testdata/test_ssh_key",
PlaybookFile: "testdata/conf.yml",
TaskName: "task1",
TaskNames: []string{"task1"},
Targets: []string{"dev"},
SecretsProvider: SecretsProvider{
Provider: "spot",
Expand Down Expand Up @@ -282,7 +309,7 @@ func Test_connectFailed(t *testing.T) {
SSHUser: "bad_user",
SSHKey: "testdata/test_ssh_key",
PlaybookFile: "testdata/conf.yml",
TaskName: "task1",
TaskNames: []string{"task1"},
Targets: []string{hostAndPort},
SecretsProvider: SecretsProvider{
Provider: "spot",
Expand Down Expand Up @@ -321,9 +348,9 @@ func Test_sshUserAndKey(t *testing.T) {
{
name: "command line overrides all",
opts: options{
TaskName: "test_task",
SSHUser: "cmd_user",
SSHKey: "cmd_key",
TaskNames: []string{"test_task"},
SSHUser: "cmd_user",
SSHKey: "cmd_key",
},
conf: config.PlayBook{
User: "default_user",
Expand All @@ -338,7 +365,7 @@ func Test_sshUserAndKey(t *testing.T) {
{
name: "no user or key in playbook and no in command line",
opts: options{
TaskName: "test_task",
TaskNames: []string{"test_task"},
},
conf: config.PlayBook{
Tasks: []config.Task{
Expand All @@ -351,9 +378,9 @@ func Test_sshUserAndKey(t *testing.T) {
{
name: "tilde expansion in key path",
opts: options{
TaskName: "test_task",
SSHUser: "cmd_user",
SSHKey: "~/cmd_key",
TaskNames: []string{"test_task"},
SSHUser: "cmd_user",
SSHKey: "~/cmd_key",
},
conf: config.PlayBook{
User: "default_user",
Expand Down
22 changes: 22 additions & 0 deletions cmd/spot/testdata/conf3.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
targets:
remark42:
hosts: [{ host: "h1.example.com" }]

tasks:

- name: task1
commands:
- name: wait
script: sleep 1s
- name: good command
script: echo task 1 command 1

- name: task2
commands:
- name: good command
script: echo task 2 command 1

- name: task3
commands:
- name: good command
script: echo task 3 command 1

0 comments on commit d9ebe8c

Please sign in to comment.