Skip to content

Commit

Permalink
feat: Implement self-restart functionality for the agent
Browse files Browse the repository at this point in the history
  • Loading branch information
lchico committed Dec 19, 2024
1 parent 1eb2738 commit 5d10b86
Show file tree
Hide file tree
Showing 7 changed files with 152 additions and 37 deletions.
27 changes: 3 additions & 24 deletions packages/debs/SPECS/wazuh-agent/debian/prerm
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,9 @@ case "$1" in
elif ${BINARY_DIR}wazuh-agent --status 2>/dev/null | grep "is running" > /dev/null 2>&1; then
pid=$(ps -ef | grep "${BINARY_DIR}wazuh-agent" | grep -v grep | awk '{print $2}')
if [ -n "$pid" ]; then
kill -SIGTERM "$pid" 2>/dev/null
kill -15 "$pid" 2>/dev/null
fi
fi

# # Process: wazuh-agent
# if pgrep -f "wazuh-agent" > /dev/null 2>&1; then
# kill -15 $(pgrep -f "wazuh-agent") > /dev/null 2>&1
# fi

# if pgrep -f "wazuh-agent" > /dev/null 2>&1; then
# kill -9 $(pgrep -f "wazuh-agent") > /dev/null 2>&1
# fi
;;

remove)
Expand All @@ -38,10 +29,9 @@ case "$1" in
elif ${BINARY_DIR}wazuh-agent --status 2>/dev/null | grep "is running" > /dev/null 2>&1; then
pid=$(ps -ef | grep "${BINARY_DIR}wazuh-agent" | grep -v grep | awk '{print $2}')
if [ -n "$pid" ]; then
kill -SIGTERM "$pid" 2>/dev/null
kill -15 "$pid" 2>/dev/null
fi
fi

;;

failed-upgrade)
Expand All @@ -52,20 +42,9 @@ case "$1" in
elif ${BINARY_DIR}wazuh-agent --status 2>/dev/null | grep "is running" > /dev/null 2>&1; then
pid=$(ps -ef | grep "${BINARY_DIR}wazuh-agent" | grep -v grep | awk '{print $2}')
if [ -n "$pid" ]; then
kill -SIGTERM "$pid" 2>/dev/null
kill -15 "$pid" 2>/dev/null
fi
fi

# if [ -f ${INSTALLATION_WAZUH_DIR}/bin/wazuh-agent ]; then
# # pkill wazuh-agent
# if pgrep -f "wazuh-agent" > /dev/null 2>&1; then
# kill -15 $(pgrep -f "wazuh-agent") > /dev/null 2>&1
# fi

# if pgrep -f "wazuh-agent" > /dev/null 2>&1; then
# kill -9 $(pgrep -f "wazuh-agent") > /dev/null 2>&1
# fi
# fi
;;

*)
Expand Down
1 change: 0 additions & 1 deletion src/agent/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ target_link_libraries(Agent
MultiTypeQueue
ModuleManager
ModuleCommand
CentralizedConfiguration
Boost::asio
sysinfo
PRIVATE
Expand Down
9 changes: 7 additions & 2 deletions src/agent/command_handler/include/command_handler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,13 @@ namespace command_handler
{
for (auto& cmd : *cmds)
{
cmd.ExecutionResult.ErrorCode = module_command::Status::FAILURE;
cmd.ExecutionResult.Message = "Agent stopped during execution";
if (cmd.Command == "restart") {
cmd.ExecutionResult.ErrorCode = module_command::Status::IN_PROGRESS;
cmd.ExecutionResult.Message = "Restarting Agent...";
} else {
cmd.ExecutionResult.ErrorCode = module_command::Status::FAILURE;
cmd.ExecutionResult.Message = "Agent stopped during execution";
}
ReportCommandResult(cmd);
m_commandStore.UpdateCommand(cmd);
}
Expand Down
2 changes: 1 addition & 1 deletion src/agent/command_handler/src/command_handler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
namespace command_handler
{
const std::unordered_map<std::string, std::string> VALID_COMMANDS_MAP = {
{"set-group", "CentralizedConfiguration"}, {"update-group", "CentralizedConfiguration"}};
{"set-group", "CentralizedConfiguration"}, {"update-group", "CentralizedConfiguration"}, {"restart", "restart"}};

void CommandHandler::Stop()
{
Expand Down
5 changes: 3 additions & 2 deletions src/agent/service/wazuh-agent.service
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@ After=network.target network-online.target

[Service]
Type=simple

PIDFile=/var/run/wazuh-agent.lock
ExecStart=/usr/bin/env WAZUH_HOME/wazuh-agent
TimeoutStopSec=30s # Wait for 30 seconds before killing the service

KillSignal=SIGTERM

KillMode=process
KillMode=mixed

SendSIGKILL=no

Expand Down
95 changes: 92 additions & 3 deletions src/agent/src/agent.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <agent.hpp>
#include <unix_daemon.hpp>

#include <command_handler_utils.hpp>
#include <config.h>
Expand All @@ -10,10 +11,13 @@
#include <filesystem>
#include <memory>

Agent::Agent(const std::string& configFilePath, std::unique_ptr<ISignalHandler> signalHandler)
: m_configurationParser(configFilePath.empty() ? std::make_shared<configuration::ConfigurationParser>()
#include <unistd.h>

Agent::Agent(const std::string& configFilePath, const char** mainArgv, std::unique_ptr<ISignalHandler> signalHandler)
: argv(mainArgv)
, m_configurationParser(configFilePath.empty() ? std::make_shared<configuration::ConfigurationParser>()
: std::make_shared<configuration::ConfigurationParser>(
std::filesystem::path(configFilePath)))
std::filesystem::path(configFilePath)))
, m_dataPath(
m_configurationParser->GetConfig<std::string>("agent", "path.data").value_or(config::DEFAULT_DATA_PATH))
, m_messageQueue(std::make_shared<MultiTypeQueue>(
Expand Down Expand Up @@ -101,6 +105,89 @@ void Agent::ReloadModules()
}
}

void Agent::StopAgent(){

LogInfo("Restart: Stopping wazuh-agent.");
unix_daemon::LockFileHandler lockFileHandler = unix_daemon::GenerateLockFile(m_configurationParser->GetConfigFilePath());

if (lockFileHandler.isLockFileCreated())
{
LogInfo("wazuh-agent is not running");
return;
}

pid_t pid = lockFileHandler.ReadPIDFromFile();

if (pid < 0)
{
LogError("Error reading pid file");
return;
}

if (!kill(pid, SIGTERM))
{
LogInfo("wazuh-agent stopped successfully");
}

lockFileHandler.removeLockFile();
}

boost::asio::awaitable<module_command::CommandExecutionResult> Agent::RestartExecuteCommand() {

int timeoutSeconds = 30;
auto startTime = std::chrono::steady_clock::now();

if (0 == std::system("which systemctl > /dev/null 2>&1") &&
nullptr != std::getenv("INVOCATION_ID"))
{
LogInfo("Restart: systemctl restarting wazuh agent service.");
std::system("systemctl restart wazuh-agent");
}else{
StopAgent();
pid_t pid = fork();
if (pid == 0) {
// Child process
LogInfo("Restart: starting wazuh agent from the fork child.");

std::vector<const char*> args;
for (int i = 0; argv[i] != nullptr; ++i) {
args.push_back(argv[i]);
}

// End the argument list with nullptr (required for execve)
args.push_back(nullptr);

LogInfo("Waiting for wazuh-agent to stop...");
while ( "stopped" != unix_daemon::GetDaemonStatus(m_configurationParser->GetConfigFilePath()) ) {
auto elapsed = std::chrono::steady_clock::now() - startTime;
if (std::chrono::duration_cast<std::chrono::seconds>(elapsed).count() > timeoutSeconds) {
LogError("Timeout reached while stopping wazuh-agent.");
if (!kill(pid, SIGKILL))
{
LogInfo("wazuh-agent stopped successfully");
}

}
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}

std::this_thread::sleep_for(std::chrono::milliseconds(200));
if (execve(argv[0], const_cast<char* const*>(args.data()), nullptr) == -1) {
LogError("Failed to spawn new Wazuh agent process.");
}
exit(1);
} else if (pid < 0) {
LogError("Fork failed");
exit(1);
} else {
// Parent process
setpgid(pid, pid);
exit(0);
}
}
co_return module_command::CommandExecutionResult{module_command::Status::IN_PROGRESS, "Pending check of status."};
}

void Agent::Run()
{
m_taskManager.Start(m_agentThreadCount);
Expand Down Expand Up @@ -158,6 +245,8 @@ void Agent::Run()
return m_centralizedConfiguration.ExecuteCommand(std::move(command), std::move(parameters));
},
m_messageQueue);
} else if (cmd.Module == "restart") {
return RestartExecuteCommand();
}
return DispatchCommand(cmd, m_moduleManager.GetModule(cmd.Module), m_messageQueue);
}),
Expand Down
50 changes: 46 additions & 4 deletions src/agent/src/unix/unix_daemon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ namespace unix_daemon
try
{
std::filesystem::remove(filePath);
LogDebug("Lock file removed.");
return true;
}
catch (const std::filesystem::filesystem_error& e)
Expand Down Expand Up @@ -63,16 +64,24 @@ namespace unix_daemon

bool LockFileHandler::createLockFile()
{

const std::string filename = fmt::format("{}/wazuh-agent.lock", m_lockFilePath);

// Check if the lock file already exists
if (access(filename.c_str(), F_OK) != -1)
{
LogDebug("Lock file already exists: {}", filename);
return false;
}

if (!createDirectory(m_lockFilePath))
{
LogError("Unable to create lock directory: {}", m_lockFilePath);
return false;
}

const std::string filename = fmt::format("{}/wazuh-agent.lock", m_lockFilePath);

// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, cppcoreguidelines-avoid-magic-numbers)
int fd = open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0644);
int fd = open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0644);
if (fd == -1)
{
LogError("Unable to open lock file: {}. Error: {} ({})", filename.c_str(), errno, std::strerror(errno));
Expand All @@ -86,11 +95,44 @@ namespace unix_daemon
return false;
}

LogDebug("Lock file created: {}", filename);
// Write the PID to the lock file
const std::string pidStr = std::to_string(getpid()) + "\n";
if (write(fd, pidStr.c_str(), pidStr.size()) == -1)
{
LogError("Unable to write PID to lock file: {}. Error: {} ({})", filename.c_str(), errno, std::strerror(errno));
close(fd);
return false;
}

LogDebug("Lock file created: {}", filename);
return true;
}


pid_t LockFileHandler::ReadPIDFromFile() const
{
const std::string filename = fmt::format("{}/wazuh-agent.lock", m_lockFilePath);
std::ifstream file(filename);

if (!file.is_open())
{
LogError("Unable to open lock file: {}. Error: {} ({})", filename.c_str(), errno, std::strerror(errno));
return 0;
}

pid_t value {};
file >> value;

if (file.fail())
{
LogError("Error reading PID file: {}({})", filename.c_str(), errno, std::strerror(errno));
return -1;
}

return value;
}


LockFileHandler GenerateLockFile(const std::string& configFilePath)
{
auto configurationParser = configFilePath.empty()
Expand Down

0 comments on commit 5d10b86

Please sign in to comment.