Kea 3.1.8
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:X" + 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 '?': {
317 char const saved_optopt(optopt);
318 std::string const saved_optarg(optarg ? optarg : std::string());
319
320 // We hit an invalid option.
321 isc_throw(InvalidUsage, "unsupported option: -" << saved_optopt <<
322 (saved_optarg.empty() ? std::string() : " " + saved_optarg));
323
324 break;
325 }
326
327 default:
328 // We hit a valid custom option
329 if (!customOption(ch, optarg)) {
330 char const saved_optopt(optopt);
331 std::string const saved_optarg(optarg ? optarg : std::string());
332
333 // We hit an invalid option.
334 isc_throw(InvalidUsage, "unsupported option: -" << saved_optopt <<
335 (saved_optarg.empty() ? std::string() : " " + saved_optarg));
336 }
337 break;
338 }
339 }
340
341 // There was too much information on the command line.
342 if (argc > optind) {
343 isc_throw(InvalidUsage, "extraneous command line information");
344 }
345}
346
347bool
348DControllerBase::customOption(int /* option */, char* /*optarg*/) {
349 // Default implementation returns false.
350 return (false);
351}
352
353void
356 .arg(app_name_);
357
358 // Invoke virtual method to instantiate the application process.
359 try {
360 process_.reset(createProcess());
361 } catch (const std::exception& ex) {
362 isc_throw(DControllerBaseError, std::string("createProcess failed: ") +
363 ex.what());
364 }
365
366 // This is pretty unlikely, but will test for it just to be safe..
367 if (!process_) {
368 isc_throw(DControllerBaseError, "createProcess returned NULL");
369 }
370
371 // Invoke application's init method (Note this call should throw
372 // DProcessBaseError if it fails).
373 process_->init();
374}
375
378 // Rollback any previous staging configuration. For D2, only a
379 // logger configuration is used here.
380 // We're not using cfgmgr to store logging configuration anymore.
381 // isc::dhcp::CfgMgr::instance().rollback();
382
383 // Will hold configuration.
384 ConstElementPtr module_config;
385 // Will receive configuration result.
386 ConstElementPtr answer;
387 try {
388 std::string config_file = getConfigFile();
389 if (config_file.empty()) {
390 // Basic sanity check: file name must not be empty.
391 isc_throw(BadValue, "JSON configuration file not specified. Please "
392 "use -c command line option.");
393 }
394
395 // If parseFile returns an empty pointer, then pass the file onto the
396 // original JSON parser.
397 ConstElementPtr whole_config = parseFile(config_file);
398 if (!whole_config) {
399 // Read contents of the file and parse it as JSON
400 whole_config = Element::fromJSONFile(config_file, true);
401 }
402
403 // Extract derivation-specific portion of the configuration.
404 module_config = whole_config->get(getAppName());
405 if (!module_config) {
406 isc_throw(BadValue, "Config file " << config_file <<
407 " does not include '" <<
408 getAppName() << "' entry.");
409 }
410 if (module_config->getType() != Element::map) {
411 isc_throw(InvalidUsage, "Config file " << config_file <<
412 " includes not map '" << getAppName() << "' entry");
413 }
414
415 // Handle other (i.e. not application name) objects.
416 std::string errmsg = handleOtherObjects(whole_config);
417 if (!errmsg.empty()) {
418 isc_throw(InvalidUsage, "Config file " << config_file << errmsg);
419 }
420
421 // Let's configure logging before applying the configuration,
422 // so we can log things during configuration process.
423
424 // Temporary storage for logging configuration
425 ConfigPtr storage(new ConfigBase());
426
427 // Configure logging to the temporary storage.
428 Daemon::configureLogger(module_config, storage);
429
430 // Let's apply the new logging. We do it early, so we'll be able
431 // to print out what exactly is wrong with the new config in
432 // case of problems.
433 storage->applyLoggingCfg();
434
435 answer = updateConfig(module_config);
436 // In all cases the right logging configuration is in the context.
437 process_->getCfgMgr()->getContext()->applyLoggingCfg();
438 } catch (const std::exception& ex) {
439 // Rollback logging configuration.
440 process_->getCfgMgr()->getContext()->applyLoggingCfg();
441
442 // build an error result
444 std::string("Configuration parsing failed: ") + ex.what());
445 return (error);
446 }
447
448 return (answer);
449}
450
451void
454 .arg(app_name_);
455 if (!process_) {
456 // This should not be possible.
457 isc_throw(DControllerBaseError, "Process not initialized");
458 }
459
460 // Invoke the application process's run method. This may throw
461 // DProcessBaseError
462 process_->run();
463}
464
465// Instance method for handling new config
468 return (process_->configure(new_config, false));
469}
470
471// Instance method for checking new config
474 return (process_->configure(new_config, true));
475}
476
479 ConstElementPtr /*args*/) {
480 ElementPtr config = process_->getCfgMgr()->getContext()->toElement();
481 std::string hash = BaseCommandMgr::getHash(config);
482 config->set("hash", Element::create(hash));
483
485}
486
489 ConstElementPtr /*args*/) {
490 ConstElementPtr config = process_->getCfgMgr()->getContext()->toElement();
491 std::string hash = BaseCommandMgr::getHash(config);
493 params->set("hash", Element::create(hash));
494 return (createAnswer(CONTROL_RESULT_SUCCESS, params));
495}
496
499 ConstElementPtr args) {
500 std::string filename;
501
502 if (args) {
503 if (args->getType() != Element::map) {
504 return (createAnswer(CONTROL_RESULT_ERROR, "Argument must be a map"));
505 }
506 ConstElementPtr filename_param = args->get("filename");
507 if (filename_param) {
508 if (filename_param->getType() != Element::string) {
510 "passed parameter 'filename' "
511 "is not a string"));
512 }
513 filename = filename_param->stringValue();
514 }
515 }
516
517 if (filename.empty()) {
518 // filename parameter was not specified, so let's use
519 // whatever we remember
520 filename = getConfigFile();
521 if (filename.empty()) {
523 "Unable to determine filename."
524 "Please specify filename explicitly."));
525 }
526 } else {
527 try {
528 checkWriteConfigFile(filename);
529 } catch (const isc::Exception& ex) {
530 std::ostringstream msg;
531 msg << "not allowed to write config into " << filename
532 << ": " << ex.what();
533 return (createAnswer(CONTROL_RESULT_ERROR, msg.str()));
534 }
535 }
536
537 // Ok, it's time to write the file.
538 size_t size = 0;
539
540 try {
541 ElementPtr cfg = process_->getCfgMgr()->getContext()->toElement();
542 size = writeConfigFile(filename, cfg);
543 } catch (const isc::Exception& ex) {
545 std::string("Error during config-write:")
546 + ex.what()));
547 }
548 if (size == 0) {
550 "Error writing configuration to " + filename));
551 }
552
553 // Ok, it's time to return the successful response.
555 params->set("size", Element::create(static_cast<long long>(size)));
556 params->set("filename", Element::create(filename));
557
558 return (createAnswer(CONTROL_RESULT_SUCCESS, "Configuration written to "
559 + filename + " successful", params));
560}
561
562std::string
564 // Check obsolete or unknown (aka unsupported) objects.
565 const std::string& app_name = getAppName();
566 std::string errmsg;
567 for (auto const& obj : args->mapValue()) {
568 const std::string& obj_name = obj.first;
569 if (obj_name == app_name) {
570 continue;
571 }
573 .arg("'" + obj_name + "', defining anything in global level besides '"
574 + app_name + "' is no longer supported.");
575 if (errmsg.empty()) {
576 errmsg = " contains unsupported '" + obj_name + "' parameter";
577 } else {
578 errmsg += " (and '" + obj_name + "')";
579 }
580 }
581 return (errmsg);
582}
583
586 const int status_code = CONTROL_RESULT_ERROR; // 1 indicates an error
587 ConstElementPtr module_config;
588 std::string app_name = getAppName();
589 std::string message;
590
591 // Command arguments are expected to be:
592 // { "Module": { ... } }
593 if (!args) {
594 message = "Missing mandatory 'arguments' parameter.";
595 } else {
596 module_config = args->get(app_name);
597 if (!module_config) {
598 message = "Missing mandatory '" + app_name + "' parameter.";
599 } else if (module_config->getType() != Element::map) {
600 message = "'" + app_name + "' parameter expected to be a map.";
601 }
602 }
603
604 if (message.empty()) {
605 // Handle other (i.e. not application name) objects.
606 std::string errmsg = handleOtherObjects(args);
607 if (!errmsg.empty()) {
608 message = "'arguments' parameter" + errmsg;
609 }
610 }
611
612 if (!message.empty()) {
613 // Something is amiss with arguments, return a failure response.
614 ConstElementPtr result = isc::config::createAnswer(status_code,
615 message);
616 return (result);
617 }
618
619 // We are starting the configuration process so we should remove any
620 // staging configuration that has been created during previous
621 // configuration attempts.
622 // We're not using cfgmgr to store logging information anymore.
623 // isc::dhcp::CfgMgr::instance().rollback();
624
625 // Now we check the server proper.
626 return (checkConfig(module_config));
627}
628
631 // Add reload in message?
632 return (configFromFile());
633}
634
637 const int status_code = CONTROL_RESULT_ERROR; // 1 indicates an error
638 ConstElementPtr module_config;
639 std::string app_name = getAppName();
640 std::string message;
641
642 // Command arguments are expected to be:
643 // { "Module": { ... } }
644 if (!args) {
645 message = "Missing mandatory 'arguments' parameter.";
646 } else {
647 module_config = args->get(app_name);
648 if (!module_config) {
649 message = "Missing mandatory '" + app_name + "' parameter.";
650 } else if (module_config->getType() != Element::map) {
651 message = "'" + app_name + "' parameter expected to be a map.";
652 }
653 }
654
655 if (!message.empty()) {
656 // Something is amiss with arguments, return a failure response.
657 ConstElementPtr result = isc::config::createAnswer(status_code,
658 message);
659 return (result);
660 }
661
662 try {
663
664 // Handle other (i.e. not application name) objects.
665 handleOtherObjects(args);
666
667 // We are starting the configuration process so we should remove any
668 // staging configuration that has been created during previous
669 // configuration attempts.
670 // We're not using cfgmgr to store logging information anymore.
671 // isc::dhcp::CfgMgr::instance().rollback();
672
673 // Temporary storage for logging configuration
674 ConfigPtr storage(new ConfigBase());
675
676 // Configure logging to the temporary storage.
677 Daemon::configureLogger(module_config, storage);
678
679 // Let's apply the new logging. We do it early, so we'll be able
680 // to print out what exactly is wrong with the new config in
681 // case of problems.
682 storage->applyLoggingCfg();
683
684 ConstElementPtr answer = updateConfig(module_config);
685 int rcode = 0;
686 parseAnswer(rcode, answer);
687 // In all cases the right logging configuration is in the context.
688 process_->getCfgMgr()->getContext()->applyLoggingCfg();
689 return (answer);
690 } catch (const std::exception& ex) {
691 // Rollback logging configuration.
692 process_->getCfgMgr()->getContext()->applyLoggingCfg();
693
694 // build an error result
696 std::string("Configuration parsing failed: ") + ex.what());
697 return (error);
698 }
699}
700
703 const std::string& tag = process_->getCfgMgr()->getContext()->getServerTag();
704 ElementPtr response = Element::createMap();
705 response->set("server-tag", Element::create(tag));
706
707 return (createAnswer(CONTROL_RESULT_SUCCESS, response));
708}
709
713 status->set("pid", Element::create(static_cast<int>(getpid())));
714
715 auto now = boost::posix_time::second_clock::universal_time();
716 if (!start_.is_not_a_date_time()) {
717 auto uptime = now - start_;
718 status->set("uptime", Element::create(uptime.total_seconds()));
719 }
720
721 auto last_commit = process_->getCfgMgr()->getContext()->getLastCommitTime();
722 if (!last_commit.is_not_a_date_time()) {
723 auto reload = now - last_commit;
724 status->set("reload", Element::create(reload.total_seconds()));
725 }
726
727 return (createAnswer(CONTROL_RESULT_SUCCESS, status));
728}
729
732 ConstElementPtr answer;
733
734 // For version-get put the extended version in arguments
735 ElementPtr extended = Element::create(getVersion(true));
736 ElementPtr arguments = Element::createMap();
737 arguments->set("extended", extended);
738 answer = createAnswer(CONTROL_RESULT_SUCCESS, getVersion(false), arguments);
739 return (answer);
740}
741
746
749 // Shutdown is universal. If its not that, then try it as
750 // a custom command supported by the derivation. If that
751 // doesn't pan out either, than send to it the application
752 // as it may be supported there.
753
754 int exit_value = EXIT_SUCCESS;
755 if (args) {
756 // @todo Should we go ahead and shutdown even if the args are invalid?
757 if (args->getType() != Element::map) {
758 return (createAnswer(CONTROL_RESULT_ERROR, "Argument must be a map"));
759 }
760
761 ConstElementPtr param = args->get("exit-value");
762 if (param) {
763 if (param->getType() != Element::integer) {
765 "parameter 'exit-value' is not an integer"));
766 }
767
768 exit_value = param->intValue();
769 }
770 }
771
772 setExitValue(exit_value);
773 return (shutdownProcess(args));
774}
775
778 if (process_) {
779 return (process_->shutdown(args));
780 }
781
782 // Not really a failure, but this condition is worth noting. In reality
783 // it should be pretty hard to cause this.
784 LOG_WARN(dctl_logger, DCTL_NOT_RUNNING).arg(app_name_);
785 return (createAnswer(CONTROL_RESULT_SUCCESS, "Process has not been initialized"));
786}
787
788void
791
792 // Create our signal set.
793 io_signal_set_.reset(new IOSignalSet(io_service_,
794 std::bind(&DControllerBase::
796 this, ph::_1)));
797 // Register for the signals we wish to handle.
798 io_signal_set_->add(SIGHUP);
799 io_signal_set_->add(SIGINT);
800 io_signal_set_->add(SIGTERM);
801}
802
803void
805 switch (signum) {
806 case SIGHUP:
807 {
809 .arg(signum).arg(getConfigFile());
810 int rcode;
811 ConstElementPtr comment = parseAnswer(rcode, configFromFile());
812 if (rcode != 0) {
814 .arg(comment->stringValue());
815 }
816
817 break;
818 }
819
820 case SIGINT:
821 case SIGTERM:
822 {
824 DCTL_SHUTDOWN_SIGNAL_RECVD).arg(signum);
825 ElementPtr arg_set;
826 shutdownHandler(SHUT_DOWN_COMMAND, arg_set);
827 break;
828 }
829
830 default:
832 break;
833 }
834}
835
836void
837DControllerBase::usage(const std::string & text) {
838 if (text != "") {
839 std::cerr << "Usage error: " << text << std::endl;
840 }
841
842 std::cerr << "Usage: " << bin_name_ << std::endl
843 << " -v: print version number and exit" << std::endl
844 << " -V: print extended version information and exit"
845 << std::endl
846 << " -W: display the configuration report and exit"
847 << std::endl
848 << " -d: optional, verbose output " << std::endl
849 << " -c <config file name> : mandatory,"
850 << " specify name of configuration file" << std::endl
851 << " -t <config file name> : check the"
852 << " configuration file and exit" << std::endl
853 << " -X: disables security restrictions" << std::endl;
854
855 // add any derivation specific usage
856 std::cerr << getUsageText() << std::endl;
857}
858
860 // Explicitly unload hooks
863 auto names = HooksManager::getLibraryNames();
864 std::string msg;
865 if (!names.empty()) {
866 msg = names[0];
867 for (size_t i = 1; i < names.size(); ++i) {
868 msg += std::string(", ") + names[i];
869 }
870 }
872 }
873
875
876 io_signal_set_.reset();
877 try {
878 getIOService()->poll();
879 } catch (...) {
880 // Don't want to throw exceptions from the destructor. The process
881 // is shutting down anyway.
882 }
883}
884
885std::string
887 std::stringstream tmp;
888
889 tmp << VERSION;
890 if (extended) {
891 tmp << " (" << SOURCE_OF_INSTALLATION << ")" << std::endl;
892 tmp << "premium: " << PREMIUM_EXTENDED_VERSION << std::endl;
893 tmp << "linked with:" << std::endl;
894 tmp << "- " << isc::log::Logger::getVersion() << std::endl;
896 }
897
898 return (tmp.str());
899}
900
901} // end of namespace isc::process
902
903} // end of namespace isc
static ElementPtr create(const Position &pos=ZERO_POSITION())
Create a NullElement.
Definition data.cc:299
@ 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:877
static ElementPtr createMap(const Position &pos=ZERO_POSITION())
Creates an empty MapElement type ElementPtr.
Definition data.cc:354
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:107
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:269
static void setVerbose(const bool verbose)
Sets or clears verbose mode.
Definition daemon.cc:82
static void configureLogger(const isc::data::ConstElementPtr &log_config, const isc::process::ConfigPtr &storage)
Configures logger.
Definition daemon.cc:69
boost::posix_time::ptime start_
Timestamp of the start of the daemon.
Definition daemon.h:278
static void loggerInit(const char *log_name, bool verbose)
Initializes logger.
Definition daemon.cc:91
void checkWriteConfigFile(std::string &file)
Checks the to-be-written configuration file name.
Definition daemon.cc:132
void setExitValue(int value)
Sets the exit value.
Definition daemon.h:242
void checkConfigFile() const
Checks the configuration file name.
Definition daemon.cc:117
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:159
int getExitValue()
Fetches the exit value.
Definition daemon.h:235
void createPIDFile(int pid=0)
Creates the PID file.
Definition daemon.cc:236
void setConfigFile(const std::string &config_file)
Sets the configuration file name.
Definition daemon.cc:112
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_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.