Kea  2.1.7-git
d_controller.cc
Go to the documentation of this file.
1 // Copyright (C) 2013-2021 Internet Systems Consortium, Inc. ("ISC")
2 //
3 // This Source Code Form is subject to the terms of the Mozilla Public
4 // License, v. 2.0. If a copy of the MPL was not distributed with this
5 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 
7 #include <config.h>
9 #include <cfgrpt/config_report.h>
10 #include <exceptions/exceptions.h>
11 #include <hooks/hooks_manager.h>
12 #include <log/logger.h>
13 #include <log/logger_support.h>
14 #include <process/daemon.h>
15 #include <process/d_log.h>
16 #include <process/d_controller.h>
17 #include <process/config_base.h>
18 #include <kea_version.h>
19 #include <functional>
20 #include <sstream>
21 #include <unistd.h>
22 #include <signal.h>
23 
24 using namespace isc::asiolink;
25 using namespace isc::data;
26 using namespace isc::config;
27 using namespace isc::hooks;
28 namespace ph = std::placeholders;
29 
30 namespace isc {
31 namespace process {
32 
33 DControllerBasePtr DControllerBase::controller_;
34 
35 // Note that the constructor instantiates the controller's primary IOService.
36 DControllerBase::DControllerBase(const char* app_name, const char* bin_name)
37  : app_name_(app_name), bin_name_(bin_name),
38  verbose_(false), check_only_(false),
39  io_service_(new isc::asiolink::IOService()),
40  io_signal_set_() {
41 }
42 
43 void
45  if (controller_) {
46  // This shouldn't happen, but let's make sure it can't be done.
47  // It represents a programmatic error.
49  "Multiple controller instances attempted.");
50  }
51 
52  controller_ = controller;
53 }
54 
56 DControllerBase::parseFile(const std::string&) {
57  ConstElementPtr elements;
58  return (elements);
59 }
60 
61 int
62 DControllerBase::launch(int argc, char* argv[], const bool test_mode) {
63 
64  // Step 1 is to parse the command line arguments.
65  try {
66  parseArgs(argc, argv);
67  } catch (const InvalidUsage& ex) {
68  usage(ex.what());
69  // rethrow it with an empty message
71  }
72 
73  setProcName(bin_name_);
74 
75  if (isCheckOnly()) {
77  return (EXIT_SUCCESS);
78  }
79 
80  // It is important that we set a default logger name because this name
81  // will be used when the user doesn't provide the logging configuration
82  // in the Kea configuration file.
84 
85  // Logger's default configuration depends on whether we are in the
86  // verbose mode or not. CfgMgr manages the logger configuration so
87  // the verbose mode is set for CfgMgr.
88  Daemon::setVerbose(verbose_);
89 
90  // Do not initialize logger here if we are running unit tests. It would
91  // replace an instance of unit test specific logger.
92  if (!test_mode) {
93  // Now that we know what the mode flags are, we can init logging.
94  Daemon::loggerInit(bin_name_.c_str(), verbose_);
95  }
96 
97  try {
99  } catch (const std::exception& ex) {
101  .arg(app_name_).arg(ex.what());
102  isc_throw (LaunchError, "Launch Failed: " << ex.what());
103  }
104 
105  try {
106  createPIDFile();
107  } catch (const DaemonPIDExists& ex) {
109  .arg(bin_name_).arg(ex.what());
110  isc_throw (LaunchError, "Launch Failed: " << ex.what());
111  } catch (const std::exception& ex) {
113  .arg(app_name_).arg(ex.what());
114  isc_throw (LaunchError, "Launch failed: " << ex.what());
115  }
116 
117  // Log the starting of the service.
119  .arg(app_name_)
120  .arg(getpid())
121  .arg(VERSION)
122  .arg(PACKAGE_VERSION_TYPE);
123  // When it is not a stable version dissuade use in production.
124  if (std::string(PACKAGE_VERSION_TYPE) == "development") {
126  }
127  try {
128  // Step 2 is to create and initialize the application process object.
129  initProcess();
130  } catch (const std::exception& ex) {
132  .arg(app_name_).arg(ex.what());
134  "Application Process initialization failed: " << ex.what());
135  }
136 
138  .arg(app_name_);
139 
140  // Step 3 is to load configuration from file.
141  int rcode;
142  ConstElementPtr comment = parseAnswer(rcode, configFromFile());
143  if (rcode != 0) {
145  .arg(app_name_).arg(comment->stringValue());
146  isc_throw (ProcessInitError, "Could Not load configuration file: "
147  << comment->stringValue());
148  }
149 
150  // Note that the controller was started.
151  start_ = boost::posix_time::second_clock::universal_time();
152 
153  // Everything is clear for launch, so start the application's
154  // event loop.
155  try {
156  // Now that we have a process, we can set up signal handling.
158  runProcess();
159  } catch (const std::exception& ex) {
161  .arg(app_name_).arg(ex.what());
163  "Application process event loop failed: " << ex.what());
164  }
165 
166  // All done, so bail out.
168  .arg(app_name_).arg(getpid()).arg(VERSION);
169 
170  return (getExitValue());
171 }
172 
173 void
175  try {
176  // We need to initialize logging, in case any error
177  // messages are to be printed.
178  // This is just a test, so we don't care about lockfile.
179  setenv("KEA_LOCKFILE_DIR", "none", 0);
180  Daemon::setDefaultLoggerName(bin_name_);
181  Daemon::setVerbose(verbose_);
182  Daemon::loggerInit(bin_name_.c_str(), verbose_);
183 
184  // Check the syntax first.
185  std::string config_file = getConfigFile();
186  if (config_file.empty()) {
187  // Basic sanity check: file name must not be empty.
188  isc_throw(InvalidUsage, "JSON configuration file not specified");
189  }
190  ConstElementPtr whole_config = parseFile(config_file);
191  if (!whole_config) {
192  // No fallback to fromJSONFile
193  isc_throw(InvalidUsage, "No configuration found");
194  }
195  if (verbose_) {
196  std::cerr << "Syntax check OK" << std::endl;
197  }
198 
199  // Check the logic next.
200  ConstElementPtr module_config;
201  module_config = whole_config->get(getAppName());
202  if (!module_config) {
203  isc_throw(InvalidUsage, "Config file " << config_file <<
204  " does not include '" << getAppName() << "' entry");
205  }
206  if (module_config->getType() != Element::map) {
207  isc_throw(InvalidUsage, "Config file " << config_file <<
208  " includes not map '" << getAppName() << "' entry");
209  }
210 
211  // Handle other (i.e. not application name) objects.
212  std::string errmsg = handleOtherObjects(whole_config);
213  if (!errmsg.empty()) {
214  isc_throw(InvalidUsage, "Config file " << config_file << errmsg);
215  }
216 
217  // Get an application process object.
218  initProcess();
219 
220  ConstElementPtr answer = checkConfig(module_config);
221  int rcode = 0;
222  answer = parseAnswer(rcode, answer);
223  if (rcode != 0) {
224  isc_throw(InvalidUsage, "Error encountered: "
225  << answer->stringValue());
226  }
227  } catch (const VersionMessage&) {
228  throw;
229  } catch (const InvalidUsage&) {
230  throw;
231  } catch (const std::exception& ex) {
232  isc_throw(InvalidUsage, "Syntax check failed with: " << ex.what());
233  }
234  return;
235 }
236 
237 void
238 DControllerBase::parseArgs(int argc, char* argv[]) {
239 
240  if (argc == 1) {
241  isc_throw(InvalidUsage, "");
242  }
243 
244  // Iterate over the given command line options. If its a stock option
245  // ("c" or "d") handle it here. If its a valid custom option, then
246  // invoke customOption.
247  int ch;
248  opterr = 0;
249  optind = 1;
250  std::string opts("dvVWc:t:" + getCustomOpts());
251  while ((ch = getopt(argc, argv, opts.c_str())) != -1) {
252  switch (ch) {
253  case 'd':
254  // Enables verbose logging.
255  verbose_ = true;
256  break;
257 
258  case 'v':
259  // gather Kea version and throw so main() can catch and return
260  // rather than calling exit() here which disrupts gtest.
262  break;
263 
264  case 'V':
265  // gather Kea version and throw so main() can catch and return
266  // rather than calling exit() here which disrupts gtest.
268  break;
269 
270  case 'W':
271  // gather Kea config report and throw so main() can catch and
272  // return rather than calling exit() here which disrupts gtest.
274  break;
275 
276  case 'c':
277  case 't':
278  // config file name
279  if (optarg == NULL) {
280  isc_throw(InvalidUsage, "configuration file name missing");
281  }
282 
283  setConfigFile(optarg);
284 
285  if (ch == 't') {
286  check_only_ = true;
287  }
288  break;
289 
290  case '?': {
291  // We hit an invalid option.
292  isc_throw(InvalidUsage, "unsupported option: ["
293  << static_cast<char>(optopt) << "] "
294  << (!optarg ? "" : optarg));
295 
296  break;
297  }
298 
299  default:
300  // We hit a valid custom option
301  if (!customOption(ch, optarg)) {
302  // This would be a programmatic error.
303  isc_throw(InvalidUsage, " Option listed but implemented?: ["
304  << static_cast<char>(ch) << "] "
305  << (!optarg ? "" : optarg));
306  }
307  break;
308  }
309  }
310 
311  // There was too much information on the command line.
312  if (argc > optind) {
313  isc_throw(InvalidUsage, "extraneous command line information");
314  }
315 }
316 
317 bool
318 DControllerBase::customOption(int /* option */, char* /*optarg*/) {
319  // Default implementation returns false.
320  return (false);
321 }
322 
323 void
326  .arg(app_name_);
327 
328  // Invoke virtual method to instantiate the application process.
329  try {
330  process_.reset(createProcess());
331  } catch (const std::exception& ex) {
332  isc_throw(DControllerBaseError, std::string("createProcess failed: ")
333  + ex.what());
334  }
335 
336  // This is pretty unlikely, but will test for it just to be safe..
337  if (!process_) {
338  isc_throw(DControllerBaseError, "createProcess returned NULL");
339  }
340 
341  // Invoke application's init method (Note this call should throw
342  // DProcessBaseError if it fails).
343  process_->init();
344 }
345 
348  // Rollback any previous staging configuration. For D2, only a
349  // logger configuration is used here.
350  // We're not using cfgmgr to store logging configuration anymore.
351  // isc::dhcp::CfgMgr::instance().rollback();
352 
353  // Will hold configuration.
354  ConstElementPtr module_config;
355  // Will receive configuration result.
356  ConstElementPtr answer;
357  try {
358  std::string config_file = getConfigFile();
359  if (config_file.empty()) {
360  // Basic sanity check: file name must not be empty.
361  isc_throw(BadValue, "JSON configuration file not specified. Please "
362  "use -c command line option.");
363  }
364 
365  // If parseFile returns an empty pointer, then pass the file onto the
366  // original JSON parser.
367  ConstElementPtr whole_config = parseFile(config_file);
368  if (!whole_config) {
369  // Read contents of the file and parse it as JSON
370  whole_config = Element::fromJSONFile(config_file, true);
371  }
372 
373  // Extract derivation-specific portion of the configuration.
374  module_config = whole_config->get(getAppName());
375  if (!module_config) {
376  isc_throw(BadValue, "Config file " << config_file <<
377  " does not include '" <<
378  getAppName() << "' entry.");
379  }
380  if (module_config->getType() != Element::map) {
381  isc_throw(InvalidUsage, "Config file " << config_file <<
382  " includes not map '" << getAppName() << "' entry");
383  }
384 
385  // Handle other (i.e. not application name) objects.
386  std::string errmsg = handleOtherObjects(whole_config);
387  if (!errmsg.empty()) {
388  isc_throw(InvalidUsage, "Config file " << config_file << errmsg);
389  }
390 
391  // Let's configure logging before applying the configuration,
392  // so we can log things during configuration process.
393 
394  // Temporary storage for logging configuration
395  ConfigPtr storage(new ConfigBase());
396 
397  // Configure logging to the temporary storage.
398  Daemon::configureLogger(module_config, storage);
399 
400  // Let's apply the new logging. We do it early, so we'll be able
401  // to print out what exactly is wrong with the new config in
402  // case of problems.
403  storage->applyLoggingCfg();
404 
405  answer = updateConfig(module_config);
406  // In all cases the right logging configuration is in the context.
407  process_->getCfgMgr()->getContext()->applyLoggingCfg();
408  } catch (const std::exception& ex) {
409  // Rollback logging configuration.
410  process_->getCfgMgr()->getContext()->applyLoggingCfg();
411 
412  // build an error result
413  ConstElementPtr error = createAnswer(COMMAND_ERROR,
414  std::string("Configuration parsing failed: ") + ex.what());
415  return (error);
416  }
417 
418  return (answer);
419 }
420 
421 void
424  .arg(app_name_);
425  if (!process_) {
426  // This should not be possible.
427  isc_throw(DControllerBaseError, "Process not initialized");
428  }
429 
430  // Invoke the application process's run method. This may throw
431  // DProcessBaseError
432  process_->run();
433 }
434 
435 // Instance method for handling new config
438  return (process_->configure(new_config, false));
439 }
440 
441 // Instance method for checking new config
444  return (process_->configure(new_config, true));
445 }
446 
449  ConstElementPtr /*args*/) {
450  ConstElementPtr config = process_->getCfgMgr()->getContext()->toElement();
451 
452  return (createAnswer(COMMAND_SUCCESS, config));
453 }
454 
457  ConstElementPtr args) {
458  std::string filename;
459 
460  if (args) {
461  if (args->getType() != Element::map) {
462  return (createAnswer(COMMAND_ERROR, "Argument must be a map"));
463  }
464  ConstElementPtr filename_param = args->get("filename");
465  if (filename_param) {
466  if (filename_param->getType() != Element::string) {
467  return (createAnswer(COMMAND_ERROR,
468  "passed parameter 'filename' "
469  "is not a string"));
470  }
471  filename = filename_param->stringValue();
472  }
473  }
474 
475  if (filename.empty()) {
476  // filename parameter was not specified, so let's use
477  // whatever we remember
478  filename = getConfigFile();
479  if (filename.empty()) {
480  return (createAnswer(COMMAND_ERROR,
481  "Unable to determine filename."
482  "Please specify filename explicitly."));
483  }
484  }
485 
486 
487  // Ok, it's time to write the file.
488  size_t size = 0;
489  ElementPtr cfg = process_->getCfgMgr()->getContext()->toElement();
490 
491  try {
492  size = writeConfigFile(filename, cfg);
493  } catch (const isc::Exception& ex) {
494  return (createAnswer(COMMAND_ERROR,
495  std::string("Error during write-config:")
496  + ex.what()));
497  }
498  if (size == 0) {
499  return (createAnswer(COMMAND_ERROR,
500  "Error writing configuration to " + filename));
501  }
502 
503  // Ok, it's time to return the successful response.
504  ElementPtr params = Element::createMap();
505  params->set("size", Element::create(static_cast<long long>(size)));
506  params->set("filename", Element::create(filename));
507 
508  return (createAnswer(CONTROL_RESULT_SUCCESS, "Configuration written to "
509  + filename + " successful", params));
510 }
511 
512 std::string
514  // Check obsolete or unknown (aka unsupported) objects.
515  const std::string& app_name = getAppName();
516  std::string errmsg;
517  for (auto obj : args->mapValue()) {
518  const std::string& obj_name = obj.first;
519  if (obj_name == app_name) {
520  continue;
521  }
523  .arg("'" + obj_name + "', defining anything in global level besides '"
524  + app_name + "' is no longer supported.");
525  if (errmsg.empty()) {
526  errmsg = " contains unsupported '" + obj_name + "' parameter";
527  } else {
528  errmsg += " (and '" + obj_name + "')";
529  }
530  }
531  return (errmsg);
532 }
533 
536  const int status_code = COMMAND_ERROR; // 1 indicates an error
537  ConstElementPtr module_config;
538  std::string app_name = getAppName();
539  std::string message;
540 
541  // Command arguments are expected to be:
542  // { "Module": { ... } }
543  if (!args) {
544  message = "Missing mandatory 'arguments' parameter.";
545  } else {
546  module_config = args->get(app_name);
547  if (!module_config) {
548  message = "Missing mandatory '" + app_name + "' parameter.";
549  } else if (module_config->getType() != Element::map) {
550  message = "'" + app_name + "' parameter expected to be a map.";
551  }
552  }
553 
554  if (message.empty()) {
555  // Handle other (i.e. not application name) objects.
556  std::string errmsg = handleOtherObjects(args);
557  if (!errmsg.empty()) {
558  message = "'arguments' parameter" + errmsg;
559  }
560  }
561 
562  if (!message.empty()) {
563  // Something is amiss with arguments, return a failure response.
564  ConstElementPtr result = isc::config::createAnswer(status_code,
565  message);
566  return (result);
567  }
568 
569 
570  // We are starting the configuration process so we should remove any
571  // staging configuration that has been created during previous
572  // configuration attempts.
573  // We're not using cfgmgr to store logging information anymore.
574  // isc::dhcp::CfgMgr::instance().rollback();
575 
576  // Now we check the server proper.
577  return (checkConfig(module_config));
578 }
579 
582  // Add reload in message?
583  return (configFromFile());
584 }
585 
588  const int status_code = COMMAND_ERROR; // 1 indicates an error
589  ConstElementPtr module_config;
590  std::string app_name = getAppName();
591  std::string message;
592 
593  // Command arguments are expected to be:
594  // { "Module": { ... } }
595  if (!args) {
596  message = "Missing mandatory 'arguments' parameter.";
597  } else {
598  module_config = args->get(app_name);
599  if (!module_config) {
600  message = "Missing mandatory '" + app_name + "' parameter.";
601  } else if (module_config->getType() != Element::map) {
602  message = "'" + app_name + "' parameter expected to be a map.";
603  }
604  }
605 
606  if (!message.empty()) {
607  // Something is amiss with arguments, return a failure response.
608  ConstElementPtr result = isc::config::createAnswer(status_code,
609  message);
610  return (result);
611  }
612 
613  try {
614 
615  // Handle other (i.e. not application name) objects.
616  handleOtherObjects(args);
617 
618  // We are starting the configuration process so we should remove any
619  // staging configuration that has been created during previous
620  // configuration attempts.
621  // We're not using cfgmgr to store logging information anymore.
622  // isc::dhcp::CfgMgr::instance().rollback();
623 
624  // Temporary storage for logging configuration
625  ConfigPtr storage(new ConfigBase());
626 
627  // Configure logging to the temporary storage.
628  Daemon::configureLogger(module_config, storage);
629 
630  // Let's apply the new logging. We do it early, so we'll be able
631  // to print out what exactly is wrong with the new config in
632  // case of problems.
633  storage->applyLoggingCfg();
634 
635  ConstElementPtr answer = updateConfig(module_config);
636  int rcode = 0;
637  parseAnswer(rcode, answer);
638  // In all cases the right logging configuration is in the context.
639  process_->getCfgMgr()->getContext()->applyLoggingCfg();
640  return (answer);
641  } catch (const std::exception& ex) {
642  // Rollback logging configuration.
643  process_->getCfgMgr()->getContext()->applyLoggingCfg();
644 
645  // build an error result
646  ConstElementPtr error = createAnswer(COMMAND_ERROR,
647  std::string("Configuration parsing failed: ") + ex.what());
648  return (error);
649  }
650 }
651 
654  const std::string& tag = process_->getCfgMgr()->getContext()->getServerTag();
655  ElementPtr response = Element::createMap();
656  response->set("server-tag", Element::create(tag));
657 
658  return (createAnswer(COMMAND_SUCCESS, response));
659 }
660 
663  ElementPtr status = Element::createMap();
664  status->set("pid", Element::create(static_cast<int>(getpid())));
665 
666  auto now = boost::posix_time::second_clock::universal_time();
667  if (!start_.is_not_a_date_time()) {
668  auto uptime = now - start_;
669  status->set("uptime", Element::create(uptime.total_seconds()));
670  }
671 
672  auto last_commit = process_->getCfgMgr()->getContext()->getLastCommitTime();
673  if (!last_commit.is_not_a_date_time()) {
674  auto reload = now - last_commit;
675  status->set("reload", Element::create(reload.total_seconds()));
676  }
677 
678  return (createAnswer(COMMAND_SUCCESS, status));
679 }
680 
683  ConstElementPtr answer;
684 
685  // For version-get put the extended version in arguments
686  ElementPtr extended = Element::create(getVersion(true));
687  ElementPtr arguments = Element::createMap();
688  arguments->set("extended", extended);
689  answer = createAnswer(COMMAND_SUCCESS, getVersion(false), arguments);
690  return (answer);
691 }
692 
695  return (createAnswer(COMMAND_SUCCESS, isc::detail::getConfigReport()));
696 }
697 
700  // Shutdown is universal. If its not that, then try it as
701  // a custom command supported by the derivation. If that
702  // doesn't pan out either, than send to it the application
703  // as it may be supported there.
704 
705  int exit_value = EXIT_SUCCESS;
706  if (args) {
707  // @todo Should we go ahead and shutdown even if the args are invalid?
708  if (args->getType() != Element::map) {
709  return (createAnswer(CONTROL_RESULT_ERROR, "Argument must be a map"));
710  }
711 
712  ConstElementPtr param = args->get("exit-value");
713  if (param) {
714  if (param->getType() != Element::integer) {
716  "parameter 'exit-value' is not an integer"));
717  }
718 
719  exit_value = param->intValue();
720  }
721  }
722 
723  setExitValue(exit_value);
724  return (shutdownProcess(args));
725 }
726 
729  if (process_) {
730  return (process_->shutdown(args));
731  }
732 
733  // Not really a failure, but this condition is worth noting. In reality
734  // it should be pretty hard to cause this.
735  LOG_WARN(dctl_logger, DCTL_NOT_RUNNING).arg(app_name_);
736  return (createAnswer(COMMAND_SUCCESS, "Process has not been initialized"));
737 }
738 
739 void
742 
743  // Create our signal set.
744  io_signal_set_.reset(new IOSignalSet(io_service_,
745  std::bind(&DControllerBase::
747  this, ph::_1)));
748  // Register for the signals we wish to handle.
749  io_signal_set_->add(SIGHUP);
750  io_signal_set_->add(SIGINT);
751  io_signal_set_->add(SIGTERM);
752 }
753 
754 void
756  switch (signum) {
757  case SIGHUP:
758  {
760  .arg(signum).arg(getConfigFile());
761  int rcode;
762  ConstElementPtr comment = parseAnswer(rcode, configFromFile());
763  if (rcode != 0) {
765  .arg(comment->stringValue());
766  }
767 
768  break;
769  }
770 
771  case SIGINT:
772  case SIGTERM:
773  {
775  DCTL_SHUTDOWN_SIGNAL_RECVD).arg(signum);
776  ElementPtr arg_set;
777  shutdownHandler(SHUT_DOWN_COMMAND, arg_set);
778  break;
779  }
780 
781  default:
783  break;
784  }
785 }
786 
787 void
788 DControllerBase::usage(const std::string & text) {
789  if (text != "") {
790  std::cerr << "Usage error: " << text << std::endl;
791  }
792 
793  std::cerr << "Usage: " << bin_name_ << std::endl
794  << " -v: print version number and exit" << std::endl
795  << " -V: print extended version information and exit"
796  << std::endl
797  << " -W: display the configuration report and exit"
798  << std::endl
799  << " -d: optional, verbose output " << std::endl
800  << " -c <config file name> : mandatory,"
801  << " specify name of configuration file" << std::endl
802  << " -t <config file name> : check the"
803  << " configuration file and exit" << std::endl;
804 
805  // add any derivation specific usage
806  std::cerr << getUsageText() << std::endl;
807 }
808 
810  // Explicitly unload hooks
811  HooksManager::prepareUnloadLibraries();
812  if (!HooksManager::unloadLibraries()) {
813  auto names = HooksManager::getLibraryNames();
814  std::string msg;
815  if (!names.empty()) {
816  msg = names[0];
817  for (size_t i = 1; i < names.size(); ++i) {
818  msg += std::string(", ") + names[i];
819  }
820  }
822  }
823 }
824 
825 // Refer to config_report so it will be embedded in the binary
827 
828 std::string
830  std::stringstream tmp;
831 
832  tmp << VERSION;
833  if (extended) {
834  tmp << std::endl << EXTENDED_VERSION << std::endl;
835  tmp << "linked with:" << std::endl;
836  tmp << isc::log::Logger::getVersion() << std::endl;
837  tmp << getVersionAddendum();
838  }
839 
840  return (tmp.str());
841 }
842 
843 } // end of namespace isc::process
844 
845 } // end of namespace isc
virtual isc::data::ConstElementPtr parseFile(const std::string &file_name)
Parse a given file into Elements.
Definition: d_controller.cc:56
boost::shared_ptr< DControllerBase > DControllerBasePtr
Definition: d_controller.h:78
#define LOG_WARN(LOGGER, MESSAGE)
Macro to conveniently test warn output and log it.
Definition: macros.h:26
std::string getVersion(bool extended)
returns Kea version on stdout and exit.
isc::data::ConstElementPtr statusGetHandler(const std::string &command, isc::data::ConstElementPtr args)
handler for status-get command
isc::data::ConstElementPtr configTestHandler(const std::string &command, isc::data::ConstElementPtr args)
handler for config-test command
isc::data::ConstElementPtr serverTagGetHandler(const std::string &command, isc::data::ConstElementPtr args)
handler for server-tag-get command
virtual isc::data::ConstElementPtr configFromFile()
Reconfigures the process from a configuration file.
void usage(const std::string &text)
Prints the program usage text to std error.
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
Definition: macros.h:20
ConstElementPtr createAnswer(const int status_code, const std::string &text, const ConstElementPtr &arg)
const int CONTROL_RESULT_SUCCESS
Status code indicating a successful operation.
const isc::log::MessageID DCTL_INIT_PROCESS
isc::data::ConstElementPtr configReloadHandler(const std::string &command, isc::data::ConstElementPtr args)
handler for config-reload command
Exception thrown when the application process fails.
Definition: d_controller.h:55
virtual void processSignal(int signum)
Application-level signal processing method.
void parseArgs(int argc, char *argv[])
Processes the command line arguments.
const isc::log::MessageID DCTL_RUN_PROCESS
void checkConfigFile() const
Checks the configuration file name.
Definition: daemon.cc:115
virtual ~DControllerBase()
Destructor.
const isc::log::MessageID DCTL_UNLOAD_LIBRARIES_ERROR
const isc::log::MessageID DCTL_STANDALONE
Base class for all configurations.
Definition: config_base.h:33
const isc::log::MessageID DCTL_CFG_FILE_RELOAD_SIGNAL_RECVD
#define LOG_ERROR(LOGGER, MESSAGE)
Macro to conveniently test error output and log it.
Definition: macros.h:32
const int CONTROL_RESULT_ERROR
Status code indicating a general failure.
isc::log::Logger dctl_logger("dctl")
Defines the logger used within libkea-process library.
Definition: d_log.h:18
boost::shared_ptr< Element > ElementPtr
Definition: data.h:24
boost::posix_time::ptime start_
Timestamp of the start of the daemon.
Definition: daemon.h:263
void runProcess()
Invokes the application process&#39;s event loop,(DBaseProcess::run).
const isc::log::MessageID DCTL_INIT_PROCESS_FAIL
int getExitValue()
Fetches the exit value.
Definition: daemon.h:220
virtual bool customOption(int option, char *optarg)
Virtual method that provides derivations the opportunity to support additional command line options...
const isc::log::MessageID DCTL_CFG_FILE_RELOAD_ERROR
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
isc::data::ConstElementPtr shutdownHandler(const std::string &command, isc::data::ConstElementPtr args)
handler for &#39;shutdown&#39; command
const isc::log::MessageID DCTL_SHUTDOWN_SIGNAL_RECVD
std::string getConfigFile() const
Returns config file name.
Definition: daemon.cc:105
Exception used to convey version info upwards.
Definition: d_controller.h:41
virtual std::string getVersionAddendum()
Fetches text containing additional version specifics.
Definition: d_controller.h:601
static void setDefaultLoggerName(const std::string &logger)
Sets the default logger name.
Definition: daemon.h:215
const isc::log::MessageID DCTL_DEVELOPMENT_VERSION
isc::data::ConstElementPtr shutdownProcess(isc::data::ConstElementPtr args)
Initiates shutdown procedure.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
const isc::log::MessageID DCTL_ALREADY_RUNNING
const char *const * d_config_report
Exception thrown when the controller encounters an operational error.
Definition: d_controller.h:70
static void setProcName(const std::string &proc_name)
Sets the process name.
Definition: daemon.cc:135
const isc::log::MessageID DCTL_PROCESS_FAILED
virtual isc::data::ConstElementPtr checkConfig(isc::data::ConstElementPtr new_config)
Instance method invoked by the configuration event handler and which processes the actual configurati...
void setConfigFile(const std::string &config_file)
Sets the configuration file name.
Definition: daemon.cc:110
std::string handleOtherObjects(isc::data::ConstElementPtr args)
Deals with other (i.e.
boost::shared_ptr< const Element > ConstElementPtr
Definition: data.h:27
isc::data::ConstElementPtr configWriteHandler(const std::string &command, isc::data::ConstElementPtr args)
handler for config-write command
void checkConfigOnly()
Check the configuration.
const isc::log::MessageID DCTL_STARTING
static void setVerbose(const bool verbose)
Sets or clears verbose mode.
Definition: daemon.cc:79
virtual isc::data::ConstElementPtr updateConfig(isc::data::ConstElementPtr new_config)
Instance method invoked by the configuration event handler and which processes the actual configurati...
virtual int launch(int argc, char *argv[], const bool test_mode)
Acts as the primary entry point into the controller execution and provides the outermost application ...
Definition: d_controller.cc:62
Exception thrown when the command line is invalid.
Definition: d_controller.h:30
This is a base class for exceptions thrown from the DNS library module.
ConstElementPtr parseAnswer(int &rcode, const ConstElementPtr &msg)
static void setController(const DControllerBasePtr &controller)
Static setter which sets the singleton instance.
Definition: d_controller.cc:44
Defines the logger used by the top-level component of kea-lfc.
const isc::log::MessageID DCTL_CONFIG_DEPRECATED
const char *const config_report[]
isc::data::ConstElementPtr configGetHandler(const std::string &command, isc::data::ConstElementPtr args)
handler for config-get command
static void loggerInit(const char *log_name, bool verbose)
Initializes logger.
Definition: daemon.cc:88
Logging initialization functions.
void setExitValue(int value)
Sets the exit value.
Definition: daemon.h:227
virtual size_t writeConfigFile(const std::string &config_file, isc::data::ConstElementPtr cfg=isc::data::ConstElementPtr()) const
Writes current configuration to specified file.
Definition: daemon.cc:229
void initProcess()
Instantiates the application process and then initializes it.
const isc::log::MessageID DCTL_NOT_RUNNING
isc::data::ConstElementPtr configSetHandler(const std::string &command, isc::data::ConstElementPtr args)
handler for config-set command
This file contains several functions and constants that are used for handling commands and responses ...
Exception thrown when the controller launch fails.
Definition: d_controller.h:48
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition: macros.h:14
virtual const std::string getUsageText() const
Virtual method which can be used to contribute derivation specific usage text.
Definition: d_controller.h:387
static std::string getVersion()
Version.
Definition: log/logger.cc:62
std::string getConfigReport()
Definition: cfgrpt.cc:20
#define LOG_FATAL(LOGGER, MESSAGE)
Macro to conveniently test fatal output and log it.
Definition: macros.h:38
const isc::log::MessageID DCTL_SHUTDOWN
isc::data::ConstElementPtr buildReportHandler(const std::string &command, isc::data::ConstElementPtr args)
handler for &#39;build-report&#39; command
Exception thrown when the PID file points to a live PID.
Definition: daemon.h:25
virtual const std::string getCustomOpts() const
Virtual method which returns a string containing the option letters for any custom command line optio...
Definition: d_controller.h:397
Exception thrown when the application process encounters an operation in its event loop (i...
Definition: d_controller.h:63
void initSignalHandling()
Initializes signal handling.
const isc::log::MessageID DCTL_CONFIG_FILE_LOAD_FAIL
void createPIDFile(int pid=0)
Creates the PID file.
Definition: daemon.cc:203
Application Controller.
Definition: d_controller.h:104
const int DBGLVL_START_SHUT
This is given a value of 0 as that is the level selected if debugging is enabled without giving a lev...
Definition: log_dbglevels.h:50
const isc::log::MessageID DCTL_PID_FILE_ERROR
bool isCheckOnly() const
Supplies whether or not check only mode is enabled.
Definition: d_controller.h:442
virtual DProcessBase * createProcess()=0
Abstract method that is responsible for instantiating the application process object.
std::string getAppName() const
Fetches the name of the application under control.
Definition: d_controller.h:222
isc::data::ConstElementPtr versionGetHandler(const std::string &command, isc::data::ConstElementPtr args)
handler for version-get command
boost::shared_ptr< ConfigBase > ConfigPtr
Non-const pointer to the ConfigBase.
Definition: config_base.h:176
static void configureLogger(const isc::data::ConstElementPtr &log_config, const isc::process::ConfigPtr &storage)
Configures logger.
Definition: daemon.cc:66
const isc::log::MessageID DCTL_UNSUPPORTED_SIGNAL