Fawkes API  Fawkes Development Version
mongodb_thread.cpp
1 
2 /***************************************************************************
3  * mongodb_thread.cpp - MongoDB Thread
4  *
5  * Created: Sun Dec 05 23:32:13 2010
6  * Copyright 2006-2015 Tim Niemueller [www.niemueller.de]
7  ****************************************************************************/
8 
9 /* This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU Library General Public License for more details.
18  *
19  * Read the full text in the LICENSE.GPL file in the doc directory.
20  */
21 
22 #include "mongodb_thread.h"
23 
24 #include "mongodb_client_config.h"
25 #include "mongodb_instance_config.h"
26 #include "mongodb_replicaset_config.h"
27 
28 #ifdef HAVE_MONGODB_VERSION_H
29 # include <mongo/client/init.h>
30 #endif
31 
32 using namespace mongo;
33 using namespace fawkes;
34 
35 /** @class MongoDBThread "mongodb_thread.h"
36  * MongoDB Thread.
37  * This thread maintains an active connection to MongoDB and provides an
38  * aspect to access MongoDB to make it convenient for other threads to use
39  * MongoDB.
40  *
41  * @author Tim Niemueller
42  */
43 
44 /** Constructor. */
46 : Thread("MongoDBThread", Thread::OPMODE_WAITFORWAKEUP),
47  AspectProviderAspect(&mongodb_aspect_inifin_),
48  mongodb_aspect_inifin_(this)
49 {
50 }
51 
52 /** Destructor. */
54 {
55 }
56 
57 void
59 {
60 #ifdef HAVE_MONGODB_VERSION_H
61  mongo::client::initialize();
62 #endif
63 
64  init_instance_configs();
65  init_client_configs();
66  init_replicaset_configs();
67 
68  if (client_configs_.empty() && instance_configs_.empty() && replicaset_configs_.empty()) {
69  throw Exception("No enabled MongoDB configurations found");
70  }
71 }
72 
73 void
74 MongoDBThread::init_client_configs()
75 {
76  std::set<std::string> ignored_configs;
77  std::string prefix = "/plugins/mongodb/clients/";
78 
79  std::unique_ptr<Configuration::ValueIterator> i(config->search(prefix.c_str()));
80  while (i->next()) {
81  std::string cfg_name = std::string(i->path()).substr(prefix.length());
82  cfg_name = cfg_name.substr(0, cfg_name.find("/"));
83 
84  if ((client_configs_.find(cfg_name) == client_configs_.end())
85  && (ignored_configs.find(cfg_name) == ignored_configs.end())) {
86  std::string cfg_prefix = prefix + cfg_name + "/";
87 
88  try {
89  auto conf = std::make_shared<MongoDBClientConfig>(config, logger, cfg_name, cfg_prefix);
90  if (conf->is_enabled()) {
91  client_configs_[cfg_name] = conf;
92  logger->log_info(name(), "Added MongoDB client configuration %s", cfg_name.c_str());
93  conf->log(logger, name(), " ");
94  } else {
95  logger->log_info(name(),
96  "Ignoring disabled MongoDB client "
97  "configuration %s",
98  cfg_name.c_str());
99  ignored_configs.insert(cfg_name);
100  }
101  } catch (Exception &e) {
102  logger->log_warn(name(),
103  "Invalid MongoDB client config %s, ignoring, "
104  "exception follows.",
105  cfg_name.c_str());
106  logger->log_warn(name(), e);
107  ignored_configs.insert(cfg_name);
108  }
109  }
110  }
111 }
112 
113 void
114 MongoDBThread::init_instance_configs()
115 {
116  std::set<std::string> ignored_configs;
117  std::string prefix = "/plugins/mongodb/instances/";
118 
119  std::unique_ptr<Configuration::ValueIterator> i(config->search(prefix.c_str()));
120  while (i->next()) {
121  std::string cfg_name = std::string(i->path()).substr(prefix.length());
122  cfg_name = cfg_name.substr(0, cfg_name.find("/"));
123 
124  if ((instance_configs_.find(cfg_name) == instance_configs_.end())
125  && (ignored_configs.find(cfg_name) == ignored_configs.end())) {
126  std::string cfg_prefix = prefix + cfg_name + "/";
127 
128  try {
129  auto conf = std::make_shared<MongoDBInstanceConfig>(config, cfg_name, cfg_prefix);
130  if (conf->is_enabled()) {
131  instance_configs_[cfg_name] = conf;
132  logger->log_info(name(), "Added MongoDB instance configuration %s", cfg_name.c_str());
133  } else {
134  logger->log_info(name(),
135  "Ignoring disabled MongoDB instance "
136  "configuration %s",
137  cfg_name.c_str());
138  ignored_configs.insert(cfg_name);
139  }
140  } catch (Exception &e) {
141  logger->log_warn(name(),
142  "Invalid MongoDB instance config %s, ignoring, "
143  "exception follows.",
144  cfg_name.c_str());
145  logger->log_warn(name(), e);
146  ignored_configs.insert(cfg_name);
147  }
148  }
149  }
150 
151  for (auto c : instance_configs_) {
152  logger->log_info(name(), "Running instance '%s'", c.first.c_str());
153  logger->log_info(name(), " '%s'", c.second->command_line().c_str());
154  thread_collector->add(&*c.second);
155  }
156 }
157 
158 void
159 MongoDBThread::init_replicaset_configs()
160 {
161  std::set<std::string> ignored_configs;
162  std::string prefix = "/plugins/mongodb/replica-sets/managed-sets/";
163 
164  std::string bootstrap_prefix = "/plugins/mongodb/replica-sets/bootstrap-mongodb/";
165  std::string bootstrap_client_cfg = config->get_string(bootstrap_prefix + "client");
166  std::string bootstrap_database = config->get_string(bootstrap_prefix + "database");
167 
168  std::unique_ptr<Configuration::ValueIterator> i(config->search(prefix.c_str()));
169  while (i->next()) {
170  std::string cfg_name = std::string(i->path()).substr(prefix.length());
171  cfg_name = cfg_name.substr(0, cfg_name.find("/"));
172 
173  if ((replicaset_configs_.find(cfg_name) == replicaset_configs_.end())
174  && (ignored_configs.find(cfg_name) == ignored_configs.end())) {
175  std::string cfg_prefix = prefix + cfg_name + "/";
176 
177  try {
178  auto conf = std::make_shared<MongoDBReplicaSetConfig>(config,
179  cfg_name,
180  cfg_prefix,
181  bootstrap_database);
182  if (conf->is_enabled()) {
183  std::shared_ptr<mongo::DBClientBase> bootstrap_client(
184  create_client(bootstrap_client_cfg));
185  conf->bootstrap(bootstrap_client);
186  replicaset_configs_[cfg_name] = conf;
187  logger->log_info(name(), "Added MongoDB replica set configuration %s", cfg_name.c_str());
188  } else {
189  logger->log_info(name(),
190  "Ignoring disabled MongoDB replica set "
191  "configuration %s",
192  cfg_name.c_str());
193  ignored_configs.insert(cfg_name);
194  }
195  } catch (Exception &e) {
196  logger->log_warn(name(),
197  "Invalid MongoDB replica set config %s, ignoring, "
198  "exception follows.",
199  cfg_name.c_str());
200  logger->log_warn(name(), e);
201  ignored_configs.insert(cfg_name);
202  }
203  }
204  }
205 
206  for (auto c : replicaset_configs_) {
207  logger->log_info(name(), "Running replica set '%s' management", c.first.c_str());
208  thread_collector->add(&*c.second);
209  }
210 }
211 
212 void
214 {
215  for (auto c : instance_configs_) {
216  logger->log_info(name(),
217  "Stopping instance '%s', grace period %u sec",
218  c.first.c_str(),
219  c.second->termination_grace_period());
220  thread_collector->remove(&*c.second);
221  }
222  instance_configs_.clear();
223 
224  for (auto c : replicaset_configs_) {
225  logger->log_info(name(), "Stopping replica set '%s' management", c.first.c_str());
226  thread_collector->remove(&*c.second);
227  }
228  replicaset_configs_.clear();
229 
230  client_configs_.clear();
231 
232 #ifdef HAVE_MONGODB_VERSION_H
233  mongo::client::shutdown();
234 #endif
235 }
236 
237 void
239 {
240 }
241 
242 mongo::DBClientBase *
243 MongoDBThread::create_client(const std::string &config_name)
244 {
245  const std::string cname{config_name.empty() ? "default" : config_name};
246 
247  if (client_configs_.find(cname) != client_configs_.end()) {
248  if (!client_configs_[cname]->is_enabled()) {
249  throw Exception("MongoDB config '%s' is not marked enabled", cname.c_str());
250  }
251  return client_configs_[cname]->create_client();
252  } else {
253  throw Exception("No MongoDB config named '%s' exists", cname.c_str());
254  }
255 }
256 
257 void
258 MongoDBThread::delete_client(mongo::DBClientBase *client)
259 {
260  delete client;
261 }
virtual void log_info(const char *component, const char *format,...)=0
Log informational message.
virtual void remove(ThreadList &tl)=0
Remove multiple threads.
Fawkes library namespace.
virtual void finalize()
Finalize the thread.
virtual ValueIterator * search(const char *path)=0
Iterator with search results.
Thread class encapsulation of pthreads.
Definition: thread.h:45
Logger * logger
This is the Logger member used to access the logger.
Definition: logging.h:41
virtual ~MongoDBThread()
Destructor.
ThreadCollector * thread_collector
Thread collector.
virtual void loop()
Code to execute in the thread.
Base class for exceptions in Fawkes.
Definition: exception.h:35
const char * name() const
Get name of thread.
Definition: thread.h:100
virtual void log_warn(const char *component, const char *format,...)=0
Log warning message.
virtual void add(ThreadList &tl)=0
Add multiple threads.
Thread aspect provide a new aspect.
virtual mongo::DBClientBase * create_client(const std::string &config_name="")
Create a new MongoDB client.
MongoDBThread()
Constructor.
virtual void delete_client(mongo::DBClientBase *client)
Delete a client.
Configuration * config
This is the Configuration member used to access the configuration.
Definition: configurable.h:41
virtual void init()
Initialize the thread.
virtual std::string get_string(const char *path)=0
Get value from configuration which is of type string.