Leosac  0.8.0
Open Source Access Control
module_manager.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2014-2016 Leosac
3 
4  This file is part of Leosac.
5 
6  Leosac is free software: you can redistribute it and/or modify
7  it under the terms of the GNU Affero General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  Leosac is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU Affero General Public License for more details.
15 
16  You should have received a copy of the GNU Affero General Public License
17  along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #include "module_manager.hpp"
21 #include "core/kernel.hpp"
23 #include "tools/log.hpp"
24 #include "tools/unixfs.hpp"
25 
27 using namespace Leosac;
28 
30  : ctx_(ctx)
31  , config_manager_(k.config_manager())
32  , core_utils_(k.core_utils())
33 {
34 }
35 
37 {
38  try
39  {
40  stopModules();
42  }
43  catch (const std::exception &e)
44  {
46  }
47  catch (...)
48  {
49  std::cerr << "Unkown exception in ModuleManager destructor" << std::endl;
50  }
51 }
52 
54 {
55  for (auto &module_info : modules_)
56  {
57  try
58  {
59  module_info.lib_->close();
60  }
61  catch (const DynLibException &e)
62  {
63  std::throw_with_nested(ModuleException("Unloading library failed."));
64  }
65  }
66  modules_.clear();
67 }
68 
70 {
71  for (const ModuleInfo &module_info : modules_)
72  {
73  // fixme ... that cast.
74  initModule(const_cast<ModuleInfo *>(&module_info));
75  }
76 }
77 
79 {
80  assert(modinfo);
81  // if not null, may still be running
82  assert(modinfo->actor_ == nullptr);
83  assert(modinfo->lib_);
84  using namespace Colorize;
85 
86  try
87  {
88  char *(*module_name_fct)(void) =
89  (char *(*)(void))modinfo->lib_->getSymbol("get_module_name");
90  assert(module_name_fct);
91  std::string module_exported_name(module_name_fct());
92 
93  if (modinfo->name_ != module_exported_name)
94  {
95  std::stringstream error;
96  error << "Missconfiguration: Configured module name doesn't match the "
97  "name exported by the module. "
98  << "(" << modinfo->name_ << " != " << module_exported_name << ")";
99  ERROR(error.str());
100  throw ConfigException("main configuration file", error.str());
101  }
102 
103  void *symptr = modinfo->lib_->getSymbol("start_module");
104  assert(symptr);
105  // take the module init function and make a std::function out of it.
106  std::function<bool(zmqpp::socket *, boost::property_tree::ptree,
107  zmqpp::context &, CoreUtilsPtr)>
108  actor_fun = ((bool (*)(zmqpp::socket *, boost::property_tree::ptree,
109  zmqpp::context &, CoreUtilsPtr))symptr);
110 
111  auto new_module = std::unique_ptr<zmqpp::actor>(
112  new zmqpp::actor(std::bind(actor_fun, std::placeholders::_1,
114  std::ref(ctx_), core_utils_)));
115  modinfo->actor_ = std::move(new_module);
116 
117  INFO("Module "
118  << green(modinfo->name_) << " initialized. (level = "
119  << config_manager_.load_config(modinfo->name_).get<int>("level", 100)
120  << ")");
121  }
122  catch (std::exception &e)
123  {
124  ERROR("Unable to init module " << red(modinfo->name_)
125  << ". See below for "
126  "exception information.");
127  log_exception(e);
128  std::throw_with_nested(ModuleException(
129  "Unable to init module " + red(modinfo->name_) + ": " + e.what()));
130  }
131 }
132 
133 bool ModuleManager::initModule(const std::string &name)
134 {
135  if (ModuleInfo *ptr = find_module_by_name(name))
136  {
137  initModule(ptr);
138  return true;
139  }
140  else
141  {
142  WARN("Cannot find any module nammed " << name);
143  return false;
144  }
145  return false;
146 }
147 
148 void ModuleManager::addToPath(const std::string &dir)
149 {
150  if (std::find(path_.begin(), path_.end(), dir) == path_.end())
151  path_.push_back(dir);
152 }
153 
154 bool ModuleManager::loadModule(const std::string &module_name)
155 {
156  const auto &cfg = config_manager_.load_config(module_name);
157  std::string filename = cfg.get_child("file").data();
158 
159  INFO("Attempting to load module nammed "
160  << module_name << " (shared lib file = " << filename << ")");
161  for (const std::string &path_entry : path_)
162  {
163  // fixme not clean enough.
164  if (UnixFs::fileExists(path_entry + "/" + filename))
165  {
166  ModuleInfo module_info(config_manager_);
167 
168  module_info.name_ = module_name;
169 
170  if (!(module_info.lib_ = load_library_file(path_entry + "/" + filename)))
171  return false;
172  modules_.insert(std::move(module_info));
173  DEBUG("library file loaded (not init yet)");
174  return true;
175  }
176  }
177  ERROR("Could'nt load this module (file not found)");
178  return false;
179 }
180 
181 std::shared_ptr<DynamicLibrary>
182 ModuleManager::load_library_file(const std::string &full_path)
183 {
184  INFO("Loading library at: " << full_path);
185  std::shared_ptr<DynamicLibrary> lib(new DynamicLibrary(full_path));
186  try
187  {
189  }
190  catch (const DynLibException &e)
191  {
192  ERROR("FAILURE, full path was:{" << full_path << "}: " << e.what());
193  return nullptr;
194  }
195  return lib;
196 }
197 
199 {
200  for (auto itr = modules_.rbegin(); itr != modules_.rend(); ++itr)
201  {
202  stopModule(const_cast<ModuleInfo *>(&(*itr)), soft);
203  }
204  if (!soft)
205  {
206  modules_.clear();
207  assert(modules_.size() == 0);
208  }
209 }
210 
211 void ModuleManager::stopModule(ModuleInfo *modinfo, bool soft)
212 {
213  assert(modinfo);
214 
215  // make sure the module is running.
216  if (modinfo->actor_)
217  {
218  INFO("Will now stop module " << modinfo->name_ << " (Soft Stop: " << soft
219  << ")");
220  // fixme i believe we may have a potential deadlock here.
221  if (soft)
222  {
223  modinfo->actor_->stop(false);
224  }
225  else
226  {
227  modinfo->actor_->stop(true);
228  modinfo->actor_ = nullptr;
229  }
230  // modules_.erase(*modinfo);
231  // config_manager_.remove_config(modinfo->name_);
232  }
233  else
234  {
235  INFO("Not stopping module " << modinfo->name_
236  << " as it doesn't seem to run.");
237  }
238 }
239 
240 bool ModuleManager::stopModule(const std::string &name)
241 {
242  if (ModuleInfo *ptr = find_module_by_name(name))
243  {
244  stopModule(ptr);
245  // config_manager_.remove_config(name);
246  return true;
247  }
248  else
249  {
250  WARN("Cannot find any module nammed " << name);
251  return false;
252  }
253  return false;
254 }
255 
257 {
258 }
259 
261  : lib_(nullptr)
262  , actor_(nullptr)
263  , cfg_(cfg)
264 {
265 }
266 
268  : cfg_(o.cfg_)
269 {
270  actor_ = std::move(o.actor_);
271  lib_ = o.lib_;
272  name_ = o.name_;
273 
274  o.actor_ = nullptr;
275  o.lib_ = nullptr;
276 }
277 
278 std::vector<std::string> ModuleManager::modules_names() const
279 {
280  std::vector<std::string> ret;
281 
282  ret.reserve(modules_.size());
283  for (auto const &module : modules_)
284  {
285  ret.push_back(module.name_);
286  }
287  return ret;
288 }
289 
291 ModuleManager::find_module_by_name(const std::string &name) const
292 {
293  auto itr = std::find_if(modules_.begin(), modules_.end(),
294  [&](const ModuleInfo &m) { return m.name_ == name; });
295 
296  if (itr != modules_.end())
297  return const_cast<ModuleInfo *>(&(*itr));
298  return nullptr;
299 }
300 
301 bool ModuleManager::has_module(const std::string &name) const
302 {
303  return find_module_by_name(name) != nullptr;
304 }
305 
306 std::vector<std::string> const &ModuleManager::get_module_path() const
307 {
308  return path_;
309 }
310 
312 {
313  int level_me = cfg_.load_config(name_).get<int>("level", 100);
314  int level_o = cfg_.load_config(o.name_).get<int>("level", 100);
315 
316  return level_me < level_o;
317 }
Leosac::print_exception
void print_exception(const std::exception &e, int level=0)
Recursively print the exception trace to std::cerr.
Definition: ExceptionsTools.cpp:44
ModuleManager::ModuleInfo::operator<
bool operator<(const ModuleInfo &o) const
Definition: module_manager.cpp:311
LEOSACException::what
virtual const char * what() const noexcept final
Definition: leosacexception.hpp:53
Leosac::ConfigManager::load_config
const boost::property_tree::ptree & load_config(const std::string &module) const
Return the stored configuration for a given module.
Definition: ConfigManager.cpp:133
ModuleManager::ModuleInfo::actor_
std::unique_ptr< zmqpp::actor > actor_
Actor object that runs the module code.
Definition: module_manager.hpp:101
WARN
@ WARN
Definition: log.hpp:33
Leosac::ConfigManager
That class helps manage the configuration for the application and its module.
Definition: ConfigManager.hpp:45
Leosac::log_exception
void log_exception(const std::exception &e, int level=0)
Recursively log exceptions using the logging macro.
Definition: ExceptionsTools.cpp:62
ERROR
@ ERROR
Definition: log.hpp:32
DEBUG
@ DEBUG
Definition: log.hpp:35
DynLibException
Definition: dynlibexception.hpp:33
ModuleManager::ModuleManager
ModuleManager(zmqpp::context &ctx, Leosac::Kernel &k)
Construct the module manager.
Definition: module_manager.cpp:29
INFO
@ INFO
Definition: log.hpp:34
DynamicLibrary
Wraps a dynamic library handler and provide methods to interact with it.
Definition: dynamiclibrary.hpp:38
ExceptionsTools.hpp
ModuleManager::initModules
void initModules()
Actually call the init_module() function of each library we loaded.
Definition: module_manager.cpp:69
ModuleException
Definition: moduleexception.hpp:33
ModuleManager::core_utils_
Leosac::CoreUtilsPtr core_utils_
Definition: module_manager.hpp:218
ModuleManager::~ModuleManager
~ModuleManager()
Definition: module_manager.cpp:36
unixfs.hpp
unix filesystem helper functions
Leosac
This is the header file for a generated source file, GitSHA1.cpp.
Definition: APIStatusCode.hpp:22
kernel.hpp
DynamicLibrary::open
void open(RelocationMode mode=RelocationMode::Lazy)
Attempts to open the shared library file so that we can access its symbols.
Definition: dynamiclibrary.cpp:35
ModuleManager::find_module_by_name
ModuleInfo * find_module_by_name(const std::string &name) const
Definition: module_manager.cpp:291
ModuleManager::modules_names
std::vector< std::string > modules_names() const
Returns the list of the name of the loaded modules.
Definition: module_manager.cpp:278
ModuleManager::get_module_path
const std::vector< std::string > & get_module_path() const
Return the list of paths where we search for module.
Definition: module_manager.cpp:306
ConfigException
Definition: configexception.hpp:87
Leosac::Colorize::green
std::string green(const T &in)
Definition: Colorize.hpp:82
ModuleManager::load_library_file
std::shared_ptr< DynamicLibrary > load_library_file(const std::string &full_path)
This will load (actually calling dlopen()) the library file located at full_path.
Definition: module_manager.cpp:182
ModuleManager::ModuleInfo::ModuleInfo
ModuleInfo(const Leosac::ConfigManager &cfg)
Definition: module_manager.cpp:260
ModuleManager::ModuleInfo::~ModuleInfo
~ModuleInfo()
Definition: module_manager.cpp:256
ModuleManager::initModule
bool initModule(const std::string &name)
Attempt to find a module using its name, then load it.
Definition: module_manager.cpp:133
ModuleManager::config_manager_
Leosac::ConfigManager & config_manager_
Definition: module_manager.hpp:217
Leosac::Tools::UnixFs
Definition: unixfs.hpp:39
ModuleManager::modules_
std::set< ModuleInfo > modules_
Definition: module_manager.hpp:214
Leosac::Kernel
Core of Leosac.
Definition: kernel.hpp:73
Leosac::Colorize::red
std::string red(const T &in)
Definition: Colorize.hpp:70
ModuleManager::ModuleInfo
Internal helper struct that store informations related to module that are useful to the module manage...
Definition: module_manager.hpp:73
module_manager.hpp
ModuleManager::ctx_
zmqpp::context & ctx_
Definition: module_manager.hpp:216
log.hpp
ModuleManager::stopModules
void stopModules(bool soft=false)
Opposite of init module.
Definition: module_manager.cpp:198
ModuleManager::addToPath
void addToPath(const std::string &dir)
Add a directory to a path.
Definition: module_manager.cpp:148
ModuleManager::has_module
bool has_module(const std::string &name) const
Do we have some informations about the module "name".
Definition: module_manager.cpp:301
ModuleManager::loadModule
bool loadModule(const std::string &module_name)
Search the path and load a module based on a property tree for this module.
Definition: module_manager.cpp:154
Leosac::CoreUtilsPtr
std::shared_ptr< CoreUtils > CoreUtilsPtr
Definition: LeosacFwd.hpp:35
DynamicLibrary::RelocationMode::Now
@ Now
ModuleManager::stopModule
bool stopModule(const std::string &name)
Stop a module by name and remove its config info from the config manager.
Definition: module_manager.cpp:240
ModuleManager::ModuleInfo::name_
std::string name_
Name of the module, as specified in the configuration file.
Definition: module_manager.hpp:91
ModuleManager::unloadLibraries
void unloadLibraries()
Close library handler.
Definition: module_manager.cpp:53
ModuleManager::path_
std::vector< std::string > path_
Definition: module_manager.hpp:213
ModuleManager::ModuleInfo::lib_
std::shared_ptr< DynamicLibrary > lib_
Pointer to the library object.
Definition: module_manager.hpp:96