Kea 3.3.1
d_controller.cc
Go to the documentation of this file.
1// Copyright (C) 2013-2026 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#include <kea_version.h>
9
12#include <config/command_mgr.h>
15#include <hooks/hooks_manager.h>
16#include <log/logger.h>
17#include <log/logger_support.h>
19#include <process/config_base.h>
21#include <process/d_log.h>
22#include <process/daemon.h>
23#include <util/encode/encode.h>
24#include <util/filesystem.h>
25
26#include <cstdlib>
27#include <functional>
28#include <sstream>
29#include <string>
30
31#include <signal.h>
32#include <unistd.h>
33
34using namespace isc::asiolink;
35using namespace isc::config;
36using namespace isc::data;
37using namespace isc::hooks;
38using namespace isc::util;
39namespace ph = std::placeholders;
40
41namespace isc {
42namespace process {
43
44DControllerBasePtr DControllerBase::controller_;
45
46// Note that the constructor instantiates the controller's primary IOService.
47DControllerBase::DControllerBase(const char* app_name, const char* bin_name)
48 : app_name_(app_name), bin_name_(bin_name),
49 verbose_(false), check_only_(false),
50 io_service_(new isc::asiolink::IOService()),
51 io_signal_set_() {
52}
53
54void
56 if (controller_) {
57 // This shouldn't happen, but let's make sure it can't be done.
58 // It represents a programmatic error.
59 isc_throw(DControllerBaseError, "Multiple controller instances attempted.");
60 }
61
62 controller_ = controller;
63}
64
66DControllerBase::parseFile(const std::string&) {
67 ConstElementPtr elements;
68 return (elements);
69}
70
71int
72DControllerBase::launch(int argc, char* argv[], const bool test_mode) {
73
74 // Step 1 is to parse the command line arguments.
75 try {
76 parseArgs(argc, argv);
77 } catch (const InvalidUsage& ex) {
78 usage(ex.what());
79 // rethrow it with an empty message
81 }
82
83 setProcName(bin_name_);
84
85 if (isCheckOnly()) {
87 return (EXIT_SUCCESS);
88 }
89
90 // It is important that we set a default logger name because this name
91 // will be used when the user doesn't provide the logging configuration
92 // in the Kea configuration file.
94
95 // Logger's default configuration depends on whether we are in the
96 // verbose mode or not. CfgMgr manages the logger configuration so
97 // the verbose mode is set for CfgMgr.
98 Daemon::setVerbose(verbose_);
99
100 // Do not initialize logger here if we are running unit tests. It would
101 // replace an instance of unit test specific logger.
102 if (!test_mode) {
103 // Now that we know what the mode flags are, we can init logging.
104 Daemon::loggerInit(bin_name_.c_str(), verbose_);
105 }
106
107 try {
109 } catch (const std::exception& ex) {
111 .arg(app_name_).arg(ex.what());
112 isc_throw(LaunchError, "Launch Failed: " << ex.what());
113 }
114
115 try {
117 } catch (const DaemonPIDExists& ex) {
119 .arg(bin_name_).arg(ex.what());
120 isc_throw(LaunchError, "Launch Failed: " << ex.what());
121 } catch (const std::exception& ex) {
123 .arg(app_name_).arg(ex.what());
124 isc_throw(LaunchError, "Launch failed: " << ex.what());
125 }
126
127 // Log the starting of the service.
129 .arg(app_name_)
130 .arg(getpid())
131 .arg(VERSION)
132 .arg(PACKAGE_VERSION_TYPE);
133
134 // When it is not a stable version dissuade use in production.
135 if (std::string(PACKAGE_VERSION_TYPE) == "development") {
137 }
138
139 if (file::amRunningAsRoot()) {
141 .arg(app_name_);
142 }
143
144 try {
145 // Step 2 is to create and initialize the application process object.
146 initProcess();
147 } catch (const std::exception& ex) {
149 .arg(app_name_).arg(ex.what());
151 "Application Process initialization failed: " << ex.what());
152 }
153
155 .arg(app_name_);
156
157 // Step 3 is to load configuration from file.
158 int rcode;
159 ConstElementPtr comment = parseAnswer(rcode, configFromFile());
160 if (rcode != 0) {
162 .arg(app_name_).arg(comment->stringValue());
163 isc_throw(ProcessInitError, "Could Not load configuration file: "
164 << comment->stringValue());
165 }
166
167 // Note that the controller was started.
168 start_ = boost::posix_time::second_clock::universal_time();
169
170 // Everything is clear for launch, so start the application's
171 // event loop.
172 try {
173 // Now that we have a process, we can set up signal handling.
175 runProcess();
176 } catch (const std::exception& ex) {
178 .arg(app_name_).arg(ex.what());
180 "Application process event loop failed: " << ex.what());
181 }
182
183 // All done, so bail out.
185 .arg(app_name_).arg(getpid()).arg(VERSION);
186
187 return (getExitValue());
188}
189
190void
192 try {
193 // We need to initialize logging, in case any error
194 // messages are to be printed.
195 // This is just a test, so we don't care about lockfile.
196 setenv("KEA_LOCKFILE_DIR", "none", 0);
198 Daemon::setVerbose(verbose_);
199 Daemon::loggerInit(bin_name_.c_str(), verbose_);
200
201 // Check the syntax first.
202 std::string config_file = getConfigFile();
203 if (config_file.empty()) {
204 // Basic sanity check: file name must not be empty.
205 isc_throw(InvalidUsage, "JSON configuration file not specified");
206 }
207 ConstElementPtr whole_config = parseFile(config_file);
208 if (!whole_config) {
209 // No fallback to fromJSONFile
210 isc_throw(InvalidUsage, "No configuration found");
211 }
212 if (verbose_) {
213 std::cerr << "Syntax check OK" << std::endl;
214 }
215
216 // Check the logic next.
217 ConstElementPtr module_config;
218 module_config = whole_config->get(getAppName());
219 if (!module_config) {
220 isc_throw(InvalidUsage, "Config file " << config_file <<
221 " does not include '" << getAppName() << "' entry");
222 }
223 if (module_config->getType() != Element::map) {
224 isc_throw(InvalidUsage, "Config file " << config_file <<
225 " includes not map '" << getAppName() << "' entry");
226 }
227
228 // Handle other (i.e. not application name) objects.
229 std::string errmsg = handleOtherObjects(whole_config);
230 if (!errmsg.empty()) {
231 isc_throw(InvalidUsage, "Config file " << config_file << errmsg);
232 }
233
234 // Get an application process object.
235 initProcess();
236
237 ConstElementPtr answer = checkConfig(module_config);
238 int rcode = 0;
239 answer = parseAnswer(rcode, answer);
240 if (rcode != 0) {
241 isc_throw(InvalidUsage, "Error encountered: "
242 << answer->stringValue());
243 }
244 } catch (const VersionMessage&) {
245 throw;
246 } catch (const InvalidUsage&) {
247 throw;
248 } catch (const std::exception& ex) {
249 isc_throw(InvalidUsage, "Syntax check failed with: " << ex.what());
250 }
251 return;
252}
253
254void
255DControllerBase::parseArgs(int argc, char* argv[]) {
256
257 if (argc == 1) {
259 }
260
261 // Iterate over the given command line options. If its a stock option
262 // ("c" or "d") handle it here. If its a valid custom option, then
263 // invoke customOption.
264 int ch;
265 optarg = 0;
266 opterr = 0;
267 optind = 1;
268 std::string opts("dvVWc:t:XF" + getCustomOpts());
269
270 // Defer exhausting of arguments to the end.
271 ExhaustOptions e(argc, argv, opts);
272
273 while ((ch = getopt(argc, argv, opts.c_str())) != -1) {
274 switch (ch) {
275 case 'd':
276 // Enables verbose logging.
277 verbose_ = true;
278 break;
279
280 case 'v':
281 // gather Kea version and throw so main() can catch and return
282 // rather than calling exit() here which disrupts gtest.
284 break;
285
286 case 'V':
287 // gather Kea version and throw so main() can catch and return
288 // rather than calling exit() here which disrupts gtest.
290 break;
291
292 case 'W':
293 // gather Kea config report and throw so main() can catch and
294 // return rather than calling exit() here which disrupts gtest.
296 break;
297
298 case 'c':
299 case 't':
300 // config file name
301 if (optarg == NULL) {
302 isc_throw(InvalidUsage, "configuration file name missing");
303 }
304
305 setConfigFile(optarg);
306
307 if (ch == 't') {
308 check_only_ = true;
309 }
310 break;
311
312 case 'X': // relax security checks
314 break;
315
316 case 'F': // exit on fatal error
318 break;
319
320 case '?': {
321 char const saved_optopt(optopt);
322 std::string const saved_optarg(optarg ? optarg : std::string());
323
324 // We hit an invalid option.
325 isc_throw(InvalidUsage, "unsupported option: -" << saved_optopt <<
326 (saved_optarg.empty() ? std::string() : " " + saved_optarg));
327
328 break;
329 }
330
331 default:
332 // We hit a valid custom option
333 if (!customOption(ch, optarg)) {
334 char const saved_optopt(optopt);
335 std::string const saved_optarg(optarg ? optarg : std::string());
336
337 // We hit an invalid option.
338 isc_throw(InvalidUsage, "unsupported option: -" << saved_optopt <<
339 (saved_optarg.empty() ? std::string() : " " + saved_optarg));
340 }
341 break;
342 }
343 }
344
345 // There was too much information on the command line.
346 if (argc > optind) {
347 isc_throw(InvalidUsage, "extraneous command line information");
348 }
349}
350
351bool
352DControllerBase::customOption(int /* option */, char* /*optarg*/) {
353 // Default implementation returns false.
354 return (false);
355}
356
357void
360 .arg(app_name_);
361
362 // Invoke virtual method to instantiate the application process.
363 try {
364 process_.reset(createProcess());
365 } catch (const std::exception& ex) {
366 isc_throw(DControllerBaseError, std::string("createProcess failed: ") +
367 ex.what());
368 }
369
370 // This is pretty unlikely, but will test for it just to be safe..
371 if (!process_) {
372 isc_throw(DControllerBaseError, "createProcess returned NULL");
373 }
374
375 // Invoke application's init method (Note this call should throw
376 // DProcessBaseError if it fails).
377 process_->init();
378}
379
382 // Rollback any previous staging configuration. For D2, only a
383 // logger configuration is used here.
384 // We're not using cfgmgr to store logging configuration anymore.
385 // isc::dhcp::CfgMgr::instance().rollback();
386
387 // Will hold configuration.
388 ConstElementPtr module_config;
389 // Will receive configuration result.
390 ConstElementPtr answer;
391 try {
392 std::string config_file = getConfigFile();
393 if (config_file.empty()) {
394 // Basic sanity check: file name must not be empty.
395 isc_throw(BadValue, "JSON configuration file not specified. Please "
396 "use -c command line option.");
397 }
398
399 // If parseFile returns an empty pointer, then pass the file onto the
400 // original JSON parser.
401 ConstElementPtr whole_config = parseFile(config_file);
402 if (!whole_config) {
403 // Read contents of the file and parse it as JSON
404 whole_config = Element::fromJSONFile(config_file, true);
405 }
406
407 // Extract derivation-specific portion of the configuration.
408 module_config = whole_config->get(getAppName());
409 if (!module_config) {
410 isc_throw(BadValue, "Config file " << config_file <<
411 " does not include '" <<
412 getAppName() << "' entry.");
413 }
414 if (module_config->getType() != Element::map) {
415 isc_throw(InvalidUsage, "Config file " << config_file <<
416 " includes not map '" << getAppName() << "' entry");
417 }
418
419 // Handle other (i.e. not application name) objects.
420 std::string errmsg = handleOtherObjects(whole_config);
421 if (!errmsg.empty()) {
422 isc_throw(InvalidUsage, "Config file " << config_file << errmsg);
423 }
424
425 // Let's configure logging before applying the configuration,
426 // so we can log things during configuration process.
427
428 // Temporary storage for logging configuration
429 ConfigPtr storage(new ConfigBase());
430
431 // Configure logging to the temporary storage.
432 Daemon::configureLogger(module_config, storage);
433
434 // Let's apply the new logging. We do it early, so we'll be able
435 // to print out what exactly is wrong with the new config in
436 // case of problems.
437 storage->applyLoggingCfg();
438
439 answer = updateConfig(module_config);
440 // In all cases the right logging configuration is in the context.
441 process_->getCfgMgr()->getContext()->applyLoggingCfg();
442 } catch (const std::exception& ex) {
443 // Rollback logging configuration.
444 process_->getCfgMgr()->getContext()->applyLoggingCfg();
445
446 // build an error result
448 std::string("Configuration parsing failed: ") + ex.what());
449 return (error);
450 }
451
452 return (answer);
453}
454
455void
458 .arg(app_name_);
459 if (!process_) {
460 // This should not be possible.
461 isc_throw(DControllerBaseError, "Process not initialized");
462 }
463
464 // Invoke the application process's run method. This may throw
465 // DProcessBaseError
466 process_->run();
467}
468
469// Instance method for handling new config
472 return (process_->configure(new_config, false));
473}
474
475// Instance method for checking new config
478 return (process_->configure(new_config, true));
479}
480
483 ConstElementPtr /*args*/) {
484 ElementPtr config = process_->getCfgMgr()->getContext()->toElement();
485 std::string hash = BaseCommandMgr::getHash(config);
486 config->set("hash", Element::create(hash));
487
489}
490
493 ConstElementPtr /*args*/) {
494 ConstElementPtr config = process_->getCfgMgr()->getContext()->toElement();
495 std::string hash = BaseCommandMgr::getHash(config);
497 params->set("hash", Element::create(hash));
498 return (createAnswer(CONTROL_RESULT_SUCCESS, params));
499}
500
503 ConstElementPtr args) {
504 std::string filename;
505
506 if (args) {
507 if (args->getType() != Element::map) {
508 return (createAnswer(CONTROL_RESULT_ERROR, "Argument must be a map"));
509 }
510 ConstElementPtr filename_param = args->get("filename");
511 if (filename_param) {
512 if (filename_param->getType() != Element::string) {
514 "passed parameter 'filename' "
515 "is not a string"));
516 }
517 filename = filename_param->stringValue();
518 }
519 }
520
521 if (filename.empty()) {
522 // filename parameter was not specified, so let's use
523 // whatever we remember
524 filename = getConfigFile();
525 if (filename.empty()) {
527 "Unable to determine filename."
528 "Please specify filename explicitly."));
529 }
530 } else {
531 try {
532 checkWriteConfigFile(filename);
533 } catch (const isc::Exception& ex) {
534 std::ostringstream msg;
535 msg << "not allowed to write config into " << filename
536 << ": " << ex.what();
537 return (createAnswer(CONTROL_RESULT_ERROR, msg.str()));
538 }
539 }
540
541 // Ok, it's time to write the file.
542 size_t size = 0;
543
544 try {
545 ElementPtr cfg = process_->getCfgMgr()->getContext()->toElement();
546 size = writeConfigFile(filename, cfg);
547 } catch (const isc::Exception& ex) {
549 std::string("Error during config-write:")
550 + ex.what()));
551 }
552 if (size == 0) {
554 "Error writing configuration to " + filename));
555 }
556
557 // Ok, it's time to return the successful response.
559 params->set("size", Element::create(static_cast<long long>(size)));
560 params->set("filename", Element::create(filename));
561
562 return (createAnswer(CONTROL_RESULT_SUCCESS, "Configuration written to "
563 + filename + " successful", params));
564}
565
566std::string
568 // Check obsolete or unknown (aka unsupported) objects.
569 const std::string& app_name = getAppName();
570 std::string errmsg;
571 for (auto const& obj : args->mapValue()) {
572 const std::string& obj_name = obj.first;
573 if (obj_name == app_name) {
574 continue;
575 }
577 .arg("'" + obj_name + "', defining anything in global level besides '"
578 + app_name + "' is no longer supported.");
579 if (errmsg.empty()) {
580 errmsg = " contains unsupported '" + obj_name + "' parameter";
581 } else {
582 errmsg += " (and '" + obj_name + "')";
583 }
584 }
585 return (errmsg);
586}
587
590 const int status_code = CONTROL_RESULT_ERROR; // 1 indicates an error
591 ConstElementPtr module_config;
592 std::string app_name = getAppName();
593 std::string message;
594
595 // Command arguments are expected to be:
596 // { "Module": { ... } }
597 if (!args) {
598 message = "Missing mandatory 'arguments' parameter.";
599 } else {
600 module_config = args->get(app_name);
601 if (!module_config) {
602 message = "Missing mandatory '" + app_name + "' parameter.";
603 } else if (module_config->getType() != Element::map) {
604 message = "'" + app_name + "' parameter expected to be a map.";
605 }
606 }
607
608 if (message.empty()) {
609 // Handle other (i.e. not application name) objects.
610 std::string errmsg = handleOtherObjects(args);
611 if (!errmsg.empty()) {
612 message = "'arguments' parameter" + errmsg;
613 }
614 }
615
616 if (!message.empty()) {
617 // Something is amiss with arguments, return a failure response.
618 ConstElementPtr result = isc::config::createAnswer(status_code,
619 message);
620 return (result);
621 }
622
623 // We are starting the configuration process so we should remove any
624 // staging configuration that has been created during previous
625 // configuration attempts.
626 // We're not using cfgmgr to store logging information anymore.
627 // isc::dhcp::CfgMgr::instance().rollback();
628
629 // Now we check the server proper.
630 return (checkConfig(module_config));
631}
632
635 // Add reload in message?
636 return (configFromFile());
637}
638
641 const int status_code = CONTROL_RESULT_ERROR; // 1 indicates an error
642 ConstElementPtr module_config;
643 std::string app_name = getAppName();
644 std::string message;
645
646 // Command arguments are expected to be:
647 // { "Module": { ... } }
648 if (!args) {
649 message = "Missing mandatory 'arguments' parameter.";
650 } else {
651 module_config = args->get(app_name);
652 if (!module_config) {
653 message = "Missing mandatory '" + app_name + "' parameter.";
654 } else if (module_config->getType() != Element::map) {
655 message = "'" + app_name + "' parameter expected to be a map.";
656 }
657 }
658
659 if (!message.empty()) {
660 // Something is amiss with arguments, return a failure response.
661 ConstElementPtr result = isc::config::createAnswer(status_code,
662 message);
663 return (result);
664 }
665
666 try {
667
668 // Handle other (i.e. not application name) objects.
669 handleOtherObjects(args);
670
671 // We are starting the configuration process so we should remove any
672 // staging configuration that has been created during previous
673 // configuration attempts.
674 // We're not using cfgmgr to store logging information anymore.
675 // isc::dhcp::CfgMgr::instance().rollback();
676
677 // Temporary storage for logging configuration
678 ConfigPtr storage(new ConfigBase());
679
680 // Configure logging to the temporary storage.
681 Daemon::configureLogger(module_config, storage);
682
683 // Let's apply the new logging. We do it early, so we'll be able
684 // to print out what exactly is wrong with the new config in
685 // case of problems.
686 storage->applyLoggingCfg();
687
688 ConstElementPtr answer = updateConfig(module_config);
689 int rcode = 0;
690 parseAnswer(rcode, answer);
691
693 setExitValue(EXIT_FAILURE);
695 }
696 // In all cases the right logging configuration is in the context.
697 process_->getCfgMgr()->getContext()->applyLoggingCfg();
698 return (answer);
699 } catch (const std::exception& ex) {
700 // Rollback logging configuration.
701 process_->getCfgMgr()->getContext()->applyLoggingCfg();
702
703 // build an error result
705 std::string("Configuration parsing failed: ") + ex.what());
706 return (error);
707 }
708}
709
712 const std::string& tag = process_->getCfgMgr()->getContext()->getServerTag();
713 ElementPtr response = Element::createMap();
714 response->set("server-tag", Element::create(tag));
715
716 return (createAnswer(CONTROL_RESULT_SUCCESS, response));
717}
718
722 status->set("pid", Element::create(static_cast<int>(getpid())));
723
724 auto now = boost::posix_time::second_clock::universal_time();
725 if (!start_.is_not_a_date_time()) {
726 auto uptime = now - start_;
727 status->set("uptime", Element::create(uptime.total_seconds()));
728 }
729
730 auto last_commit = process_->getCfgMgr()->getContext()->getLastCommitTime();
731 if (!last_commit.is_not_a_date_time()) {
732 auto reload = now - last_commit;
733 status->set("reload", Element::create(reload.total_seconds()));
734 }
735
736 return (createAnswer(CONTROL_RESULT_SUCCESS, status));
737}
738
741 ConstElementPtr answer;
742
743 // For version-get put the extended version in arguments
744 ElementPtr extended = Element::create(getVersion(true));
745 ElementPtr arguments = Element::createMap();
746 arguments->set("extended", extended);
747 answer = createAnswer(CONTROL_RESULT_SUCCESS, getVersion(false), arguments);
748 return (answer);
749}
750
755
758 // Shutdown is universal. If its not that, then try it as
759 // a custom command supported by the derivation. If that
760 // doesn't pan out either, than send to it the application
761 // as it may be supported there.
762
763 int exit_value = EXIT_SUCCESS;
764 if (args) {
765 // @todo Should we go ahead and shutdown even if the args are invalid?
766 if (args->getType() != Element::map) {
767 return (createAnswer(CONTROL_RESULT_ERROR, "Argument must be a map"));
768 }
769
770 ConstElementPtr param = args->get("exit-value");
771 if (param) {
772 if (param->getType() != Element::integer) {
774 "parameter 'exit-value' is not an integer"));
775 }
776
777 exit_value = param->intValue();
778 }
779 }
780
781 setExitValue(exit_value);
782 return (shutdownProcess(args));
783}
784
787 if (process_) {
788 return (process_->shutdown(args));
789 }
790
791 // Not really a failure, but this condition is worth noting. In reality
792 // it should be pretty hard to cause this.
793 LOG_WARN(dctl_logger, DCTL_NOT_RUNNING).arg(app_name_);
794 return (createAnswer(CONTROL_RESULT_SUCCESS, "Process has not been initialized"));
795}
796
797void
800
801 // Create our signal set.
802 io_signal_set_.reset(new IOSignalSet(io_service_,
803 std::bind(&DControllerBase::
805 this, ph::_1)));
806 // Register for the signals we wish to handle.
807 io_signal_set_->add(SIGHUP);
808 io_signal_set_->add(SIGINT);
809 io_signal_set_->add(SIGTERM);
810}
811
812void
814 switch (signum) {
815 case SIGHUP:
816 {
818 .arg(signum).arg(getConfigFile());
819 int rcode;
820 ConstElementPtr comment = parseAnswer(rcode, configFromFile());
821 if (rcode != 0) {
823 .arg(comment->stringValue());
824 }
825
826 break;
827 }
828
829 case SIGINT:
830 case SIGTERM:
831 {
833 DCTL_SHUTDOWN_SIGNAL_RECVD).arg(signum);
834 ElementPtr arg_set;
835 shutdownHandler(SHUT_DOWN_COMMAND, arg_set);
836 break;
837 }
838
839 default:
841 break;
842 }
843}
844
845void
846DControllerBase::usage(const std::string & text) {
847 if (text != "") {
848 std::cerr << "Usage error: " << text << std::endl;
849 }
850
851 std::cerr << "Usage: " << bin_name_ << std::endl
852 << " -v: print version number and exit" << std::endl
853 << " -V: print extended version information and exit"
854 << std::endl
855 << " -W: display the configuration report and exit"
856 << std::endl
857 << " -d: optional, verbose output" << std::endl
858 << " -c <config file name> : mandatory,"
859 << " specify name of configuration file" << std::endl
860 << " -t <config file name> : check the"
861 << " configuration file and exit" << std::endl
862 << " -X: disables security restrictions" << std::endl
863 << " -F: exit on critical error" << std::endl;
864
865 // add any derivation specific usage
866 std::cerr << getUsageText() << std::endl;
867}
868
870 // Explicitly unload hooks
873 auto names = HooksManager::getLibraryNames();
874 std::string msg;
875 if (!names.empty()) {
876 msg = names[0];
877 for (size_t i = 1; i < names.size(); ++i) {
878 msg += std::string(", ") + names[i];
879 }
880 }
882 }
883
885
886 io_signal_set_.reset();
887 try {
888 getIOService()->poll();
889 } catch (...) {
890 // Don't want to throw exceptions from the destructor. The process
891 // is shutting down anyway.
892 }
893}
894
895std::string
897 std::stringstream tmp;
898
899 tmp << VERSION;
900 if (extended) {
901 tmp << " (" << SOURCE_OF_INSTALLATION << ")" << std::endl;
902 tmp << "premium: " << PREMIUM_EXTENDED_VERSION << std::endl;
903 tmp << "linked with:" << std::endl;
904 tmp << "- " << isc::log::Logger::getVersion() << std::endl;
906 }
907
908 return (tmp.str());
909}
910
911} // end of namespace isc::process
912
913} // end of namespace isc
static ElementPtr create(const Position &pos=ZERO_POSITION())
Create a NullElement.
Definition data.cc:300
@ map
Definition data.h:160
@ integer
Definition data.h:153
@ string
Definition data.h:157
static ElementPtr fromJSONFile(const std::string &file_name, bool preproc=false)
Reads contents of specified file and interprets it as JSON.
Definition data.cc:884
static ElementPtr createMap(const Position &pos=ZERO_POSITION())
Creates an empty MapElement type ElementPtr.
Definition data.cc:355
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
static void setShutdownOnFailure(bool shutdown)
Set the shutdown on critical failure flag.
Definition daemon.h:275
std::string getConfigFile() const
Returns config file name.
Definition daemon.cc:108
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:270
static void setVerbose(const bool verbose)
Sets or clears verbose mode.
Definition daemon.cc:83
static void configureLogger(const isc::data::ConstElementPtr &log_config, const isc::process::ConfigPtr &storage)
Configures logger.
Definition daemon.cc:70
boost::posix_time::ptime start_
Timestamp of the start of the daemon.
Definition daemon.h:292
static void loggerInit(const char *log_name, bool verbose)
Initializes logger.
Definition daemon.cc:92
void checkWriteConfigFile(std::string &file)
Checks the to-be-written configuration file name.
Definition daemon.cc:133
void setExitValue(int value)
Sets the exit value.
Definition daemon.h:242
void checkConfigFile() const
Checks the configuration file name.
Definition daemon.cc:118
static void setDefaultLoggerName(const std::string &logger)
Sets the default logger name.
Definition daemon.h:230
static void setProcName(const std::string &proc_name)
Sets the process name.
Definition daemon.cc:160
int getExitValue()
Fetches the exit value.
Definition daemon.h:235
void createPIDFile(int pid=0)
Creates the PID file.
Definition daemon.cc:237
static bool getShutdownOnFailure()
Get the shutdown on critical failure flag.
Definition daemon.h:268
void setConfigFile(const std::string &config_file)
Sets the configuration file name.
Definition daemon.cc:113
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 enforcement 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_FATAL_ERROR
Status code indicating that the command was unsuccessful and the configuration could not be reverted ...
const int CONTROL_RESULT_SUCCESS
Status code indicating a successful operation.
boost::shared_ptr< const Element > ConstElementPtr
Definition data.h:30
boost::shared_ptr< Element > ElementPtr
Definition data.h:29
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_ROOT_USER_SECURITY_WARNING
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
bool amRunningAsRoot()
Indicates if current user is root.
Defines the logger used by the top-level component of kea-lfc.