22 #include "mongodb_instance_config.h"
26 #include <config/config.h>
27 #include <core/exceptions/system.h>
28 #include <utils/sub_process/proc.h>
29 #include <utils/time/wait.h>
31 #include <boost/filesystem.hpp>
32 #include <boost/filesystem/operations.hpp>
33 #include <boost/format.hpp>
34 #include <bsoncxx/builder/basic/document.hpp>
35 #include <bsoncxx/json.hpp>
37 #include <mongocxx/client.hpp>
38 #include <mongocxx/exception/exception.hpp>
44 using namespace std::chrono_literals;
64 set_name(
"MongoDBInstance|%s", cfgname.c_str());
65 config_name_ = cfgname;
71 enabled_ = config->
get_bool(prefix +
"enabled");
76 startup_grace_period_ = 10;
78 startup_grace_period_ = config->
get_uint(prefix +
"startup-grace-period");
83 loop_interval_ = config->
get_float(prefix +
"loop-interval");
86 termination_grace_period_ = config->
get_uint(prefix +
"termination-grace-period");
87 port_ = config->
get_uint(prefix +
"port");
89 use_tmp_directory_ = config->
get_bool_or_default((prefix +
"use-tmp-directory").c_str(),
false);
91 clear_data_on_termination_ =
94 if (use_tmp_directory_) {
96 const std::string filename =
97 boost::str(boost::format(
"mongodb-%1%-%%%%%%%%-%%%%%%%%-%%%%%%%%") % port_);
98 const boost::filesystem::path path =
99 boost::filesystem::unique_path(boost::filesystem::temp_directory_path() / filename);
100 data_path_ = path.string();
101 log_path_ = (path /
"mongodb.log").
string();
103 data_path_ = config->
get_string(prefix +
"data-path");
104 log_path_ = config->
get_string(prefix +
"log/path");
106 log_append_ = config->
get_bool(prefix +
"log/append");
108 replica_set_ = config->
get_string(prefix +
"replica-set");
112 if (!replica_set_.empty()) {
115 oplog_size_ = config->
get_uint(prefix +
"oplog-size");
122 "mongod",
"--bind_ip", bind_ip_,
"--port", std::to_string(port_),
"--dbpath", data_path_};
124 if (!log_path_.empty()) {
126 argv_.push_back(
"--logappend");
128 argv_.push_back(
"--logpath");
129 argv_.push_back(log_path_);
132 if (!replica_set_.empty()) {
133 argv_.push_back(
"--replSet");
134 argv_.push_back(replica_set_);
135 if (oplog_size_ > 0) {
136 argv_.push_back(
"--oplogSize");
137 argv_.push_back(std::to_string(oplog_size_));
143 if (!extra_args.empty()) {
145 int wrv = wordexp(extra_args.c_str(), &p, WRDE_NOCMD | WRDE_UNDEF);
148 case WRDE_BADCHAR:
throw Exception(
"%s: invalid character in args",
name());
149 case WRDE_BADVAL:
throw Exception(
"%s: undefined variable referenced in args",
name());
151 throw Exception(
"%s: running sub-commands has been disabled for args",
name());
153 case WRDE_SYNTAX:
throw Exception(
"%s: shell syntax error in args",
name());
154 default:
throw Exception(
"Unexpected wordexp error %d when parsing args", wrv);
159 std::vector<std::string> invalid_args = {
"--port",
172 for (
size_t i = 0; i < p.we_wordc; ++i) {
173 for (
size_t j = 0; j < invalid_args.size(); ++j) {
174 if (invalid_args[j] == p.we_wordv[i]) {
176 throw Exception(
"%s: %s may not be passed in args",
name(), invalid_args[j].c_str());
179 argv_.push_back(p.we_wordv[i]);
185 command_line_ = std::accumulate(std::next(argv_.begin()),
188 [](std::string &s,
const std::string &a) { return s +
" " + a; });
199 "clear data on termination: %s",
200 clear_data_on_termination_ ?
"yes" :
"no");
206 replica_set_.empty() ?
"DISABLED" : replica_set_.c_str());
207 if (!replica_set_.empty()) {
213 throw Exception(
"Instance '%s' cannot be started while disabled",
name());
216 timewait_ =
new TimeWait(
clock, (
int)(loop_interval_ * 1000000.));
223 if (!running_ || !check_alive()) {
249 return command_line_;
258 return termination_grace_period_;
262 MongoDBInstanceConfig::check_alive()
265 mongocxx::client client{mongocxx::uri(
"mongodb://localhost:" + std::to_string(port_))};
267 using namespace bsoncxx::builder;
268 auto cmd{basic::document{}};
269 cmd.append(basic::kvp(
"isMaster", 1));
271 auto reply = client[
"admin"].run_command(cmd.view());
272 bool ok = check_mongodb_ok(reply.view());
274 logger->
log_warn(
name(),
"Failed to connect: %s", bsoncxx::to_json(reply.view()).c_str());
277 }
catch (mongocxx::exception &e) {
297 boost::filesystem::create_directories(data_path_);
298 }
catch (boost::filesystem::filesystem_error &e) {
299 throw Exception(
"Failed to create data path '%s' for mongod(%s): %s",
301 config_name_.c_str(),
305 if (!log_path_.empty()) {
306 boost::filesystem::path p(log_path_);
308 boost::filesystem::create_directories(p.parent_path());
309 }
catch (boost::filesystem::filesystem_error &e) {
310 throw Exception(
"Failed to create log path '%s' for mongod(%s): %s",
311 p.parent_path().string().c_str(),
312 config_name_.c_str(),
317 std::string progname =
"mongod(" + config_name_ +
")";
319 std::make_shared<SubProcess>(progname,
"mongod", argv_, std::vector<std::string>{},
logger);
321 for (
unsigned i = 0; i < startup_grace_period_ * 4; ++i) {
326 std::this_thread::sleep_for(250ms);
330 throw Exception(
"%s: instance did not start in time",
name());
344 for (
unsigned i = 0; i < termination_grace_period_; ++i) {
347 std::this_thread::sleep_for(1s);
354 boost::filesystem::remove_all(data_path_);
355 }
catch (boost::filesystem::filesystem_error &e) {
356 throw Exception(
"Failed to create data path '%s' for mongod(%s): %s",
358 config_name_.c_str(),
unsigned int termination_grace_period() const
Get termination grace period.
virtual void loop()
Code to execute in the thread.
virtual void finalize()
Finalize the thread.
void start_mongod()
Start mongod.
void kill_mongod(bool clear_data)
Stop mongod.
MongoDBInstanceConfig(fawkes::Configuration *config, std::string cfgname, std::string prefix)
Constructor.
virtual void init()
Initialize the thread.
std::string command_line() const
Get command line used to execute program.
Clock * clock
By means of this member access to the clock is given.
Interface for configuration handling.
virtual unsigned int get_uint(const char *path)=0
Get value from configuration which is of type unsigned int.
virtual bool get_bool(const char *path)=0
Get value from configuration which is of type bool.
virtual std::string get_string_or_default(const char *path, const std::string &default_val)
Get value from configuration which is of type string, or the given default if the path does not exist...
virtual float get_float(const char *path)=0
Get value from configuration which is of type float.
virtual bool get_bool_or_default(const char *path, const bool &default_val)
Get value from configuration which is of type bool, or the given default if the path does not exist.
virtual std::string get_string(const char *path)=0
Get value from configuration which is of type string.
Base class for exceptions in Fawkes.
virtual const char * what_no_backtrace() const noexcept
Get primary string (does not implicitly print the back trace).
virtual void log_debug(const char *component, const char *format,...)=0
Log debug message.
virtual void log_warn(const char *component, const char *format,...)=0
Log warning message.
virtual void log_error(const char *component, const char *format,...)=0
Log error message.
Logger * logger
This is the Logger member used to access the logger.
System ran out of memory and desired operation could not be fulfilled.
Thread class encapsulation of pthreads.
const char * name() const
Get name of thread.
void set_name(const char *format,...)
Set name of thread.
void mark_start()
Mark start of loop.
void wait_systime()
Wait until minimum loop time has been reached in real time.
Fawkes library namespace.