Skip to content

Commit

Permalink
[?] Use setup and teardown hooks for REP static initialization.
Browse files Browse the repository at this point in the history
  • Loading branch information
korydraughn committed Oct 21, 2024
1 parent 6541cca commit 0b8957d
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 57 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ void initialize_microservice_table()

extern Cache ruleEngineConfig;

irods::error start(irods::default_re_ctx&, const std::string& _instance_name)
irods::error setup(irods::default_re_ctx&, const std::string& _instance_name)
{
local_instance_name = _instance_name;

Expand Down Expand Up @@ -178,11 +178,7 @@ irods::error start(irods::default_re_ctx&, const std::string& _instance_name)
logger::rule_engine::error(msg);

return ERROR(SYS_INVALID_INPUT_PARAM, msg);
} // start

irods::error stop(irods::default_re_ctx& _u, const std::string& _instance_name) {
return SUCCESS();
}
} // setup

irods::error rule_exists(irods::default_re_ctx&, const std::string& _rn, bool& _ret) {
if(ruleEngineConfig.ruleEngineStatus == UNINITIALIZED) {
Expand Down Expand Up @@ -419,13 +415,17 @@ irods::error exec_rule_expression(

extern "C"
irods::pluggable_rule_engine<irods::default_re_ctx>* plugin_factory( const std::string& _inst_name,
const std::string& _context ) {
irods::pluggable_rule_engine<irods::default_re_ctx>* re = new irods::pluggable_rule_engine<irods::default_re_ctx>( _inst_name , _context);
re->add_operation( "start",
std::function<irods::error(irods::default_re_ctx&,const std::string&)>( start ) );
const std::string& _context )
{
const auto no_op = [](irods::default_re_ctx&, const std::string&) { return SUCCESS(); };

auto* re = new irods::pluggable_rule_engine<irods::default_re_ctx>( _inst_name , _context);

re->add_operation("setup", std::function{setup});
re->add_operation("teardown", std::function{no_op});

re->add_operation( "stop",
std::function<irods::error(irods::default_re_ctx&,const std::string&)>( stop ) );
re->add_operation("start", std::function{no_op});
re->add_operation("stop", std::function{no_op});

re->add_operation( "rule_exists",
std::function<irods::error(irods::default_re_ctx&, const std::string&, bool&)>( rule_exists ) );
Expand Down
8 changes: 8 additions & 0 deletions plugins/rule_engines/src/cpp_default_policy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1171,6 +1171,14 @@ extern "C"
irods::pluggable_rule_engine<irods::default_re_ctx>* plugin_factory( const std::string& _inst_name,
const std::string& _context ) {
irods::pluggable_rule_engine<irods::default_re_ctx>* re = new irods::pluggable_rule_engine<irods::default_re_ctx>( _inst_name , _context);

const auto no_op = [](irods::default_re_ctx&, const std::string&) -> irods::error {
return SUCCESS();
};

re->add_operation("setup", std::function{no_op});
re->add_operation("teardown", std::function{no_op});

re->add_operation( "start",
std::function<irods::error(irods::default_re_ctx&, const std::string&)>( start ) );

Expand Down
60 changes: 20 additions & 40 deletions plugins/rule_engines/src/passthrough.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,49 +33,24 @@ namespace
int code;
};

// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
std::unordered_map<std::string, std::vector<pep_config>> pep_configs;

// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
int matched_code = 0;

template <typename ...Args>
using operation = std::function<irods::error(irods::default_re_ctx&, Args...)>;

irods::error start(irods::default_re_ctx&, const std::string& _instance_name)
irods::error setup(irods::default_re_ctx&, const std::string& _instance_name)
{
std::string config_path;

if (auto error = irods::get_full_path_for_config_file("server_config.json", config_path);
!error.ok())
{
std::string msg = "Server configuration not found [path => ";
msg += config_path;
msg += ']';

// clang-format off
log::rule_engine::error({{"rule_engine_plugin", "passthrough"},
{"rule_engine_plugin_function", __func__},
{"log_message", msg}});
// clang-format on

return ERROR(SYS_CONFIG_FILE_ERR, msg.c_str());
}

// clang-format off
log::rule_engine::trace({{"rule_engine_plugin", "passthrough"},
{"rule_engine_plugin_function", __func__},
{"log_message", "Reading plugin configuration ..."}});
// clang-format on

nlohmann::json config;

{
std::ifstream config_file{config_path};
config_file >> config;
}

try {
const auto config_handle = irods::server_properties::server_properties::instance().map();
const auto& config = config_handle.get_json();

// Iterate over the list of rule engine plugins until the Passthrough REP is found.
for (const auto& re : config.at(irods::KW_CFG_PLUGIN_CONFIGURATION).at(irods::KW_CFG_PLUGIN_TYPE_RULE_ENGINE)) {
if (_instance_name == re.at(irods::KW_CFG_INSTANCE_NAME).get<std::string>()) {
if (_instance_name == re.at(irods::KW_CFG_INSTANCE_NAME).get_ref<const std::string&>()) {
// Fill the "pep_configs" plugin variable with objects containing the values
// defined in the "return_codes_for_peps" configuration. Each object in the list
// will contain a regular expression and a code.
Expand All @@ -98,10 +73,10 @@ namespace
}

return ERROR(SYS_CONFIG_FILE_ERR, "[passthrough] Bad rule engine plugin configuration");
}
} // setup

irods::error rule_exists(const std::string& _instance_name,
irods::default_re_ctx&,
[[maybe_unused]] irods::default_re_ctx& _ctx,
const std::string& _rule_name,
bool& _exists)
{
Expand All @@ -123,17 +98,18 @@ namespace
return SUCCESS();
}

irods::error list_rules(irods::default_re_ctx&, std::vector<std::string>& _rules)
irods::error list_rules(irods::default_re_ctx&, [[maybe_unused]] std::vector<std::string>& _rules)
{
log::rule_engine::trace({{"rule_engine_plugin", "passthrough"}, {"rule_engine_plugin_function", __func__}});
return SUCCESS();
}

irods::error exec_rule(const std::string& _instance_name,
irods::default_re_ctx&,
[[maybe_unused]] irods::default_re_ctx& _ctx,
const std::string& _rule_name,
std::list<boost::any>& _rule_arguments,
irods::callback _effect_handler)
[[maybe_unused]] std::list<boost::any>& _rule_arguments,
// NOLINTNEXTLINE(performance-unnecessary-value-param)
[[maybe_unused]] irods::callback _effect_handler)
{
std::string msg = "Returned '";
msg += std::to_string(matched_code);
Expand Down Expand Up @@ -185,12 +161,16 @@ pluggable_rule_engine* plugin_factory(const std::string& _instance_name,
std::list<boost::any>& _rule_arguments,
irods::callback _effect_handler)
{
// NOLINTNEXTLINE(performance-unnecessary-value-param)
return exec_rule(_instance_name, _ctx, _rule_name, _rule_arguments, _effect_handler);
};

// NOLINTNEXTLINE(cppcoreguidelines-owning-memory)
auto* re = new pluggable_rule_engine{_instance_name, _context};

re->add_operation("start", operation<const std::string&>{start});
re->add_operation("setup", operation<const std::string&>{setup});
re->add_operation("teardown", operation<const std::string&>{no_op});
re->add_operation("start", operation<const std::string&>{no_op});
re->add_operation("stop", operation<const std::string&>{no_op});
re->add_operation("rule_exists", operation<const std::string&, bool&>{rule_exists_wrapper});
re->add_operation("list_rules", operation<std::vector<std::string>&>{list_rules});
Expand Down
10 changes: 9 additions & 1 deletion server/main_server/src/agent_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,8 @@ int main(int _argc, char* _argv[])
}
}};

// TODO Why is this necessary?
// Initialize the global rule engine plugin facilities.
// This is where the rule engine plugins are loaded (i.e. plugin_factory is invoked here).
irods::re_plugin_globals = std::make_unique<irods::global_re_plugin_mgr>();

// Initialize zone information for request processing.
Expand All @@ -320,6 +321,10 @@ int main(int _argc, char* _argv[])
return 1;
}

// Run setup() for each rule engine plugin.
// This allows rule engine plugins to setup state which doesn't change frequently.
irods::re_plugin_globals->global_re_mgr.call_setup_operations();

// Enter parent process main loop.
//
// This process should never introduce threads. Everything it cares about must be handled
Expand Down Expand Up @@ -426,6 +431,9 @@ int main(int _argc, char* _argv[])
// Do not accept new client requests (i.e. close the listening socket).
close(svrComm.sock);

// Give the rule engine plugins a chance to free any resources established during setup().
irods::re_plugin_globals->global_re_mgr.call_teardown_operations();

if (0 == g_terminate_graceful) {
// Instruct all agents to shutdown gracefully.
// To avoid unnecessary complexity, we use SIGUSR1 as the termination signal for agents.
Expand Down
2 changes: 1 addition & 1 deletion server/main_server/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ auto main(int _argc, char* _argv[]) -> int
}

if (create_pid_file(pid_file) != 0) {
fmt::print(stderr, "Error: could not create PID file [{}].", pid_file);
fmt::print(stderr, "Error: could not create PID file [{}].\n", pid_file);
return 1;
}
}
Expand Down
48 changes: 45 additions & 3 deletions server/re/include/irods/irods_re_plugin.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@
#include "irods/irods_re_structs.hpp"
#include "irods/irods_state_table.h"

#include <boost/any.hpp>
#include <boost/algorithm/string.hpp>

#include <fmt/format.h>

#include <functional>
#include <initializer_list>
#include <iostream>
Expand All @@ -17,9 +22,6 @@
#include <utility>
#include <vector>

#include <boost/any.hpp>
#include <boost/algorithm/string.hpp>

#ifdef IRODS_ENABLE_SYSLOG
# define IRODS_SERVER_ONLY(x) x
# include "irods/irods_logger.hpp"
Expand Down Expand Up @@ -193,6 +195,34 @@ namespace irods {

}

error setup_operation(T& _in)
{
try {
auto fcn = boost::any_cast<std::function<error(T&,const std::string&)>>(operations_["setup"]);
return fcn(_in, instance_name_);
}
catch (const boost::bad_any_cast& e) {
return ERROR(INVALID_ANY_CAST, fmt::format("failed to extract setup operation from instance [{}]: {}", instance_name_, e.what()));
}
catch (const std::exception& e) {
return ERROR(PLUGIN_ERROR, fmt::format("failed to extract setup operation from instance [{}]: {}", instance_name_, e.what()));
}
} // setup_operation

error teardown_operation(T& _in)
{
try {
auto fcn = boost::any_cast<std::function<error(T&,const std::string&)>>(operations_["teardown"]);
return fcn(_in, instance_name_);
}
catch (const boost::bad_any_cast& e) {
return ERROR(INVALID_ANY_CAST, fmt::format("failed to extract teardown operation from instance [{}]: {}", instance_name_, e.what()));
}
catch (const std::exception& e) {
return ERROR(PLUGIN_ERROR, fmt::format("failed to extract teardown operation from instance [{}]: {}", instance_name_, e.what()));
}
} // teardown_operation

error start_operation(T& _in) {
try {
auto fcn = boost::any_cast<std::function<error(T&,const std::string&)>>( operations_["start"] );
Expand Down Expand Up @@ -418,6 +448,18 @@ namespace irods {
return SUCCESS();
}

void call_setup_operations() {
std::for_each(begin(re_packs_), end(re_packs_), [](re_pack_inp<T> &_inp) {
_inp.re_->setup_operation(_inp.re_ctx_);
});
}

void call_teardown_operations() {
std::for_each(begin(re_packs_), end(re_packs_), [](re_pack_inp<T> &_inp) {
_inp.re_->teardown_operation(_inp.re_ctx_);
});
}

void call_start_operations() {
std::for_each(begin(re_packs_), end(re_packs_), [](re_pack_inp<T> &_inp) {
_inp.re_->start_operation(_inp.re_ctx_);
Expand Down

0 comments on commit 0b8957d

Please sign in to comment.