Leosac  0.8.0
Open Source Access Control
RemoteConfigCollector.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 
26 #include "tools/BuildString.hpp"
28 #include "tools/log.hpp"
29 #include <zmqpp/curve.hpp>
30 
31 using namespace Leosac;
32 
34  std::string const &remote_endpoint,
35  std::string const &remote_pk)
36  : remote_endpoint_(remote_endpoint)
37  , remote_pk_(remote_pk)
38  , sock_(ctx, zmqpp::socket_type::dealer)
39  , mstimeout_(5000)
40  , first_call_(true)
41  , succeed_(false)
42 {
43  auto kp = zmqpp::curve::generate_keypair();
44  sock_.set(zmqpp::socket_option::curve_secret_key, kp.secret_key);
45  sock_.set(zmqpp::socket_option::curve_public_key, kp.public_key);
46  sock_.set(zmqpp::socket_option::curve_server_key, remote_pk);
47  sock_.set(zmqpp::socket_option::linger, 0);
48  poller_.add(sock_);
49 }
50 
51 
52 static bool warn_and_set_error(std::string *error_str, const std::string &msg)
53 {
54  WARN(msg);
55  if (error_str)
56  *error_str = msg;
57  return false;
58 }
59 
60 bool RemoteConfigCollector::fetch_config(std::string *error_str) noexcept
61 {
62  assert(first_call_);
63  first_call_ = false;
64 
65  try
66  {
67  sock_.connect(remote_endpoint_);
68  if (!fetch_remote_config_version(remote_version_))
69  return warn_and_set_error(error_str,
70  "Cannot retrieve remote config version.");
71 
72  if (!fetch_general_config())
73  return warn_and_set_error(
74  error_str,
75  build_str("Error fetching general configuration of remote Leosac (",
76  remote_endpoint_, ")"));
77 
78  if (!fetch_module_list())
79  return warn_and_set_error(
80  error_str,
81  build_str("Error fetching module list from remote Leosac (",
82  remote_endpoint_, ")"));
83 
84  if (!fetch_modules_config())
85  return warn_and_set_error(
86  error_str,
87  build_str(
88  "Error fetching modules configuration from remote Leosac (",
89  remote_endpoint_, ")"));
90  // fetch the version again, and compare
91  uint64_t version2;
92  if (!fetch_remote_config_version(version2))
93  return warn_and_set_error(
94  error_str, build_str("Cannot retrieve remote config version."));
95  if (version2 != remote_version_)
96  return warn_and_set_error(error_str,
97  build_str("Looks like configuration changed "
98  "while we were retrieving it."));
99  succeed_ = true;
100  return true;
101  }
102  catch (std::exception &e)
103  {
104  print_exception(e);
105  if (error_str)
106  *error_str = std::string("Exception occured: ") + e.what();
107  }
108  return false;
109 }
110 
112 {
113  zmqpp::message msg;
114 
115  msg << "GENERAL_CONFIG" << ConfigManager::ConfigFormat::BOOST_ARCHIVE;
116  sock_.send(msg);
117  poller_.poll(mstimeout_);
118 
119  if (poller_.has_input(sock_))
120  {
121  sock_.receive(msg);
122  if (msg.remaining() == 2)
123  {
124  std::string tmp;
125  msg >> tmp;
126  assert(tmp == "OK");
127  msg >> tmp;
129  return true;
130  }
131  }
132  return false;
133 }
134 
136 {
137  sock_.send("MODULE_LIST");
138 
139  poller_.poll(mstimeout_);
140  if (poller_.has_input(sock_))
141  {
142  zmqpp::message msg;
143  sock_.receive(msg);
144 
145  while (msg.remaining())
146  {
147  std::string tmp;
148  msg >> tmp;
149  module_list_.push_back(tmp);
150  }
151  return true;
152  }
153  return false;
154 }
155 
156 bool RemoteConfigCollector::fetch_module_config(const std::string &module_name)
157 {
158  zmqpp::message msg;
159 
160  msg << "MODULE_CONFIG" << module_name
162  sock_.send(msg);
163  poller_.poll(mstimeout_);
164 
165  if (poller_.has_input(sock_))
166  {
167  sock_.receive(msg);
168  if (msg.remaining() < 3)
169  return false;
170 
171  std::string result;
172  std::string config_str;
173  std::string recv_module_name;
174 
175  msg >> result >> recv_module_name >> config_str;
176  assert(result == "OK");
177  assert(recv_module_name == module_name);
178 
179  // process additional file.
180  if (msg.remaining() % 2 != 0)
181  {
182  ERROR("Msg has " << msg.remaining()
183  << " remaining parts, but need a multiple of 2.");
184  return false;
185  }
186  while (msg.remaining())
187  {
188  std::string file_name;
189  std::string file_content;
190 
191  msg >> file_name >> file_content;
192  additional_files_[module_name].push_back(
193  std::make_pair(file_name, file_content));
194  }
195 
196  // make sure the map is not empty event if there is no file.
197  additional_files_[module_name];
198 
199  if (Tools::boost_text_archive_to_ptree(config_str, config_map_[module_name]))
200  return true;
201  }
202  return false;
203 }
204 
206 {
207  for (const auto &mod_name : module_list_)
208  {
209  if (!fetch_module_config(mod_name))
210  return false;
211  }
212  return true;
213 }
214 
215 const std::list<std::string> &RemoteConfigCollector::modules_list() const noexcept
216 {
217  assert(succeed_);
218  return module_list_;
219 }
220 
223 {
224  assert(succeed_);
225  return config_map_;
226 }
227 
228 const boost::property_tree::ptree &
229 RemoteConfigCollector::module_config(const std::string &name) const
230 {
231  assert(succeed_);
232  auto itr = config_map_.find(name);
233  if (itr != config_map_.end())
234  return itr->second;
235  assert(0);
236  throw std::runtime_error("Code is broken: module " + name +
237  " doesn't exist in this config map.");
238 }
239 
240 const boost::property_tree::ptree &RemoteConfigCollector::general_config() const
241 {
242  return general_config_;
243 }
244 
246 RemoteConfigCollector::additional_files(const std::string module) const
247 {
248  if (additional_files_.count(module))
249  return additional_files_.at(module);
250  assert(0);
251  throw std::runtime_error("Module doesn't exist here.");
252 }
253 
255 {
256  auto task = std::make_shared<Tasks::GetRemoteConfigVersion>(remote_endpoint_,
257  remote_pk_);
258  task->run();
259  if (task->succeed())
260  {
261  version = task->config_version_;
262  return true;
263  }
264  return false;
265 }
266 
268 {
269  return remote_version_;
270 }
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
Leosac::RemoteConfigCollector::remote_version
uint64_t remote_version() const
Definition: RemoteConfigCollector.cpp:267
Leosac::RemoteConfigCollector::sock_
zmqpp::socket_t sock_
Definition: RemoteConfigCollector.hpp:153
WARN
@ WARN
Definition: log.hpp:33
zmqpp
Definition: CoreUtils.hpp:27
ERROR
@ ERROR
Definition: log.hpp:32
Leosac::RemoteConfigCollector::module_config
const boost::property_tree::ptree & module_config(const std::string &name) const
Returns the configuration for one specific module, identified by name.
Definition: RemoteConfigCollector.cpp:229
Leosac::RemoteConfigCollector::fetch_remote_config_version
bool fetch_remote_config_version(uint64_t &version)
Fetch the version of the remote configuration.
Definition: RemoteConfigCollector.cpp:254
Leosac::RemoteConfigCollector::poller_
zmqpp::poller_t poller_
Poll on the socket.
Definition: RemoteConfigCollector.hpp:152
Leosac::RemoteConfigCollector::fetch_module_config
bool fetch_module_config(const std::string &module_name)
Sends the MODULE_CONFIG command for the module whose name is module_name.
Definition: RemoteConfigCollector.cpp:156
Leosac::RemoteConfigCollector::general_config_
boost::property_tree::ptree general_config_
Definition: RemoteConfigCollector.hpp:164
Leosac::RemoteConfigCollector::fetch_module_list
bool fetch_module_list()
Sends the MODULE_LIST command.
Definition: RemoteConfigCollector.cpp:135
ExceptionsTools.hpp
GetRemoteConfigVersion.hpp
Leosac::RemoteConfigCollector::fetch_modules_config
bool fetch_modules_config()
Fetch the conf for all modules (relying on fetch_module_config()).
Definition: RemoteConfigCollector.cpp:205
Leosac::RemoteConfigCollector::fetch_general_config
bool fetch_general_config()
Send the GENERAL_CONFIG command to the remote, and wait for response.
Definition: RemoteConfigCollector.cpp:111
Leosac::RemoteConfigCollector::additional_files_
ModuleAdditionalFiles additional_files_
Definition: RemoteConfigCollector.hpp:166
Leosac::RemoteConfigCollector::general_config
const boost::property_tree::ptree & general_config() const
Returns the tree for the general configuration option.
Definition: RemoteConfigCollector.cpp:240
Leosac::ConfigManager::ConfigFormat::BOOST_ARCHIVE
@ BOOST_ARCHIVE
Leosac
This is the header file for a generated source file, GitSHA1.cpp.
Definition: APIStatusCode.hpp:22
build_str
std::string build_str(Args... args)
Use a stringstream to build a string that combine all arguments.
Definition: BuildString.hpp:44
Leosac::Tools::boost_text_archive_to_ptree
bool boost_text_archive_to_ptree(const std::string &data, boost::property_tree::ptree &tree) noexcept
Convert a boost text archive, whose content is represented as a string (data) to a property tree.
Definition: XmlPropertyTree.cpp:89
Leosac::RemoteConfigCollector::remote_pk_
std::string remote_pk_
Definition: RemoteConfigCollector.hpp:147
BuildString.hpp
Leosac::RemoteConfigCollector::FileNameContentList
std::list< std::pair< std::string, std::string > > FileNameContentList
Definition: RemoteConfigCollector.hpp:76
Leosac::RemoteConfigCollector::fetch_config
bool fetch_config(std::string *error_str) noexcept
Fetch the complete remote configuration.
Definition: RemoteConfigCollector.cpp:60
Leosac::RemoteConfigCollector::modules_list
const std::list< std::string > & modules_list() const noexcept
Return the list of modules that are loaded on the remote host.
Definition: RemoteConfigCollector.cpp:215
XmlPropertyTree.hpp
Leosac::RemoteConfigCollector::ModuleConfigMap
std::map< std::string, boost::property_tree::ptree > ModuleConfigMap
Definition: RemoteConfigCollector.hpp:74
Leosac::RemoteConfigCollector::mstimeout_
long mstimeout_
Definition: RemoteConfigCollector.hpp:155
Leosac::RemoteConfigCollector::remote_endpoint_
std::string remote_endpoint_
Definition: RemoteConfigCollector.hpp:146
FetchRemoteConfig.hpp
Leosac::RemoteConfigCollector::config_map_
ModuleConfigMap config_map_
Map module name to their config tree.
Definition: RemoteConfigCollector.hpp:163
RemoteConfigCollector.hpp
log.hpp
Leosac::RemoteConfigCollector::RemoteConfigCollector
RemoteConfigCollector(zmqpp::context_t &ctx, const std::string &remote_endpoint, const std::string &remote_pk)
Construct a new RemoteConfigCollector, this object will work for a one-time config collection.
Definition: RemoteConfigCollector.cpp:33
Leosac::RemoteConfigCollector::additional_files
const FileNameContentList & additional_files(const std::string module) const
Definition: RemoteConfigCollector.cpp:246
Leosac::RemoteConfigCollector::succeed_
bool succeed_
Definition: RemoteConfigCollector.hpp:172
Leosac::RemoteConfigCollector::remote_version_
uint64_t remote_version_
Definition: RemoteConfigCollector.hpp:157
ConfigManager.hpp
Leosac::RemoteConfigCollector::module_list_
std::list< std::string > module_list_
Definition: RemoteConfigCollector.hpp:165
Leosac::RemoteConfigCollector::modules_config
const ModuleConfigMap & modules_config() const noexcept
Returns a reference to modules and their configuration.
Definition: RemoteConfigCollector.cpp:222