#include <config.h>
#include <asiolink/io_service_mgr.h>
+#include <asiolink/process_spawn.h>
#include <cc/command_interpreter.h>
#include <cc/data.h>
#include <config/command_mgr.h>
}
server_ = this; // remember this instance for later use in handlers
+ // ProcessSpawn uses IO service to handle signal set events.
+ ProcessSpawn::setIOService(getIOService());
+
// TimerMgr uses IO service to run asynchronous timers.
TimerMgr::instance()->setIOService(getIOService());
// Reset DatabaseConnection IO service.
DatabaseConnection::setIOService(IOServicePtr());
+
+ // Reset ProcessSpawn IO service.
+ ProcessSpawn::setIOService(IOServicePtr());
}
/// @brief Class which handles initialization of database
#define DHCP4_TEST_UTILS_H
#include <gtest/gtest.h>
+
+#include <asiolink/process_spawn.h>
#include <dhcp/iface_mgr.h>
#include <dhcp/option4_addrlst.h>
#include <dhcp/pkt4.h>
// Create a default lease database backend.
std::string dbconfig = "type=memfile universe=4 persist=false";
isc::dhcp::LeaseMgrFactory::create(dbconfig);
+
// Create fixed server id.
server_id_.reset(new Option4AddrLst(DHO_DHCP_SERVER_IDENTIFIER,
asiolink::IOAddress("192.0.3.1")));
+
+ isc::asiolink::ProcessSpawn::setIOService(getIOService());
+
db::DatabaseConnection::setIOService(getIOService());
dhcp::TimerMgr::instance()->setIOService(getIOService());
#include <config.h>
#include <asiolink/io_service_mgr.h>
+#include <asiolink/process_spawn.h>
#include <cc/command_interpreter.h>
#include <cc/data.h>
#include <config/command_mgr.h>
}
server_ = this; // remember this instance for later use in handlers
+ // ProcessSpawn uses IO service to handle signal set events.
+ ProcessSpawn::setIOService(getIOService());
+
// TimerMgr uses IO service to run asynchronous timers.
TimerMgr::instance()->setIOService(getIOService());
// Reset DatabaseConnection IO service.
DatabaseConnection::setIOService(IOServicePtr());
+
+ // Reset ProcessSpawn IO service.
+ ProcessSpawn::setIOService(IOServicePtr());
}
/// @brief Class which handles initialization of database
#include <gtest/gtest.h>
+#include <asiolink/process_spawn.h>
#include <dhcp6/dhcp6_srv.h>
#include <dhcp6/parser_context.h>
#include <dhcp/pkt6.h>
// Open the "memfile" database for leases
std::string memfile = "type=memfile universe=6 persist=false";
isc::dhcp::LeaseMgrFactory::create(memfile);
+
+ isc::asiolink::ProcessSpawn::setIOService(getIOService());
+
db::DatabaseConnection::setIOService(getIOService());
dhcp::TimerMgr::instance()->setIOService(getIOService());
namespace isc {
namespace run_script {
-IOServicePtr RunScriptImpl::io_service_;
-
RunScriptImpl::RunScriptImpl() : io_context_(new IOService()), name_(), sync_(false) {
}
isc_throw(InvalidParameter, "The 'name' parameter must be a string");
}
try {
- ProcessSpawn process(IOServicePtr(), name->stringValue());
+ ProcessSpawn process(false, name->stringValue());
} catch (const isc::Exception& ex) {
isc_throw(InvalidParameter, "Invalid 'name' parameter: " << ex.what());
}
void
RunScriptImpl::runScript(const ProcessArgs& args, const ProcessEnvVars& vars) {
- ProcessSpawn process(getIOService(), name_, args, vars);
+ ProcessSpawn process(false, name_, args, vars);
process.spawn(true);
}
/// @brief This function parses and applies configuration parameters.
void configure(isc::hooks::LibraryHandle& handle);
- /// @brief Get the hook I/O service.
- ///
- /// @return the hook I/O service.
- isc::asiolink::IOServicePtr getIOContext() {
- return (io_context_);
- }
-
- /// @brief Set the hook I/O service.
- ///
- /// @param io_service the hook I/O service.
- void setIOContext(isc::asiolink::IOServicePtr io_service) {
- io_context_ = io_service;
- }
-
- /// @brief Get the hook I/O service.
- ///
- /// @return the hook I/O service.
- static isc::asiolink::IOServicePtr getIOService() {
- return (io_service_);
- }
-
- /// @brief Set the hook I/O service.
- ///
- /// @param io_service the hook I/O service.
- static void setIOService(isc::asiolink::IOServicePtr io_service) {
- io_service_ = io_service;
- }
-
private:
/// @brief The IOService object, used for all ASIO operations.
/// exits, otherwise the call will return immediately after the script is
/// started.
bool sync_;
-
- /// @brief The hook I/O service.
- static isc::asiolink::IOServicePtr io_service_;
};
/// @brief The type of shared pointers to Run Script implementations.
///
/// @return always 0.
int unload() {
- if (impl) {
- IOServiceMgr::instance().unregisterIOService(impl->getIOContext());
- }
impl.reset();
- if (RunScriptImpl::getIOService()) {
- RunScriptImpl::getIOService()->stop();
- RunScriptImpl::getIOService()->restart();
- try {
- RunScriptImpl::getIOService()->poll();
- } catch (...) {
- }
- }
- RunScriptImpl::setIOService(IOServicePtr());
LOG_INFO(run_script_logger, RUN_SCRIPT_UNLOAD);
return (0);
}
-/// @brief dhcp4_srv_configured callout implementation.
-///
-/// @param handle callout handle.
-int dhcp4_srv_configured(CalloutHandle& handle) {
- try {
- RunScriptImpl::setIOService(impl->getIOContext());
- IOServiceMgr::instance().registerIOService(impl->getIOContext());
-
- } catch (const exception& ex) {
- LOG_ERROR(run_script_logger, RUN_SCRIPT_LOAD_ERROR)
- .arg(ex.what());
- handle.setStatus(isc::hooks::CalloutHandle::NEXT_STEP_DROP);
- return (1);
- }
- return (0);
-}
-
-/// @brief dhcp6_srv_configured callout implementation.
-///
-/// @param handle callout handle.
-int dhcp6_srv_configured(CalloutHandle& handle) {
- try {
- RunScriptImpl::setIOService(impl->getIOContext());
- IOServiceMgr::instance().registerIOService(impl->getIOContext());
-
- } catch (const exception& ex) {
- LOG_ERROR(run_script_logger, RUN_SCRIPT_LOAD_ERROR)
- .arg(ex.what());
- handle.setStatus(isc::hooks::CalloutHandle::NEXT_STEP_DROP);
- return (1);
- }
- return (0);
-}
-
/// @brief handle @ref lease4_renew hook and set environment parameters for the
/// script.
/// IN: query4 subnet4 clientid hwaddr lease4
/// @brief Constructor.
RunScriptTest() :
co_manager_(new CalloutManager(1)), io_service_(new IOService()) {
- RunScriptImpl::setIOService(io_service_);
+ ProcessSpawn::setIOService(io_service_);
clearLogFile();
}
/// @brief Destructor.
~RunScriptTest() {
- RunScriptImpl::setIOService(IOServicePtr());
+ ProcessSpawn::setIOService(IOServicePtr());
clearLogFile();
}
/// @brief Constructor.
///
- /// @param io_service The IOService which handles signal handlers.
+ /// @param sync enables synchronous mode (spawning thread waits on
+ /// child to complete if true)
/// @param executable A full path to the program to be executed.
/// @param args Arguments for the program to be executed.
/// @param vars Environment variables for the program to be executed.
/// @param inherit_env whether the spawned process will inherit the
- /// environment before adding 'vars' on top.
- /// @param sync enables synchronous mode (spawning thread waits on
- /// child to complete if true)
- ProcessSpawnImpl(IOServicePtr io_service,
+ /// environment before adding 'vars' on top.
+ ProcessSpawnImpl(const bool sync,
const std::string& executable,
const ProcessArgs& args,
const ProcessEnvVars& vars,
- const bool inherit_env,
- const bool sync);
+ const bool inherit_env);
/// @brief Destructor.
~ProcessSpawnImpl();
/// for any child process
/// @param sync whether this function is called immediately after spawning
/// (synchronous) or not (asynchronous, default).
- static void waitForProcess(int signum, pid_t const wpid = -1, bool const sync = false);
+ static void waitForProcess(int signum, pid_t const wpid = -1,
+ bool const sync = false);
/// @brief A map holding the status codes of executed processes.
static ProcessCollection process_collection_;
+ /// @brief Whether the process is waited immediately after spawning
+ /// (synchronous) or not (asynchronous, default).
+ bool sync_;
+
/// @brief Path to an executable.
std::string executable_;
/// @brief Mutex to protect internal state.
static std::mutex mutex_;
-
- /// @brief The IOService which handles IO operations.
- IOServicePtr io_service_;
-
- /// @brief Whether the process is waited immediately after spawning
- /// (synchronous) or not (asynchronous, default).
- bool sync_;
};
ProcessCollection ProcessSpawnImpl::process_collection_;
static IOSignalSetInitializer init(io_service);
}
-ProcessSpawnImpl::ProcessSpawnImpl(IOServicePtr io_service,
+ProcessSpawnImpl::ProcessSpawnImpl(const bool sync,
const std::string& executable,
const ProcessArgs& args,
const ProcessEnvVars& vars,
- const bool inherit_env,
- const bool sync)
- : executable_(executable), args_(new char*[args.size() + 2]),
- store_(false), io_service_(io_service), sync_(sync) {
+ const bool inherit_env)
+ : sync_(sync), executable_(executable), args_(new char*[args.size() + 2]),
+ store_(false) {
// Size of vars except the trailing null
size_t vars_size;
ProcessSpawnImpl::spawn(bool dismiss) {
lock_guard<std::mutex> lk(mutex_);
if (!sync_) {
- ProcessSpawnImpl::IOSignalSetInitializer::initIOSignalSet(io_service_);
+ ProcessSpawnImpl::IOSignalSetInitializer::initIOSignalSet(ProcessSpawn::getIOService());
}
// Create the child
pid_t pid = fork();
}
}
-ProcessSpawn::ProcessSpawn(IOServicePtr io_service,
- const std::string& executable,
- const ProcessArgs& args,
- const ProcessEnvVars& vars,
- const bool inherit_env /* = false */)
- : impl_(new ProcessSpawnImpl(io_service,
- executable,
- args,
- vars,
- inherit_env,
- /* sync = */ false)) {
-}
+IOServicePtr ProcessSpawn::io_service_;
-ProcessSpawn::ProcessSpawn(const std::string& executable,
+ProcessSpawn::ProcessSpawn(const bool sync,
+ const std::string& executable,
const ProcessArgs& args,
const ProcessEnvVars& vars,
const bool inherit_env /* = false */)
- : impl_(new ProcessSpawnImpl(IOServicePtr(new IOService()),
- executable,
- args,
- vars,
- inherit_env,
- /* sync = */ true)) {
+ : impl_(new ProcessSpawnImpl(sync, executable, args, vars, inherit_env)) {
}
std::string
/// @brief Constructor.
///
- /// @param io_service The IOService which handles signal handlers.
+ /// @param sync enables synchronous mode (spawning thread waits on
+ /// child to complete if true)
/// @param executable A full path to the program to be executed.
/// @param args Arguments for the program to be executed.
/// @param vars Environment variables for the program to be executed.
/// @param inherit_env whether the spawned process will inherit the
- /// environment before adding 'vars' on top.
- ProcessSpawn(isc::asiolink::IOServicePtr io_service,
+ /// environment before adding 'vars' on top.
+ ProcessSpawn(bool sync,
const std::string& executable,
const ProcessArgs& args = ProcessArgs(),
const ProcessEnvVars& vars = ProcessEnvVars(),
const bool inherit_env = false);
- /// @brief Constructor for synchronous spawn and wait.
- ///
- /// Abstracts away the IO service detail since the caller is not
- /// required to interact with it in sync mode.
- ///
- /// @param executable A full path to the program to be executed.
- /// @param args Arguments for the program to be executed.
- /// @param vars Environment variables for the program to be executed.
- /// @param inherit_env whether the spawned process will inherit the
- /// environment before adding 'vars' on top.
- ProcessSpawn(const std::string& executable,
- const ProcessArgs& args = ProcessArgs(),
- const ProcessEnvVars& vars = ProcessEnvVars(),
- const bool inherit_env = false);
-
/// @brief Destructor.
~ProcessSpawn() = default;
/// @param pid A process pid.
void clearState(const pid_t pid);
+ /// @brief Get the I/O service.
+ ///
+ /// @return the I/O service.
+ static isc::asiolink::IOServicePtr getIOService() {
+ return (io_service_);
+ }
+
+ /// @brief Set the I/O service.
+ ///
+ /// @param io_service the I/O service.
+ static void setIOService(isc::asiolink::IOServicePtr io_service) {
+ io_service_ = io_service;
+ }
+
private:
+ /// @brief The IOService object, used for all ASIO operations.
+ static isc::asiolink::IOServicePtr io_service_;
+
/// @brief A smart pointer to the implementation of this class.
ProcessSpawnImplPtr impl_;
};
ProcessSpawnTest() :
io_service_(getIOService()), test_timer_(io_service_),
test_time_ms_(0), io_signal_set_(), processed_signals_() {
+ ProcessSpawn::setIOService(getIOService());
io_signal_set_.reset(new IOSignalSet(io_service_,
std::bind(&ProcessSpawnTest::processSignal,
args.push_back("-e");
args.push_back("64");
- ProcessSpawn process(io_service_, TEST_SCRIPT_SH, args);
+ ProcessSpawn process(false, TEST_SCRIPT_SH, args);
pid_t pid = 0;
ASSERT_NO_THROW(pid = process.spawn());
args.push_back("TEST_VARIABLE_VALUE");
vars.push_back("TEST_VARIABLE_NAME=TEST_VARIABLE_VALUE");
- ProcessSpawn process(io_service_, TEST_SCRIPT_SH, args, vars);
+ ProcessSpawn process(false, TEST_SCRIPT_SH, args, vars);
pid_t pid = 0;
ASSERT_NO_THROW(pid = process.spawn());
vector<string> args;
args.push_back("-p");
- ProcessSpawn process(io_service_, TEST_SCRIPT_SH, args);
+ ProcessSpawn process(false, TEST_SCRIPT_SH, args);
pid_t pid1 = 0;
ASSERT_NO_THROW(pid1 = process.spawn());
// This test verifies that the external application can be ran without
// arguments and that the exit code is gathered.
TEST_F(ProcessSpawnTest, spawnNoArgs) {
- ProcessSpawn process(io_service_, TEST_SCRIPT_SH);
+ ProcessSpawn process(false, TEST_SCRIPT_SH);
pid_t pid = 0;
ASSERT_NO_THROW(pid = process.spawn());
// application can't be executed.
TEST_F(ProcessSpawnTest, invalidExecutable) {
std::string expected = "File not found: foo";
- ASSERT_THROW_MSG(ProcessSpawn process(io_service_, "foo"),
+ ASSERT_THROW_MSG(ProcessSpawn process(false, "foo"),
ProcessSpawnError, expected);
std::string name = INVALID_TEST_SCRIPT_SH;
expected = "File not executable: ";
expected += name;
- ASSERT_THROW_MSG(ProcessSpawn process(io_service_, name),
+ ASSERT_THROW_MSG(ProcessSpawn process(false, name),
ProcessSpawnError, expected);
}
args.push_back("-y");
args.push_back("foo");
args.push_back("bar");
- ProcessSpawn process(io_service_, TEST_SCRIPT_SH, args);
+ ProcessSpawn process(false, TEST_SCRIPT_SH, args);
std::string expected = TEST_SCRIPT_SH;
expected += " -x -y foo bar";
EXPECT_EQ(expected, process.getCommandLine());
{
// Case 2: no arguments.
- ProcessSpawn process(io_service_, TEST_SCRIPT_SH);
+ ProcessSpawn process(false, TEST_SCRIPT_SH);
EXPECT_EQ(TEST_SCRIPT_SH, process.getCommandLine());
}
}
args.push_back("-s");
args.push_back("10");
- ProcessSpawn process(io_service_, TEST_SCRIPT_SH, args);
+ ProcessSpawn process(false, TEST_SCRIPT_SH, args);
pid_t pid = 0;
ASSERT_NO_THROW(pid = process.spawn());
ProcessEnvVars vars{"VAR=value"};
- ProcessSpawn process(io_service_, TEST_SCRIPT_SH, args, vars,
+ ProcessSpawn process(false, TEST_SCRIPT_SH, args, vars,
/* inherit_env = */ true);
pid_t pid = 0;
ASSERT_NO_THROW(pid = process.spawn());
ProcessEnvVars vars{"VAR=value"};
- ProcessSpawn process(io_service_, TEST_SCRIPT_SH, args, vars,
+ ProcessSpawn process(false, TEST_SCRIPT_SH, args, vars,
/* inherit_env = */ true);
pid_t pid = 0;
ASSERT_NO_THROW(pid = process.spawn());
args.push_back("-e");
args.push_back("64");
- ProcessSpawn process(TEST_SCRIPT_SH, args);
+ ProcessSpawn process(true, TEST_SCRIPT_SH, args);
pid_t pid = 0;
ASSERT_NO_THROW(pid = process.spawn());
args.push_back("TEST_VARIABLE_VALUE");
vars.push_back("TEST_VARIABLE_NAME=TEST_VARIABLE_VALUE");
- ProcessSpawn process(TEST_SCRIPT_SH, args, vars);
+ ProcessSpawn process(true, TEST_SCRIPT_SH, args, vars);
pid_t pid = 0;
ASSERT_NO_THROW(pid = process.spawn());
vector<string> args;
args.push_back("-p");
- ProcessSpawn process(TEST_SCRIPT_SH, args);
+ ProcessSpawn process(true, TEST_SCRIPT_SH, args);
pid_t pid1 = 0;
ASSERT_NO_THROW(pid1 = process.spawn());
// This test verifies that the external application can be ran synchronously
// without arguments and that the exit code is gathered.
TEST_F(ProcessSpawnTest, spawnNoArgsSync) {
- ProcessSpawn process(TEST_SCRIPT_SH);
+ ProcessSpawn process(true, TEST_SCRIPT_SH);
pid_t pid = 0;
ASSERT_NO_THROW(pid = process.spawn());
// application can't be executed synchronously.
TEST_F(ProcessSpawnTest, invalidExecutableSync) {
std::string expected = "File not found: foo";
- ASSERT_THROW_MSG(ProcessSpawn process("foo"),
+ ASSERT_THROW_MSG(ProcessSpawn process(true, "foo"),
ProcessSpawnError, expected);
std::string name = INVALID_TEST_SCRIPT_SH;
expected = "File not executable: ";
expected += name;
- ASSERT_THROW_MSG(ProcessSpawn process(name),
+ ASSERT_THROW_MSG(ProcessSpawn process(true, name),
ProcessSpawnError, expected);
}
args.push_back("-y");
args.push_back("foo");
args.push_back("bar");
- ProcessSpawn process(TEST_SCRIPT_SH, args);
+ ProcessSpawn process(true, TEST_SCRIPT_SH, args);
std::string expected = TEST_SCRIPT_SH;
expected += " -x -y foo bar";
EXPECT_EQ(expected, process.getCommandLine());
{
// Case 2: no arguments.
- ProcessSpawn process(TEST_SCRIPT_SH);
+ ProcessSpawn process(true, TEST_SCRIPT_SH);
EXPECT_EQ(TEST_SCRIPT_SH, process.getCommandLine());
}
}
// This test verifies that the synchronous process reports as not running after
// it was spawned.
TEST_F(ProcessSpawnTest, isRunningSync) {
- ProcessSpawn process(TEST_SCRIPT_SH);
+ ProcessSpawn process(true, TEST_SCRIPT_SH);
pid_t pid = 0;
ASSERT_NO_THROW(pid = process.spawn());
ProcessEnvVars vars{"VAR=value"};
- ProcessSpawn process(TEST_SCRIPT_SH, args, vars,
+ ProcessSpawn process(true, TEST_SCRIPT_SH, args, vars,
/* inherit_env = */ true);
pid_t pid = 0;
ASSERT_NO_THROW(pid = process.spawn());
ProcessEnvVars vars{"VAR=value"};
- ProcessSpawn process(TEST_SCRIPT_SH, args, vars,
+ ProcessSpawn process(true, TEST_SCRIPT_SH, args, vars,
/* inherit_env = */ true);
pid_t pid = 0;
ASSERT_NO_THROW(pid = process.spawn());
#include <config.h>
#include <asiolink/addr_utilities.h>
-#include <database/database_connection.h>
#include <dhcpsrv/cfg_consistency.h>
#include <dhcpsrv/cfgmgr.h>
#include <dhcpsrv/dhcpsrv_exceptions.h>
args.push_back("ignored-path");
// Create the process (do not start it yet).
- process_.reset(new ProcessSpawn(DatabaseConnection::getIOService(), executable, args));
+ process_.reset(new ProcessSpawn(false, executable, args));
// If we've been told to run it once now, invoke the callback directly.
if (run_once_now) {
timer_mgr_->setIOService(io_service_);
DatabaseConnection::setIOService(io_service_);
+ ProcessSpawn::setIOService(io_service_);
std::ostringstream s;
s << KEA_LFC_BUILD_DIR << "/kea-lfc";
kea_admin_parameters.insert(kea_admin_parameters.begin(), "db-init");
// Run.
- ProcessSpawn kea_admin(KEA_ADMIN_, kea_admin_parameters, vars,
+ ProcessSpawn kea_admin(true, KEA_ADMIN_, kea_admin_parameters, vars,
/* inherit_env = */ true);
DB_LOG_INFO(MYSQL_INITIALIZE_SCHEMA).arg(kea_admin.getCommandLine());
pid_t const pid(kea_admin.spawn());
kea_admin_parameters.insert(kea_admin_parameters.begin(), "db-init");
// Run.
- ProcessSpawn kea_admin(KEA_ADMIN_, kea_admin_parameters, vars,
+ ProcessSpawn kea_admin(true, KEA_ADMIN_, kea_admin_parameters, vars,
/* inherit_env = */ true);
DB_LOG_INFO(PGSQL_INITIALIZE_SCHEMA).arg(kea_admin.getCommandLine());
pid_t const pid(kea_admin.spawn());