Kea 3.1.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
131 // When it is not a stable version dissuade use in production.
132 if (std::string(PACKAGE_VERSION_TYPE) == "development") {
134 }
135
136 if (file::amRunningAsRoot()) {
138 .arg(app_name_);
139 }
140
141 try {
142 // Step 2 is to create and initialize the application process object.
143 initProcess();
144 } catch (const std::exception& ex) {
146 .arg(app_name_).arg(ex.what());
148 "Application Process initialization failed: " << ex.what());
149 }
150
152 .arg(app_name_);
153
154 // Step 3 is to load configuration from file.
155 int rcode;
156 ConstElementPtr comment = parseAnswer(rcode, configFromFile());
157 if (rcode != 0) {
159 .arg(app_name_).arg(comment->stringValue());
160 isc_throw(ProcessInitError, "Could Not load configuration file: "
161 << comment->stringValue());
162 }
163
164 // Note that the controller was started.
165 start_ = boost::posix_time::second_clock::universal_time();
166
167 // Everything is clear for launch, so start the application's
168 // event loop.
169 try {
170 // Now that we have a process, we can set up signal handling.
172 runProcess();
173 } catch (const std::exception& ex) {
175 .arg(app_name_).arg(ex.what());
177 "Application process event loop failed: " << ex.what());
178 }
179
180 // All done, so bail out.
182 .arg(app_name_).arg(getpid()).arg(VERSION);
183
184 return (getExitValue());
185}
186
187void
189 try {
190 // We need to initialize logging, in case any error
191 // messages are to be printed.
192 // This is just a test, so we don't care about lockfile.
193 setenv("KEA_LOCKFILE_DIR", "none", 0);
195 Daemon::setVerbose(verbose_);
196 Daemon::loggerInit(bin_name_.c_str(), verbose_);
197
198 // Check the syntax first.
199 std::string config_file = getConfigFile();
200 if (config_file.empty()) {
201 // Basic sanity check: file name must not be empty.
202 isc_throw(InvalidUsage, "JSON configuration file not specified");
203 }
204 ConstElementPtr whole_config = parseFile(config_file);
205 if (!whole_config) {
206 // No fallback to fromJSONFile
207 isc_throw(InvalidUsage, "No configuration found");
208 }
209 if (verbose_) {
210 std::cerr << "Syntax check OK" << std::endl;
211 }
212
213 // Check the logic next.
214 ConstElementPtr module_config;
215 module_config = whole_config->get(getAppName());
216 if (!module_config) {
217 isc_throw(InvalidUsage, "Config file " << config_file <<
218 " does not include '" << getAppName() << "' entry");
219 }
220 if (module_config->getType() != Element::map) {
221 isc_throw(InvalidUsage, "Config file " << config_file <<
222 " includes not map '" << getAppName() << "' entry");
223 }
224
225 // Handle other (i.e. not application name) objects.
226 std::string errmsg = handleOtherObjects(whole_config);
227 if (!errmsg.empty()) {
228 isc_throw(InvalidUsage, "Config file " << config_file << errmsg);
229 }
230
231 // Get an application process object.
232 initProcess();
233
234 ConstElementPtr answer = checkConfig(module_config);
235 int rcode = 0;
236 answer = parseAnswer(rcode, answer);
237 if (rcode != 0) {
238 isc_throw(InvalidUsage, "Error encountered: "
239 << answer->stringValue());
240 }
241 } catch (const VersionMessage&) {
242 throw;
243 } catch (const InvalidUsage&) {
244 throw;
245 } catch (const std::exception& ex) {
246 isc_throw(InvalidUsage, "Syntax check failed with: " << ex.what());
247 }
248 return;
249}
250
251void
252DControllerBase::parseArgs(int argc, char* argv[]) {
253
254 if (argc == 1) {
256 }
257
258 // Iterate over the given command line options. If its a stock option
259 // ("c" or "d") handle it here. If its a valid custom option, then
260 // invoke customOption.
261 int ch;
262 optarg = 0;
263 opterr = 0;
264 optind = 1;
265 std::string opts("dvVWc:t:X" + getCustomOpts());
266
267 // Defer exhausting of arguments to the end.
268 ExhaustOptions e(argc, argv, opts);
269
270 while ((ch = getopt(argc, argv, opts.c_str())) != -1) {
271 switch (ch) {
272 case 'd':
273 // Enables verbose logging.
274 verbose_ = true;
275 break;
276
277 case 'v':
278 // gather Kea version and throw so main() can catch and return
279 // rather than calling exit() here which disrupts gtest.
281 break;
282
283 case 'V':
284 // gather Kea version and throw so main() can catch and return
285 // rather than calling exit() here which disrupts gtest.
287 break;
288
289 case 'W':
290 // gather Kea config report and throw so main() can catch and
291 // return rather than calling exit() here which disrupts gtest.
293 break;
294
295 case 'c':
296 case 't':
297 // config file name
298 if (optarg == NULL) {
299 isc_throw(InvalidUsage, "configuration file name missing");
300 }
301
302 setConfigFile(optarg);
303
304 if (ch == 't') {
305 check_only_ = true;
306 }
307 break;
308
309 case 'X': // relax security checks
311 break;
312
313 case '?': {
314 char const saved_optopt(optopt);
315 std::string const saved_optarg(optarg ? optarg : std::string());
316
317 // We hit an invalid option.
318 isc_throw(InvalidUsage, "unsupported option: -" << saved_optopt <<
319 (saved_optarg.empty() ? std::string() : " " + saved_optarg));
320
321 break;
322 }
323
324 default:
325 // We hit a valid custom option
326 if (!customOption(ch, optarg)) {
327 char const saved_optopt(optopt);
328 std::string const saved_optarg(optarg ? optarg : std::string());
329
330 // We hit an invalid option.
331 isc_throw(InvalidUsage, "unsupported option: -" << saved_optopt <<
332 (saved_optarg.empty() ? std::string() : " " + saved_optarg));
333 }
334 break;
335 }
336 }
337
338 // There was too much information on the command line.
339 if (argc > optind) {
340 isc_throw(InvalidUsage, "extraneous command line information");
341 }
342}
343
344bool
345DControllerBase::customOption(int /* option */, char* /*optarg*/) {
346 // Default implementation returns false.
347 return (false);
348}
349
350void
353 .arg(app_name_);
354
355 // Invoke virtual method to instantiate the application process.
356 try {
357 process_.reset(createProcess());
358 } catch (const std::exception& ex) {
359 isc_throw(DControllerBaseError, std::string("createProcess failed: ") +
360 ex.what());
361 }
362
363 // This is pretty unlikely, but will test for it just to be safe..
364 if (!process_) {
365 isc_throw(DControllerBaseError, "createProcess returned NULL");
366 }
367
368 // Invoke application's init method (Note this call should throw
369 // DProcessBaseError if it fails).
370 process_->init();
371}
372
375 // Rollback any previous staging configuration. For D2, only a
376 // logger configuration is used here.
377 // We're not using cfgmgr to store logging configuration anymore.
378 // isc::dhcp::CfgMgr::instance().rollback();
379
380 // Will hold configuration.
381 ConstElementPtr module_config;
382 // Will receive configuration result.
383 ConstElementPtr answer;
384 try {
385 std::string config_file = getConfigFile();
386 if (config_file.empty()) {
387 // Basic sanity check: file name must not be empty.
388 isc_throw(BadValue, "JSON configuration file not specified. Please "
389 "use -c command line option.");
390 }
391
392 // If parseFile returns an empty pointer, then pass the file onto the
393 // original JSON parser.
394 ConstElementPtr whole_config = parseFile(config_file);
395 if (!whole_config) {
396 // Read contents of the file and parse it as JSON
397 whole_config = Element::fromJSONFile(config_file, true);
398 }
399
400 // Extract derivation-specific portion of the configuration.
401 module_config = whole_config->get(getAppName());
402 if (!module_config) {
403 isc_throw(BadValue, "Config file " << config_file <<
404 " does not include '" <<
405 getAppName() << "' entry.");
406 }
407 if (module_config->getType() != Element::map) {
408 isc_throw(InvalidUsage, "Config file " << config_file <<
409 " includes not map '" << getAppName() << "' entry");
410 }
411
412 // Handle other (i.e. not application name) objects.
413 std::string errmsg = handleOtherObjects(whole_config);
414 if (!errmsg.empty()) {
415 isc_throw(InvalidUsage, "Config file " << config_file << errmsg);
416 }
417
418 // Let's configure logging before applying the configuration,
419 // so we can log things during configuration process.
420
421 // Temporary storage for logging configuration
422 ConfigPtr storage(new ConfigBase());
423
424 // Configure logging to the temporary storage.
425 Daemon::configureLogger(module_config, storage);
426
427 // Let's apply the new logging. We do it early, so we'll be able
428 // to print out what exactly is wrong with the new config in
429 // case of problems.
430 storage->applyLoggingCfg();
431
432 answer = updateConfig(module_config);
433 // In all cases the right logging configuration is in the context.
434 process_->getCfgMgr()->getContext()->applyLoggingCfg();
435 } catch (const std::exception& ex) {
436 // Rollback logging configuration.
437 process_->getCfgMgr()->getContext()->applyLoggingCfg();
438
439 // build an error result
441 std::string("Configuration parsing failed: ") + ex.what());
442 return (error);
443 }
444
445 return (answer);
446}
447
448void
451 .arg(app_name_);
452 if (!process_) {
453 // This should not be possible.
454 isc_throw(DControllerBaseError, "Process not initialized");
455 }
456
457 // Invoke the application process's run method. This may throw
458 // DProcessBaseError
459 process_->run();
460}
461
462// Instance method for handling new config
465 return (process_->configure(new_config, false));
466}
467
468// Instance method for checking new config
471 return (process_->configure(new_config, true));
472}
473
476 ConstElementPtr /*args*/) {
477 ElementPtr config = process_->getCfgMgr()->getContext()->toElement();
478 std::string hash = BaseCommandMgr::getHash(config);
479 config->set("hash", Element::create(hash));
480
482}
483
486 ConstElementPtr /*args*/) {
487 ConstElementPtr config = process_->getCfgMgr()->getContext()->toElement();
488 std::string hash = BaseCommandMgr::getHash(config);
490 params->set("hash", Element::create(hash));
491 return (createAnswer(CONTROL_RESULT_SUCCESS, params));
492}
493
496 ConstElementPtr args) {
497 std::string filename;
498
499 if (args) {
500 if (args->getType() != Element::map) {
501 return (createAnswer(CONTROL_RESULT_ERROR, "Argument must be a map"));
502 }
503 ConstElementPtr filename_param = args->get("filename");
504 if (filename_param) {
505 if (filename_param->getType() != Element::string) {
507 "passed parameter 'filename' "
508 "is not a string"));
509 }
510 filename = filename_param->stringValue();
511 }
512 }
513
514 if (filename.empty()) {
515 // filename parameter was not specified, so let's use
516 // whatever we remember
517 filename = getConfigFile();
518 if (filename.empty()) {
520 "Unable to determine filename."
521 "Please specify filename explicitly."));
522 }
523 } else {
524 try {
525 checkWriteConfigFile(filename);
526 } catch (const isc::Exception& ex) {
527 std::ostringstream msg;
528 msg << "not allowed to write config into " << filename
529 << ": " << ex.what();
530 return (createAnswer(CONTROL_RESULT_ERROR, msg.str()));
531 }
532 }
533
534 // Ok, it's time to write the file.
535 size_t size = 0;
536
537 try {
538 ElementPtr cfg = process_->getCfgMgr()->getContext()->toElement();
539 size = writeConfigFile(filename, cfg);
540 } catch (const isc::Exception& ex) {
542 std::string("Error during config-write:")
543 + ex.what()));
544 }
545 if (size == 0) {
547 "Error writing configuration to " + filename));
548 }
549
550 // Ok, it's time to return the successful response.
552 params->set("size", Element::create(static_cast<long long>(size)));
553 params->set("filename", Element::create(filename));
554
555 return (createAnswer(CONTROL_RESULT_SUCCESS, "Configuration written to "
556 + filename + " successful", params));
557}
558
559std::string
561 // Check obsolete or unknown (aka unsupported) objects.
562 const std::string& app_name = getAppName();
563 std::string errmsg;
564 for (auto const& obj : args->mapValue()) {
565 const std::string& obj_name = obj.first;
566 if (obj_name == app_name) {
567 continue;
568 }
570 .arg("'" + obj_name + "', defining anything in global level besides '"
571 + app_name + "' is no longer supported.");
572 if (errmsg.empty()) {
573 errmsg = " contains unsupported '" + obj_name + "' parameter";
574 } else {
575 errmsg += " (and '" + obj_name + "')";
576 }
577 }
578 return (errmsg);
579}
580
583 const int status_code = CONTROL_RESULT_ERROR; // 1 indicates an error
584 ConstElementPtr module_config;
585 std::string app_name = getAppName();
586 std::string message;
587
588 // Command arguments are expected to be:
589 // { "Module": { ... } }
590 if (!args) {
591 message = "Missing mandatory 'arguments' parameter.";
592 } else {
593 module_config = args->get(app_name);
594 if (!module_config) {
595 message = "Missing mandatory '" + app_name + "' parameter.";
596 } else if (module_config->getType() != Element::map) {
597 message = "'" + app_name + "' parameter expected to be a map.";
598 }
599 }
600
601 if (message.empty()) {
602 // Handle other (i.e. not application name) objects.
603 std::string errmsg = handleOtherObjects(args);
604 if (!errmsg.empty()) {
605 message = "'arguments' parameter" + errmsg;
606 }
607 }
608
609 if (!message.empty()) {
610 // Something is amiss with arguments, return a failure response.
611 ConstElementPtr result = isc::config::createAnswer(status_code,
612 message);
613 return (result);
614 }
615
616 // We are starting the configuration process so we should remove any
617 // staging configuration that has been created during previous
618 // configuration attempts.
619 // We're not using cfgmgr to store logging information anymore.
620 // isc::dhcp::CfgMgr::instance().rollback();
621
622 // Now we check the server proper.
623 return (checkConfig(module_config));
624}
625
628 // Add reload in message?
629 return (configFromFile());
630}
631
634 const int status_code = CONTROL_RESULT_ERROR; // 1 indicates an error
635 ConstElementPtr module_config;
636 std::string app_name = getAppName();
637 std::string message;
638
639 // Command arguments are expected to be:
640 // { "Module": { ... } }
641 if (!args) {
642 message = "Missing mandatory 'arguments' parameter.";
643 } else {
644 module_config = args->get(app_name);
645 if (!module_config) {
646 message = "Missing mandatory '" + app_name + "' parameter.";
647 } else if (module_config->getType() != Element::map) {
648 message = "'" + app_name + "' parameter expected to be a map.";
649 }
650 }
651
652 if (!message.empty()) {
653 // Something is amiss with arguments, return a failure response.
654 ConstElementPtr result = isc::config::createAnswer(status_code,
655 message);
656 return (result);
657 }
658
659 try {
660
661 // Handle other (i.e. not application name) objects.
662 handleOtherObjects(args);
663
664 // We are starting the configuration process so we should remove any
665 // staging configuration that has been created during previous
666 // configuration attempts.
667 // We're not using cfgmgr to store logging information anymore.
668 // isc::dhcp::CfgMgr::instance().rollback();
669
670 // Temporary storage for logging configuration
671 ConfigPtr storage(new ConfigBase());
672
673 // Configure logging to the temporary storage.
674 Daemon::configureLogger(module_config, storage);
675
676 // Let's apply the new logging. We do it early, so we'll be able
677 // to print out what exactly is wrong with the new config in
678 // case of problems.
679 storage->applyLoggingCfg();
680
681 ConstElementPtr answer = updateConfig(module_config);
682 int rcode = 0;
683 parseAnswer(rcode, answer);
684 // In all cases the right logging configuration is in the context.
685 process_->getCfgMgr()->getContext()->applyLoggingCfg();
686 return (answer);
687 } catch (const std::exception& ex) {
688 // Rollback logging configuration.
689 process_->getCfgMgr()->getContext()->applyLoggingCfg();
690
691 // build an error result
693 std::string("Configuration parsing failed: ") + ex.what());
694 return (error);
695 }
696}
697
700 const std::string& tag = process_->getCfgMgr()->getContext()->getServerTag();
701 ElementPtr response = Element::createMap();
702 response->set("server-tag", Element::create(tag));
703
704 return (createAnswer(CONTROL_RESULT_SUCCESS, response));
705}
706
710 status->set("pid", Element::create(static_cast<int>(getpid())));
711
712 auto now = boost::posix_time::second_clock::universal_time();
713 if (!start_.is_not_a_date_time()) {
714 auto uptime = now - start_;
715 status->set("uptime", Element::create(uptime.total_seconds()));
716 }
717
718 auto last_commit = process_->getCfgMgr()->getContext()->getLastCommitTime();
719 if (!last_commit.is_not_a_date_time()) {
720 auto reload = now - last_commit;
721 status->set("reload", Element::create(reload.total_seconds()));
722 }
723
724 return (createAnswer(CONTROL_RESULT_SUCCESS, status));
725}
726
729 ConstElementPtr answer;
730
731 // For version-get put the extended version in arguments
732 ElementPtr extended = Element::create(getVersion(true));
733 ElementPtr arguments = Element::createMap();
734 arguments->set("extended", extended);
735 answer = createAnswer(CONTROL_RESULT_SUCCESS, getVersion(false), arguments);
736 return (answer);
737}
738
743
746 // Shutdown is universal. If its not that, then try it as
747 // a custom command supported by the derivation. If that
748 // doesn't pan out either, than send to it the application
749 // as it may be supported there.
750
751 int exit_value = EXIT_SUCCESS;
752 if (args) {
753 // @todo Should we go ahead and shutdown even if the args are invalid?
754 if (args->getType() != Element::map) {
755 return (createAnswer(CONTROL_RESULT_ERROR, "Argument must be a map"));
756 }
757
758 ConstElementPtr param = args->get("exit-value");
759 if (param) {
760 if (param->getType() != Element::integer) {
762 "parameter 'exit-value' is not an integer"));
763 }
764
765 exit_value = param->intValue();
766 }
767 }
768
769 setExitValue(exit_value);
770 return (shutdownProcess(args));
771}
772
775 if (process_) {
776 return (process_->shutdown(args));
777 }
778
779 // Not really a failure, but this condition is worth noting. In reality
780 // it should be pretty hard to cause this.
781 LOG_WARN(dctl_logger, DCTL_NOT_RUNNING).arg(app_name_);
782 return (createAnswer(CONTROL_RESULT_SUCCESS, "Process has not been initialized"));
783}
784
785void
788
789 // Create our signal set.
790 io_signal_set_.reset(new IOSignalSet(io_service_,
791 std::bind(&DControllerBase::
793 this, ph::_1)));
794 // Register for the signals we wish to handle.
795 io_signal_set_->add(SIGHUP);
796 io_signal_set_->add(SIGINT);
797 io_signal_set_->add(SIGTERM);
798}
799
800void
802 switch (signum) {
803 case SIGHUP:
804 {
806 .arg(signum).arg(getConfigFile());
807 int rcode;
808 ConstElementPtr comment = parseAnswer(rcode, configFromFile());
809 if (rcode != 0) {
811 .arg(comment->stringValue());
812 }
813
814 break;
815 }
816
817 case SIGINT:
818 case SIGTERM:
819 {
821 DCTL_SHUTDOWN_SIGNAL_RECVD).arg(signum);
822 ElementPtr arg_set;
823 shutdownHandler(SHUT_DOWN_COMMAND, arg_set);
824 break;
825 }
826
827 default:
829 break;
830 }
831}
832
833void
834DControllerBase::usage(const std::string & text) {
835 if (text != "") {
836 std::cerr << "Usage error: " << text << std::endl;
837 }
838
839 std::cerr << "Usage: " << bin_name_ << std::endl
840 << " -v: print version number and exit" << std::endl
841 << " -V: print extended version information and exit"
842 << std::endl
843 << " -W: display the configuration report and exit"
844 << std::endl
845 << " -d: optional, verbose output " << std::endl
846 << " -c <config file name> : mandatory,"
847 << " specify name of configuration file" << std::endl
848 << " -t <config file name> : check the"
849 << " configuration file and exit" << std::endl
850 << " -X: disables security restrictions" << std::endl;
851
852 // add any derivation specific usage
853 std::cerr << getUsageText() << std::endl;
854}
855
857 // Explicitly unload hooks
860 auto names = HooksManager::getLibraryNames();
861 std::string msg;
862 if (!names.empty()) {
863 msg = names[0];
864 for (size_t i = 1; i < names.size(); ++i) {
865 msg += std::string(", ") + names[i];
866 }
867 }
869 }
870
872
873 io_signal_set_.reset();
874 try {
875 getIOService()->poll();
876 } catch (...) {
877 // Don't want to throw exceptions from the destructor. The process
878 // is shutting down anyway.
879 }
880}
881
882std::string
884 std::stringstream tmp;
885
886 tmp << VERSION;
887 if (extended) {
888 tmp << " (" << EXTENDED_VERSION << ")" << std::endl;
889 tmp << "premium: " << PREMIUM_EXTENDED_VERSION << std::endl;
890 tmp << "linked with:" << std::endl;
891 tmp << "- " << isc::log::Logger::getVersion() << std::endl;
893 }
894
895 return (tmp.str());
896}
897
898} // end of namespace isc::process
899
900} // 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_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.