feat(ansible): support stdin for command and shell modules
Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
a475924e6f
commit
ce60a583f3
3 changed files with 66 additions and 0 deletions
|
|
@ -521,6 +521,10 @@ func moduleShellWithClient(_ *Executor, client sshRunner, args map[string]any) (
|
|||
cmd = sprintf("cd %q && %s", chdir, cmd)
|
||||
}
|
||||
|
||||
if stdin := getStringArg(args, "stdin", ""); stdin != "" {
|
||||
cmd = prefixCommandStdin(cmd, stdin, getBoolArg(args, "stdin_add_newline", true))
|
||||
}
|
||||
|
||||
stdout, stderr, rc, err := client.RunScript(context.Background(), cmd)
|
||||
if err != nil {
|
||||
return &TaskResult{Failed: true, Msg: err.Error(), Stdout: stdout, Stderr: stderr, RC: rc}, nil
|
||||
|
|
@ -545,6 +549,10 @@ func moduleCommandWithClient(_ *Executor, client sshRunner, args map[string]any)
|
|||
cmd = sprintf("cd %q && %s", chdir, cmd)
|
||||
}
|
||||
|
||||
if stdin := getStringArg(args, "stdin", ""); stdin != "" {
|
||||
cmd = prefixCommandStdin(cmd, stdin, getBoolArg(args, "stdin_add_newline", true))
|
||||
}
|
||||
|
||||
stdout, stderr, rc, err := client.Run(context.Background(), cmd)
|
||||
if err != nil {
|
||||
return &TaskResult{Failed: true, Msg: err.Error()}, nil
|
||||
|
|
|
|||
23
modules.go
23
modules.go
|
|
@ -14,6 +14,7 @@ import (
|
|||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
coreio "dappco.re/go/core/io"
|
||||
|
|
@ -262,6 +263,10 @@ func (e *Executor) moduleShell(ctx context.Context, client sshExecutorClient, ar
|
|||
cmd = sprintf("cd %q && %s", chdir, cmd)
|
||||
}
|
||||
|
||||
if stdin := getStringArg(args, "stdin", ""); stdin != "" {
|
||||
cmd = prefixCommandStdin(cmd, stdin, getBoolArg(args, "stdin_add_newline", true))
|
||||
}
|
||||
|
||||
stdout, stderr, rc, err := client.RunScript(ctx, cmd)
|
||||
if err != nil {
|
||||
return &TaskResult{Failed: true, Msg: err.Error(), Stdout: stdout, Stderr: stderr, RC: rc}, nil
|
||||
|
|
@ -295,6 +300,10 @@ func (e *Executor) moduleCommand(ctx context.Context, client sshExecutorClient,
|
|||
cmd = sprintf("cd %q && %s", chdir, cmd)
|
||||
}
|
||||
|
||||
if stdin := getStringArg(args, "stdin", ""); stdin != "" {
|
||||
cmd = prefixCommandStdin(cmd, stdin, getBoolArg(args, "stdin_add_newline", true))
|
||||
}
|
||||
|
||||
stdout, stderr, rc, err := client.Run(ctx, cmd)
|
||||
if err != nil {
|
||||
return &TaskResult{Failed: true, Msg: err.Error()}, nil
|
||||
|
|
@ -1896,6 +1905,20 @@ func quoteArgs(values []string) []string {
|
|||
return quoted
|
||||
}
|
||||
|
||||
func prefixCommandStdin(cmd, stdin string, addNewline bool) string {
|
||||
if stdin == "" {
|
||||
return cmd
|
||||
}
|
||||
if addNewline {
|
||||
stdin += "\n"
|
||||
}
|
||||
return sprintf("printf %%s %s | %s", shellSingleQuote(stdin), cmd)
|
||||
}
|
||||
|
||||
func shellSingleQuote(value string) string {
|
||||
return "'" + strings.ReplaceAll(value, "'", `'"'"'`) + "'"
|
||||
}
|
||||
|
||||
// --- Helpers ---
|
||||
|
||||
func getStringArg(args map[string]any, key, def string) string {
|
||||
|
|
|
|||
|
|
@ -256,6 +256,25 @@ func TestModulesCmd_ModuleCommand_Good_WithChdir(t *testing.T) {
|
|||
assert.Contains(t, last.Cmd, "ls")
|
||||
}
|
||||
|
||||
func TestModulesCmd_ModuleCommand_Good_WithStdin(t *testing.T) {
|
||||
e, mock := newTestExecutorWithMock("host1")
|
||||
mock.expectCommand("cat", "input\n", "", 0)
|
||||
|
||||
result, err := moduleCommandWithClient(e, mock, map[string]any{
|
||||
"_raw_params": "cat",
|
||||
"stdin": "payload",
|
||||
})
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.True(t, result.Changed)
|
||||
assert.Equal(t, "input\n", result.Stdout)
|
||||
last := mock.lastCommand()
|
||||
assert.Equal(t, "Run", last.Method)
|
||||
assert.Contains(t, last.Cmd, "printf %s")
|
||||
assert.Contains(t, last.Cmd, "| cat")
|
||||
assert.Contains(t, last.Cmd, "payload\n")
|
||||
}
|
||||
|
||||
func TestModulesCmd_ModuleCommand_Bad_NoCommand(t *testing.T) {
|
||||
e, _ := newTestExecutorWithMock("host1")
|
||||
mock := NewMockSSHClient()
|
||||
|
|
@ -705,6 +724,22 @@ func TestModulesCmd_ModuleDifferentiation_Good_ShellUsesRunScript(t *testing.T)
|
|||
assert.Equal(t, "RunScript", cmds[0].Method, "shell module must use RunScript()")
|
||||
}
|
||||
|
||||
func TestModulesCmd_ModuleDifferentiation_Good_ShellWithStdinStillUsesRunScript(t *testing.T) {
|
||||
e, mock := newTestExecutorWithMock("host1")
|
||||
mock.expectCommand("echo test", "test\n", "", 0)
|
||||
|
||||
_, _ = moduleShellWithClient(e, mock, map[string]any{
|
||||
"_raw_params": "echo test",
|
||||
"stdin": "payload",
|
||||
})
|
||||
|
||||
cmds := mock.executedCommands()
|
||||
require.Len(t, cmds, 1)
|
||||
assert.Equal(t, "RunScript", cmds[0].Method, "shell module must still use RunScript()")
|
||||
assert.Contains(t, cmds[0].Cmd, "printf %s")
|
||||
assert.Contains(t, cmds[0].Cmd, "| echo test")
|
||||
}
|
||||
|
||||
func TestModulesCmd_ModuleDifferentiation_Good_RawUsesRun(t *testing.T) {
|
||||
e, mock := newTestExecutorWithMock("host1")
|
||||
mock.expectCommand("echo test", "test\n", "", 0)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue