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