go-devops/ansible/modules_cmd_test.go
Snider 3330e55b2b test(ansible): Phase 1 Steps 1.0-1.1 — SSH mock + command module tests
Step 1.0: MockSSHClient with command registry, file system simulation,
become state tracking, execution log, upload log, and assertion helpers.
Module shims via sshRunner interface for testability.

Step 1.1: 48 tests for command/shell/raw/script modules verifying:
- command uses Run(), shell uses RunScript()
- chdir wrapping, non-zero RC, SSH error propagation
- raw passes through without shell wrapping
- script reads local file content, sends via RunScript()
- Cross-module dispatch differentiation
- Template variable resolution in args

Co-Authored-By: Virgil <virgil@lethean.io>
2026-02-20 02:31:48 +00:00

722 lines
20 KiB
Go

package ansible
import (
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// ============================================================
// Step 1.1: command / shell / raw / script module tests
// ============================================================
// --- MockSSHClient basic tests ---
func TestMockSSHClient_Good_RunRecordsExecution(t *testing.T) {
mock := NewMockSSHClient()
mock.expectCommand("echo hello", "hello\n", "", 0)
stdout, stderr, rc, err := mock.Run(nil, "echo hello")
assert.NoError(t, err)
assert.Equal(t, "hello\n", stdout)
assert.Equal(t, "", stderr)
assert.Equal(t, 0, rc)
assert.Equal(t, 1, mock.commandCount())
assert.Equal(t, "Run", mock.lastCommand().Method)
assert.Equal(t, "echo hello", mock.lastCommand().Cmd)
}
func TestMockSSHClient_Good_RunScriptRecordsExecution(t *testing.T) {
mock := NewMockSSHClient()
mock.expectCommand("set -e", "ok", "", 0)
stdout, _, rc, err := mock.RunScript(nil, "set -e\necho done")
assert.NoError(t, err)
assert.Equal(t, "ok", stdout)
assert.Equal(t, 0, rc)
assert.Equal(t, 1, mock.commandCount())
assert.Equal(t, "RunScript", mock.lastCommand().Method)
}
func TestMockSSHClient_Good_DefaultSuccessResponse(t *testing.T) {
mock := NewMockSSHClient()
// No expectations registered — should return empty success
stdout, stderr, rc, err := mock.Run(nil, "anything")
assert.NoError(t, err)
assert.Equal(t, "", stdout)
assert.Equal(t, "", stderr)
assert.Equal(t, 0, rc)
}
func TestMockSSHClient_Good_LastMatchWins(t *testing.T) {
mock := NewMockSSHClient()
mock.expectCommand("echo", "first", "", 0)
mock.expectCommand("echo", "second", "", 0)
stdout, _, _, _ := mock.Run(nil, "echo hello")
assert.Equal(t, "second", stdout)
}
func TestMockSSHClient_Good_FileOperations(t *testing.T) {
mock := NewMockSSHClient()
// File does not exist initially
exists, err := mock.FileExists(nil, "/etc/config")
assert.NoError(t, err)
assert.False(t, exists)
// Add file
mock.addFile("/etc/config", []byte("key=value"))
// Now it exists
exists, err = mock.FileExists(nil, "/etc/config")
assert.NoError(t, err)
assert.True(t, exists)
// Download it
content, err := mock.Download(nil, "/etc/config")
assert.NoError(t, err)
assert.Equal(t, []byte("key=value"), content)
// Download non-existent file
_, err = mock.Download(nil, "/nonexistent")
assert.Error(t, err)
}
func TestMockSSHClient_Good_StatWithExplicit(t *testing.T) {
mock := NewMockSSHClient()
mock.addStat("/var/log", map[string]any{"exists": true, "isdir": true})
info, err := mock.Stat(nil, "/var/log")
assert.NoError(t, err)
assert.Equal(t, true, info["exists"])
assert.Equal(t, true, info["isdir"])
}
func TestMockSSHClient_Good_StatFallback(t *testing.T) {
mock := NewMockSSHClient()
mock.addFile("/etc/hosts", []byte("127.0.0.1 localhost"))
info, err := mock.Stat(nil, "/etc/hosts")
assert.NoError(t, err)
assert.Equal(t, true, info["exists"])
assert.Equal(t, false, info["isdir"])
info, err = mock.Stat(nil, "/nonexistent")
assert.NoError(t, err)
assert.Equal(t, false, info["exists"])
}
func TestMockSSHClient_Good_BecomeTracking(t *testing.T) {
mock := NewMockSSHClient()
assert.False(t, mock.become)
assert.Equal(t, "", mock.becomeUser)
mock.SetBecome(true, "root", "secret")
assert.True(t, mock.become)
assert.Equal(t, "root", mock.becomeUser)
assert.Equal(t, "secret", mock.becomePass)
}
func TestMockSSHClient_Good_HasExecuted(t *testing.T) {
mock := NewMockSSHClient()
_, _, _, _ = mock.Run(nil, "systemctl restart nginx")
_, _, _, _ = mock.Run(nil, "apt-get update")
assert.True(t, mock.hasExecuted("systemctl.*nginx"))
assert.True(t, mock.hasExecuted("apt-get"))
assert.False(t, mock.hasExecuted("yum"))
}
func TestMockSSHClient_Good_HasExecutedMethod(t *testing.T) {
mock := NewMockSSHClient()
_, _, _, _ = mock.Run(nil, "echo run")
_, _, _, _ = mock.RunScript(nil, "echo script")
assert.True(t, mock.hasExecutedMethod("Run", "echo run"))
assert.True(t, mock.hasExecutedMethod("RunScript", "echo script"))
assert.False(t, mock.hasExecutedMethod("Run", "echo script"))
assert.False(t, mock.hasExecutedMethod("RunScript", "echo run"))
}
func TestMockSSHClient_Good_Reset(t *testing.T) {
mock := NewMockSSHClient()
_, _, _, _ = mock.Run(nil, "echo hello")
assert.Equal(t, 1, mock.commandCount())
mock.reset()
assert.Equal(t, 0, mock.commandCount())
}
func TestMockSSHClient_Good_ErrorExpectation(t *testing.T) {
mock := NewMockSSHClient()
mock.expectCommandError("bad cmd", assert.AnError)
_, _, _, err := mock.Run(nil, "bad cmd")
assert.Error(t, err)
}
// --- command module ---
func TestModuleCommand_Good_BasicCommand(t *testing.T) {
e, mock := newTestExecutorWithMock("host1")
mock.expectCommand("ls -la /tmp", "total 0\n", "", 0)
result, err := moduleCommandWithClient(e, mock, map[string]any{
"_raw_params": "ls -la /tmp",
})
require.NoError(t, err)
assert.True(t, result.Changed)
assert.False(t, result.Failed)
assert.Equal(t, "total 0\n", result.Stdout)
assert.Equal(t, 0, result.RC)
// Verify it used Run (not RunScript)
assert.True(t, mock.hasExecutedMethod("Run", "ls -la /tmp"))
assert.False(t, mock.hasExecutedMethod("RunScript", ".*"))
}
func TestModuleCommand_Good_CmdArg(t *testing.T) {
e, mock := newTestExecutorWithMock("host1")
mock.expectCommand("whoami", "root\n", "", 0)
result, err := moduleCommandWithClient(e, mock, map[string]any{
"cmd": "whoami",
})
require.NoError(t, err)
assert.True(t, result.Changed)
assert.Equal(t, "root\n", result.Stdout)
assert.True(t, mock.hasExecutedMethod("Run", "whoami"))
}
func TestModuleCommand_Good_WithChdir(t *testing.T) {
e, mock := newTestExecutorWithMock("host1")
mock.expectCommand(`cd "/var/log" && ls`, "syslog\n", "", 0)
result, err := moduleCommandWithClient(e, mock, map[string]any{
"_raw_params": "ls",
"chdir": "/var/log",
})
require.NoError(t, err)
assert.True(t, result.Changed)
// The command should have been wrapped with cd
last := mock.lastCommand()
assert.Equal(t, "Run", last.Method)
assert.Contains(t, last.Cmd, `cd "/var/log"`)
assert.Contains(t, last.Cmd, "ls")
}
func TestModuleCommand_Bad_NoCommand(t *testing.T) {
e, _ := newTestExecutorWithMock("host1")
mock := NewMockSSHClient()
_, err := moduleCommandWithClient(e, mock, map[string]any{})
assert.Error(t, err)
assert.Contains(t, err.Error(), "no command specified")
}
func TestModuleCommand_Good_NonZeroRC(t *testing.T) {
e, mock := newTestExecutorWithMock("host1")
mock.expectCommand("false", "", "error occurred", 1)
result, err := moduleCommandWithClient(e, mock, map[string]any{
"_raw_params": "false",
})
require.NoError(t, err)
assert.True(t, result.Failed)
assert.Equal(t, 1, result.RC)
assert.Equal(t, "error occurred", result.Stderr)
}
func TestModuleCommand_Good_SSHError(t *testing.T) {
e, _ := newTestExecutorWithMock("host1")
mock := NewMockSSHClient()
mock.expectCommandError(".*", assert.AnError)
result, err := moduleCommandWithClient(e, mock, map[string]any{
"_raw_params": "any command",
})
require.NoError(t, err) // Module wraps SSH errors into result.Failed
assert.True(t, result.Failed)
assert.Contains(t, result.Msg, assert.AnError.Error())
}
func TestModuleCommand_Good_RawParamsTakesPrecedence(t *testing.T) {
e, mock := newTestExecutorWithMock("host1")
mock.expectCommand("from_raw", "raw\n", "", 0)
result, err := moduleCommandWithClient(e, mock, map[string]any{
"_raw_params": "from_raw",
"cmd": "from_cmd",
})
require.NoError(t, err)
assert.Equal(t, "raw\n", result.Stdout)
assert.True(t, mock.hasExecuted("from_raw"))
}
// --- shell module ---
func TestModuleShell_Good_BasicShell(t *testing.T) {
e, mock := newTestExecutorWithMock("host1")
mock.expectCommand("echo hello", "hello\n", "", 0)
result, err := moduleShellWithClient(e, mock, map[string]any{
"_raw_params": "echo hello",
})
require.NoError(t, err)
assert.True(t, result.Changed)
assert.False(t, result.Failed)
assert.Equal(t, "hello\n", result.Stdout)
// Shell must use RunScript (not Run)
assert.True(t, mock.hasExecutedMethod("RunScript", "echo hello"))
assert.False(t, mock.hasExecutedMethod("Run", ".*"))
}
func TestModuleShell_Good_CmdArg(t *testing.T) {
e, mock := newTestExecutorWithMock("host1")
mock.expectCommand("date", "Thu Feb 20\n", "", 0)
result, err := moduleShellWithClient(e, mock, map[string]any{
"cmd": "date",
})
require.NoError(t, err)
assert.True(t, result.Changed)
assert.True(t, mock.hasExecutedMethod("RunScript", "date"))
}
func TestModuleShell_Good_WithChdir(t *testing.T) {
e, mock := newTestExecutorWithMock("host1")
mock.expectCommand(`cd "/app" && npm install`, "done\n", "", 0)
result, err := moduleShellWithClient(e, mock, map[string]any{
"_raw_params": "npm install",
"chdir": "/app",
})
require.NoError(t, err)
assert.True(t, result.Changed)
last := mock.lastCommand()
assert.Equal(t, "RunScript", last.Method)
assert.Contains(t, last.Cmd, `cd "/app"`)
assert.Contains(t, last.Cmd, "npm install")
}
func TestModuleShell_Bad_NoCommand(t *testing.T) {
e, _ := newTestExecutorWithMock("host1")
mock := NewMockSSHClient()
_, err := moduleShellWithClient(e, mock, map[string]any{})
assert.Error(t, err)
assert.Contains(t, err.Error(), "no command specified")
}
func TestModuleShell_Good_NonZeroRC(t *testing.T) {
e, mock := newTestExecutorWithMock("host1")
mock.expectCommand("exit 2", "", "failed", 2)
result, err := moduleShellWithClient(e, mock, map[string]any{
"_raw_params": "exit 2",
})
require.NoError(t, err)
assert.True(t, result.Failed)
assert.Equal(t, 2, result.RC)
}
func TestModuleShell_Good_SSHError(t *testing.T) {
e, _ := newTestExecutorWithMock("host1")
mock := NewMockSSHClient()
mock.expectCommandError(".*", assert.AnError)
result, err := moduleShellWithClient(e, mock, map[string]any{
"_raw_params": "some command",
})
require.NoError(t, err)
assert.True(t, result.Failed)
}
func TestModuleShell_Good_PipelineCommand(t *testing.T) {
e, mock := newTestExecutorWithMock("host1")
mock.expectCommand(`cat /etc/passwd \| grep root`, "root:x:0:0\n", "", 0)
result, err := moduleShellWithClient(e, mock, map[string]any{
"_raw_params": "cat /etc/passwd | grep root",
})
require.NoError(t, err)
assert.True(t, result.Changed)
// Shell uses RunScript, so pipes work
assert.True(t, mock.hasExecutedMethod("RunScript", "cat /etc/passwd"))
}
// --- raw module ---
func TestModuleRaw_Good_BasicRaw(t *testing.T) {
e, mock := newTestExecutorWithMock("host1")
mock.expectCommand("uname -a", "Linux host1 5.15\n", "", 0)
result, err := moduleRawWithClient(e, mock, map[string]any{
"_raw_params": "uname -a",
})
require.NoError(t, err)
assert.True(t, result.Changed)
assert.Equal(t, "Linux host1 5.15\n", result.Stdout)
// Raw must use Run (not RunScript) — no shell wrapping
assert.True(t, mock.hasExecutedMethod("Run", "uname -a"))
assert.False(t, mock.hasExecutedMethod("RunScript", ".*"))
}
func TestModuleRaw_Bad_NoCommand(t *testing.T) {
e, _ := newTestExecutorWithMock("host1")
mock := NewMockSSHClient()
_, err := moduleRawWithClient(e, mock, map[string]any{})
assert.Error(t, err)
assert.Contains(t, err.Error(), "no command specified")
}
func TestModuleRaw_Good_NoChdir(t *testing.T) {
// Raw module does NOT support chdir — it should ignore it
e, mock := newTestExecutorWithMock("host1")
mock.expectCommand("echo test", "test\n", "", 0)
result, err := moduleRawWithClient(e, mock, map[string]any{
"_raw_params": "echo test",
"chdir": "/should/be/ignored",
})
require.NoError(t, err)
assert.True(t, result.Changed)
// The chdir should NOT appear in the command
last := mock.lastCommand()
assert.Equal(t, "echo test", last.Cmd)
assert.NotContains(t, last.Cmd, "cd")
}
func TestModuleRaw_Good_NonZeroRC(t *testing.T) {
e, mock := newTestExecutorWithMock("host1")
mock.expectCommand("invalid", "", "not found", 127)
result, err := moduleRawWithClient(e, mock, map[string]any{
"_raw_params": "invalid",
})
require.NoError(t, err)
// Note: raw module does NOT set Failed based on RC
assert.Equal(t, 127, result.RC)
assert.Equal(t, "not found", result.Stderr)
}
func TestModuleRaw_Good_SSHError(t *testing.T) {
e, _ := newTestExecutorWithMock("host1")
mock := NewMockSSHClient()
mock.expectCommandError(".*", assert.AnError)
result, err := moduleRawWithClient(e, mock, map[string]any{
"_raw_params": "any",
})
require.NoError(t, err)
assert.True(t, result.Failed)
}
func TestModuleRaw_Good_ExactCommandPassthrough(t *testing.T) {
// Raw should pass the command exactly as given — no wrapping
e, mock := newTestExecutorWithMock("host1")
complexCmd := `/usr/bin/python3 -c 'import sys; print(sys.version)'`
mock.expectCommand(".*python3.*", "3.10.0\n", "", 0)
result, err := moduleRawWithClient(e, mock, map[string]any{
"_raw_params": complexCmd,
})
require.NoError(t, err)
assert.True(t, result.Changed)
last := mock.lastCommand()
assert.Equal(t, complexCmd, last.Cmd)
}
// --- script module ---
func TestModuleScript_Good_BasicScript(t *testing.T) {
// Create a temporary script file
tmpDir := t.TempDir()
scriptPath := filepath.Join(tmpDir, "setup.sh")
scriptContent := "#!/bin/bash\necho 'setup complete'\nexit 0"
require.NoError(t, os.WriteFile(scriptPath, []byte(scriptContent), 0755))
e, mock := newTestExecutorWithMock("host1")
mock.expectCommand("setup complete", "setup complete\n", "", 0)
result, err := moduleScriptWithClient(e, mock, map[string]any{
"_raw_params": scriptPath,
})
require.NoError(t, err)
assert.True(t, result.Changed)
assert.False(t, result.Failed)
// Script must use RunScript (not Run) — it sends the file content
assert.True(t, mock.hasExecutedMethod("RunScript", "setup complete"))
assert.False(t, mock.hasExecutedMethod("Run", ".*"))
// Verify the full script content was sent
last := mock.lastCommand()
assert.Equal(t, scriptContent, last.Cmd)
}
func TestModuleScript_Bad_NoScript(t *testing.T) {
e, _ := newTestExecutorWithMock("host1")
mock := NewMockSSHClient()
_, err := moduleScriptWithClient(e, mock, map[string]any{})
assert.Error(t, err)
assert.Contains(t, err.Error(), "no script specified")
}
func TestModuleScript_Bad_FileNotFound(t *testing.T) {
e, _ := newTestExecutorWithMock("host1")
mock := NewMockSSHClient()
_, err := moduleScriptWithClient(e, mock, map[string]any{
"_raw_params": "/nonexistent/script.sh",
})
assert.Error(t, err)
assert.Contains(t, err.Error(), "read script")
}
func TestModuleScript_Good_NonZeroRC(t *testing.T) {
tmpDir := t.TempDir()
scriptPath := filepath.Join(tmpDir, "fail.sh")
require.NoError(t, os.WriteFile(scriptPath, []byte("exit 1"), 0755))
e, mock := newTestExecutorWithMock("host1")
mock.expectCommand("exit 1", "", "script failed", 1)
result, err := moduleScriptWithClient(e, mock, map[string]any{
"_raw_params": scriptPath,
})
require.NoError(t, err)
assert.True(t, result.Failed)
assert.Equal(t, 1, result.RC)
}
func TestModuleScript_Good_MultiLineScript(t *testing.T) {
tmpDir := t.TempDir()
scriptPath := filepath.Join(tmpDir, "multi.sh")
scriptContent := "#!/bin/bash\nset -e\napt-get update\napt-get install -y nginx\nsystemctl start nginx"
require.NoError(t, os.WriteFile(scriptPath, []byte(scriptContent), 0755))
e, mock := newTestExecutorWithMock("host1")
mock.expectCommand("apt-get", "done\n", "", 0)
result, err := moduleScriptWithClient(e, mock, map[string]any{
"_raw_params": scriptPath,
})
require.NoError(t, err)
assert.True(t, result.Changed)
// Verify RunScript was called with the full content
last := mock.lastCommand()
assert.Equal(t, "RunScript", last.Method)
assert.Equal(t, scriptContent, last.Cmd)
}
func TestModuleScript_Good_SSHError(t *testing.T) {
tmpDir := t.TempDir()
scriptPath := filepath.Join(tmpDir, "ok.sh")
require.NoError(t, os.WriteFile(scriptPath, []byte("echo ok"), 0755))
e, _ := newTestExecutorWithMock("host1")
mock := NewMockSSHClient()
mock.expectCommandError(".*", assert.AnError)
result, err := moduleScriptWithClient(e, mock, map[string]any{
"_raw_params": scriptPath,
})
require.NoError(t, err)
assert.True(t, result.Failed)
}
// --- Cross-module differentiation tests ---
func TestModuleDifferentiation_Good_CommandUsesRun(t *testing.T) {
e, mock := newTestExecutorWithMock("host1")
mock.expectCommand("echo test", "test\n", "", 0)
_, _ = moduleCommandWithClient(e, mock, map[string]any{"_raw_params": "echo test"})
cmds := mock.executedCommands()
require.Len(t, cmds, 1)
assert.Equal(t, "Run", cmds[0].Method, "command module must use Run()")
}
func TestModuleDifferentiation_Good_ShellUsesRunScript(t *testing.T) {
e, mock := newTestExecutorWithMock("host1")
mock.expectCommand("echo test", "test\n", "", 0)
_, _ = moduleShellWithClient(e, mock, map[string]any{"_raw_params": "echo test"})
cmds := mock.executedCommands()
require.Len(t, cmds, 1)
assert.Equal(t, "RunScript", cmds[0].Method, "shell module must use RunScript()")
}
func TestModuleDifferentiation_Good_RawUsesRun(t *testing.T) {
e, mock := newTestExecutorWithMock("host1")
mock.expectCommand("echo test", "test\n", "", 0)
_, _ = moduleRawWithClient(e, mock, map[string]any{"_raw_params": "echo test"})
cmds := mock.executedCommands()
require.Len(t, cmds, 1)
assert.Equal(t, "Run", cmds[0].Method, "raw module must use Run()")
}
func TestModuleDifferentiation_Good_ScriptUsesRunScript(t *testing.T) {
tmpDir := t.TempDir()
scriptPath := filepath.Join(tmpDir, "test.sh")
require.NoError(t, os.WriteFile(scriptPath, []byte("echo test"), 0755))
e, mock := newTestExecutorWithMock("host1")
mock.expectCommand("echo test", "test\n", "", 0)
_, _ = moduleScriptWithClient(e, mock, map[string]any{"_raw_params": scriptPath})
cmds := mock.executedCommands()
require.Len(t, cmds, 1)
assert.Equal(t, "RunScript", cmds[0].Method, "script module must use RunScript()")
}
// --- executeModuleWithMock dispatch tests ---
func TestExecuteModuleWithMock_Good_DispatchCommand(t *testing.T) {
e, mock := newTestExecutorWithMock("host1")
mock.expectCommand("uptime", "up 5 days\n", "", 0)
task := &Task{
Module: "command",
Args: map[string]any{"_raw_params": "uptime"},
}
result, err := executeModuleWithMock(e, mock, "host1", task)
require.NoError(t, err)
assert.True(t, result.Changed)
assert.Equal(t, "up 5 days\n", result.Stdout)
}
func TestExecuteModuleWithMock_Good_DispatchShell(t *testing.T) {
e, mock := newTestExecutorWithMock("host1")
mock.expectCommand("ps aux", "root.*bash\n", "", 0)
task := &Task{
Module: "ansible.builtin.shell",
Args: map[string]any{"_raw_params": "ps aux | grep bash"},
}
result, err := executeModuleWithMock(e, mock, "host1", task)
require.NoError(t, err)
assert.True(t, result.Changed)
}
func TestExecuteModuleWithMock_Good_DispatchRaw(t *testing.T) {
e, mock := newTestExecutorWithMock("host1")
mock.expectCommand("cat /etc/hostname", "web01\n", "", 0)
task := &Task{
Module: "raw",
Args: map[string]any{"_raw_params": "cat /etc/hostname"},
}
result, err := executeModuleWithMock(e, mock, "host1", task)
require.NoError(t, err)
assert.True(t, result.Changed)
assert.Equal(t, "web01\n", result.Stdout)
}
func TestExecuteModuleWithMock_Good_DispatchScript(t *testing.T) {
tmpDir := t.TempDir()
scriptPath := filepath.Join(tmpDir, "deploy.sh")
require.NoError(t, os.WriteFile(scriptPath, []byte("echo deploying"), 0755))
e, mock := newTestExecutorWithMock("host1")
mock.expectCommand("deploying", "deploying\n", "", 0)
task := &Task{
Module: "script",
Args: map[string]any{"_raw_params": scriptPath},
}
result, err := executeModuleWithMock(e, mock, "host1", task)
require.NoError(t, err)
assert.True(t, result.Changed)
}
func TestExecuteModuleWithMock_Bad_UnsupportedModule(t *testing.T) {
e, mock := newTestExecutorWithMock("host1")
task := &Task{
Module: "ansible.builtin.copy",
Args: map[string]any{},
}
_, err := executeModuleWithMock(e, mock, "host1", task)
assert.Error(t, err)
assert.Contains(t, err.Error(), "unsupported module")
}
// --- Template integration tests ---
func TestModuleCommand_Good_TemplatedArgs(t *testing.T) {
e, mock := newTestExecutorWithMock("host1")
e.SetVar("service_name", "nginx")
mock.expectCommand("systemctl status nginx", "active\n", "", 0)
task := &Task{
Module: "command",
Args: map[string]any{"_raw_params": "systemctl status {{ service_name }}"},
}
// Template the args the way the executor does
args := e.templateArgs(task.Args, "host1", task)
result, err := moduleCommandWithClient(e, mock, args)
require.NoError(t, err)
assert.True(t, result.Changed)
assert.True(t, mock.hasExecuted("systemctl status nginx"))
}