-
Notifications
You must be signed in to change notification settings - Fork 25
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Implement self-restart functionality for the agent
feat: Address comments and improve the code
- Loading branch information
Showing
14 changed files
with
277 additions
and
32 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
cmake_minimum_required(VERSION 3.22) | ||
|
||
project(RestartHandler) | ||
|
||
include(../../cmake/CommonSettings.cmake) | ||
set_common_settings() | ||
|
||
find_package(Boost REQUIRED COMPONENTS asio) | ||
|
||
|
||
if(WIN32) | ||
set(SOURCES src/restart_handler_win.cpp) | ||
else() | ||
set(SOURCES src/restart_handler_unix.cpp) | ||
endif() | ||
|
||
add_library(RestartHandler ${SOURCES}) | ||
target_include_directories(RestartHandler PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) | ||
target_link_libraries(RestartHandler PUBLIC Boost::asio CommandEntry PRIVATE Logger) | ||
|
||
include(../../cmake/ConfigureTarget.cmake) | ||
configure_target(RestartHandler) | ||
|
||
# if(BUILD_TESTS) | ||
# enable_testing() | ||
# add_subdirectory(tests) | ||
# endif() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
#pragma once | ||
#include <command_entry.hpp> | ||
|
||
#include <boost/asio/awaitable.hpp> | ||
|
||
#include <vector> | ||
|
||
namespace restart_handler | ||
{ | ||
/// @brief Class for handling service restarts. | ||
class RestartHandler | ||
{ | ||
public: | ||
/// @brief Command-line arguments for the service. | ||
static std::vector<char*> cmd_line; | ||
explicit RestartHandler(); | ||
|
||
/// @brief Stores the command-line arguments passed to the agent. | ||
/// @param argc Number of arguments. | ||
/// @param argv Array of arguments. | ||
static void SetCommandLineArguments(int argc, char* argv[]) | ||
{ | ||
for (int i = 0; i < argc; ++i) | ||
{ | ||
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) | ||
RestartHandler::cmd_line.emplace_back(argv[i]); | ||
} | ||
RestartHandler::cmd_line.emplace_back(nullptr); | ||
} | ||
|
||
/// @brief Executes the restart command. | ||
/// @return Result of the restart command execution. | ||
static boost::asio::awaitable<module_command::CommandExecutionResult> RestartCommand(); | ||
}; | ||
} // namespace restart_handler |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
#include "restart_handler_unix.hpp" | ||
#include <fstream> | ||
#include <logger.hpp> | ||
|
||
#include <chrono> | ||
#include <thread> | ||
|
||
namespace restart_handler | ||
{ | ||
|
||
std::vector<char*> RestartHandler::cmd_line; | ||
|
||
bool UsingSystemctl() | ||
{ | ||
return (0 == std::system("which systemctl > /dev/null 2>&1") && nullptr != std::getenv("INVOCATION_ID")); | ||
} | ||
|
||
boost::asio::awaitable<module_command::CommandExecutionResult> RestartWithSystemd() | ||
{ | ||
LogInfo("Systemctl restarting wazuh agent service."); | ||
if (std::system("systemctl restart wazuh-agent") != 0) | ||
{ | ||
co_return module_command::CommandExecutionResult {module_command::Status::IN_PROGRESS, | ||
"Systemctl restart execution"}; | ||
} | ||
else | ||
{ | ||
LogError("Failed using systemctl."); | ||
co_return module_command::CommandExecutionResult {module_command::Status::FAILURE, | ||
"Systemctl restart failed"}; | ||
} | ||
} | ||
|
||
void StopAgent() | ||
{ | ||
const int timeout = 30; | ||
time_t start_time = time(nullptr); // Record the start time to track the timeout duration | ||
|
||
pid_t pid = getppid(); | ||
|
||
// Shutdown Gracefully | ||
kill(pid, SIGTERM); | ||
|
||
while (true) | ||
{ | ||
if (kill(pid, 0) != 0) | ||
{ | ||
LogInfo("Agent gracefully stopped."); | ||
break; | ||
} | ||
|
||
if (difftime(time(nullptr), start_time) > timeout) | ||
{ | ||
LogError("Timeout reached! Forcing agent process termination."); | ||
kill(pid, SIGKILL); | ||
} | ||
|
||
std::this_thread::sleep_for(std::chrono::seconds(1)); | ||
} | ||
} | ||
|
||
boost::asio::awaitable<module_command::CommandExecutionResult> RestartWithFork() | ||
{ | ||
pid_t pid = fork(); | ||
|
||
if (pid < 0) | ||
{ | ||
LogError("Fork failed."); | ||
} | ||
else if (pid == 0) | ||
{ | ||
// Child process | ||
StopAgent(); | ||
|
||
LogInfo("Starting wazuh agent in a new process."); | ||
|
||
if (execve(RestartHandler::cmd_line[0], RestartHandler::cmd_line.data(), nullptr) == -1) | ||
{ | ||
LogError("Failed to spawn new Wazuh agent process."); | ||
} | ||
} | ||
|
||
co_return module_command::CommandExecutionResult {module_command::Status::IN_PROGRESS, | ||
"Pending restart execution"}; | ||
} | ||
|
||
boost::asio::awaitable<module_command::CommandExecutionResult> RestartHandler::RestartCommand() | ||
{ | ||
|
||
if (UsingSystemctl()) | ||
{ | ||
return RestartWithSystemd(); | ||
} | ||
else | ||
{ | ||
return RestartWithFork(); | ||
} | ||
} | ||
|
||
} // namespace restart_handler |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
#pragma once | ||
#include <boost/asio/awaitable.hpp> | ||
#include <command_entry.hpp> | ||
#include <restart_handler.hpp> | ||
#include <vector> | ||
|
||
namespace restart_handler | ||
{ | ||
|
||
/// @brief Checks if systemctl is available and running as a systemd service. | ||
/// | ||
/// Determines if systemctl can be used in the current environment. | ||
/// @return true if systemctl is available and running as a systemd service, otherwise returns false. | ||
bool UsingSystemctl(); | ||
|
||
/// @brief Stops the agent by terminating the child process. | ||
/// | ||
/// This function sends a SIGTERM signal to the agent process to stop it. If the agent process | ||
/// does not stop within a specified timeout period (30 seconds), it forces termination with a SIGKILL signal. | ||
void StopAgent(); | ||
|
||
/// @brief Restarts the module by forking a new process. | ||
/// | ||
/// This function restarts the module by creating a new child process. | ||
/// | ||
/// @return A boost::asio::awaitable containing the result of the command execution. | ||
boost::asio::awaitable<module_command::CommandExecutionResult> RestartWithFork(); | ||
|
||
/// @brief Restarts the module using systemd service management. | ||
/// | ||
/// This function restarts the module via systemd, ensuring the module is properly restarted using | ||
/// system service management mechanisms. | ||
/// | ||
/// @return A boost::asio::awaitable containing the result of the command execution. | ||
boost::asio::awaitable<module_command::CommandExecutionResult> RestartWithSystemd(); | ||
|
||
} // namespace restart_handler |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
#include <boost/asio/awaitable.hpp> | ||
#include <logger.hpp> | ||
#include <restart_handler.hpp> | ||
|
||
namespace restart_handler | ||
{ | ||
|
||
std::vector<char*> RestartHandler::cmd_line; | ||
|
||
boost::asio::awaitable<module_command::CommandExecutionResult> RestartHandler::RestartCommand() | ||
{ | ||
// TODO | ||
co_return module_command::CommandExecutionResult {module_command::Status::FAILURE, | ||
"RestartHandler is not implemented yet"}; | ||
} | ||
|
||
} // namespace restart_handler |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.