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