Kea: d_controller.cc Source File

| Kea 2.2.0

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