d_controller.h 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526
  1. // Copyright (C) 2013-2015 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #ifndef D_CONTROLLER_H
  15. #define D_CONTROLLER_H
  16. #include <asiolink/io_service.h>
  17. #include <cc/data.h>
  18. #include <d2/d2_log.h>
  19. #include <d2/d_process.h>
  20. #include <d2/io_service_signal.h>
  21. #include <dhcpsrv/daemon.h>
  22. #include <exceptions/exceptions.h>
  23. #include <log/logger_support.h>
  24. #include <util/signal_set.h>
  25. #include <boost/shared_ptr.hpp>
  26. #include <boost/noncopyable.hpp>
  27. namespace isc {
  28. namespace d2 {
  29. /// @brief Exception thrown when the command line is invalid.
  30. class InvalidUsage : public isc::Exception {
  31. public:
  32. InvalidUsage(const char* file, size_t line, const char* what) :
  33. isc::Exception(file, line, what) { };
  34. };
  35. /// @brief Exception used to convey version info upwards.
  36. /// Since command line argument parsing is done as part of
  37. /// DControllerBase::launch(), it uses this exception to propagate
  38. /// version information up to main(), when command line argument
  39. /// -v or -V is given.
  40. class VersionMessage : public isc::Exception {
  41. public:
  42. VersionMessage(const char* file, size_t line, const char* what) :
  43. isc::Exception(file, line, what) { };
  44. };
  45. /// @brief Exception thrown when the controller launch fails.
  46. class LaunchError: public isc::Exception {
  47. public:
  48. LaunchError (const char* file, size_t line, const char* what) :
  49. isc::Exception(file, line, what) { };
  50. };
  51. /// @brief Exception thrown when the application process fails.
  52. class ProcessInitError: public isc::Exception {
  53. public:
  54. ProcessInitError (const char* file, size_t line, const char* what) :
  55. isc::Exception(file, line, what) { };
  56. };
  57. /// @brief Exception thrown when the application process encounters an
  58. /// operation in its event loop (i.e. run method).
  59. class ProcessRunError: public isc::Exception {
  60. public:
  61. ProcessRunError (const char* file, size_t line, const char* what) :
  62. isc::Exception(file, line, what) { };
  63. };
  64. /// @brief Exception thrown when the controller encounters an operational error.
  65. class DControllerBaseError : public isc::Exception {
  66. public:
  67. DControllerBaseError (const char* file, size_t line, const char* what) :
  68. isc::Exception(file, line, what) { };
  69. };
  70. /// @brief Defines a shared pointer to DControllerBase.
  71. class DControllerBase;
  72. typedef boost::shared_ptr<DControllerBase> DControllerBasePtr;
  73. /// @brief Application Controller
  74. ///
  75. /// DControllerBase is an abstract singleton which provides the framework and
  76. /// services for managing an application process that implements the
  77. /// DProcessBase interface. It runs the process like a stand-alone, command
  78. /// line driven executable, which must be supplied a configuration file at
  79. /// startup. It coordinates command line argument parsing, process
  80. /// instantiation and initialization, and runtime control through external
  81. /// command and configuration event handling.
  82. /// It creates the IOService instance which is used for runtime control
  83. /// events and passes the IOService into the application process at process
  84. /// creation.
  85. /// It provides the callback handlers for command and configuration events
  86. /// which could be triggered by an external source. Such sources are intended
  87. /// to be registered with and monitored by the controller's IOService such that
  88. /// the appropriate handler can be invoked.
  89. ///
  90. /// DControllerBase provides dynamic configuration file reloading upon receipt
  91. /// of SIGHUP, and graceful shutdown upon receipt of either SIGINT or SIGTERM.
  92. ///
  93. /// NOTE: Derivations must supply their own static singleton instance method(s)
  94. /// for creating and fetching the instance. The base class declares the instance
  95. /// member in order for it to be available for static callback functions.
  96. class DControllerBase : public dhcp::Daemon {
  97. public:
  98. /// @brief Constructor
  99. ///
  100. /// @param app_name is display name of the application under control. This
  101. /// name appears in log statements.
  102. /// @param bin_name is the name of the application executable.
  103. DControllerBase(const char* app_name, const char* bin_name);
  104. /// @brief Destructor
  105. virtual ~DControllerBase();
  106. /// @brief returns Kea version on stdout and exit.
  107. /// redeclaration/redefinition. @ref Daemon::getVersion()
  108. static std::string getVersion(bool extended);
  109. /// @brief Acts as the primary entry point into the controller execution
  110. /// and provides the outermost application control logic:
  111. ///
  112. /// 1. parse command line arguments
  113. /// 2. instantiate and initialize the application process
  114. /// 3. load the configuration file
  115. /// 4. initialize signal handling
  116. /// 5. start and wait on the application process event loop
  117. /// 6. exit to the caller
  118. ///
  119. /// It is intended to be called from main() and be given the command line
  120. /// arguments.
  121. ///
  122. /// This function can be run in "test mode". It prevents initialization
  123. /// of D2 module logger. This is used in unit tests which initialize logger
  124. /// in their main function. Such a logger uses environmental variables to
  125. /// control severity, verbosity etc.
  126. ///
  127. /// @param argc is the number of command line arguments supplied
  128. /// @param argv is the array of string (char *) command line arguments
  129. /// @param test_mode is a bool value which indicates if
  130. /// @c DControllerBase::launch should be run in the test mode (if true).
  131. /// This parameter doesn't have default value to force test implementers to
  132. /// enable test mode explicitly.
  133. ///
  134. /// @throw throws one of the following exceptions:
  135. /// InvalidUsage - Indicates invalid command line.
  136. /// ProcessInitError - Failed to create and initialize application
  137. /// process object.
  138. /// ProcessRunError - A fatal error occurred while in the application
  139. /// process event loop.
  140. virtual void launch(int argc, char* argv[], const bool test_mode);
  141. /// @brief Instance method invoked by the configuration event handler and
  142. /// which processes the actual configuration update. Provides behavioral
  143. /// path for both integrated and stand-alone modes. The current
  144. /// implementation will merge the configuration update into the existing
  145. /// configuration and then invoke the application process' configure method.
  146. ///
  147. /// @param new_config is the new configuration
  148. ///
  149. /// @return returns an Element that contains the results of configuration
  150. /// update composed of an integer status value (0 means successful,
  151. /// non-zero means failure), and a string explanation of the outcome.
  152. virtual isc::data::ConstElementPtr updateConfig(isc::data::ConstElementPtr
  153. new_config);
  154. /// @brief Reconfigures the process from a configuration file
  155. ///
  156. /// By default the file is assumed to be a JSON text file whose contents
  157. /// include at least:
  158. ///
  159. /// @code
  160. /// { "<module-name>": {<module-config>} }
  161. ///
  162. /// where:
  163. /// module-name : is a label which uniquely identifies the
  164. /// configuration data for this controller's application
  165. ///
  166. /// module-config: a set of zero or more JSON elements which comprise
  167. /// the application's configuration values
  168. /// @endcode
  169. ///
  170. /// The method extracts the set of configuration elements for the
  171. /// module-name which matches the controller's app_name_ and passes that
  172. /// set into @c udpateConfig().
  173. ///
  174. /// The file may contain an arbitrary number of other modules.
  175. ///
  176. /// @return returns an Element that contains the results of configuration
  177. /// update composed of an integer status value (0 means successful,
  178. /// non-zero means failure), and a string explanation of the outcome.
  179. virtual isc::data::ConstElementPtr configFromFile();
  180. /// @brief Instance method invoked by the command event handler and which
  181. /// processes the actual command directive.
  182. ///
  183. /// It supports the execution of:
  184. ///
  185. /// 1. Stock controller commands - commands common to all DControllerBase
  186. /// derivations. Currently there is only one, the shutdown command.
  187. ///
  188. /// 2. Custom controller commands - commands that the deriving controller
  189. /// class implements. These commands are executed by the deriving
  190. /// controller.
  191. ///
  192. /// 3. Custom application commands - commands supported by the application
  193. /// process implementation. These commands are executed by the application
  194. /// process.
  195. ///
  196. /// @param command is a string label representing the command to execute.
  197. /// @param args is a set of arguments (if any) required for the given
  198. /// command.
  199. ///
  200. /// @return an Element that contains the results of command composed
  201. /// of an integer status value and a string explanation of the outcome.
  202. /// The status value is one of the following:
  203. /// D2::COMMAND_SUCCESS - Command executed successfully
  204. /// D2::COMMAND_ERROR - Command is valid but suffered an operational
  205. /// failure.
  206. /// D2::COMMAND_INVALID - Command is not recognized as valid be either
  207. /// the controller or the application process.
  208. virtual isc::data::ConstElementPtr executeCommand(const std::string&
  209. command,
  210. isc::data::
  211. ConstElementPtr args);
  212. /// @brief Fetches the name of the application under control.
  213. ///
  214. /// @return returns the controller service name string
  215. std::string getAppName() const {
  216. return (app_name_);
  217. }
  218. /// @brief Fetches the name of the application executable.
  219. ///
  220. /// @return returns the controller logger name string
  221. std::string getBinName() const {
  222. return (bin_name_);
  223. }
  224. protected:
  225. /// @brief Virtual method that provides derivations the opportunity to
  226. /// support additional command line options. It is invoked during command
  227. /// line argument parsing (see parseArgs method) if the option is not
  228. /// recognized as a stock DControllerBase option.
  229. ///
  230. /// @param option is the option "character" from the command line, without
  231. /// any prefixing hyphen(s)
  232. /// @param optarg is the argument value (if one) associated with the option
  233. ///
  234. /// @return must return true if the option was valid, false if it is
  235. /// invalid. (Note the default implementation always returns false.)
  236. virtual bool customOption(int option, char *optarg);
  237. /// @brief Abstract method that is responsible for instantiating the
  238. /// application process object. It is invoked by the controller after
  239. /// command line argument parsing as part of the process initialization
  240. /// (see initProcess method).
  241. ///
  242. /// @return returns a pointer to the new process object (DProcessBase*)
  243. /// or NULL if the create fails.
  244. /// Note this value is subsequently wrapped in a smart pointer.
  245. virtual DProcessBase* createProcess() = 0;
  246. /// @brief Virtual method that provides derivations the opportunity to
  247. /// support custom external commands executed by the controller. This
  248. /// method is invoked by the processCommand if the received command is
  249. /// not a stock controller command.
  250. ///
  251. /// @param command is a string label representing the command to execute.
  252. /// @param args is a set of arguments (if any) required for the given
  253. /// command.
  254. ///
  255. /// @return an Element that contains the results of command composed
  256. /// of an integer status value and a string explanation of the outcome.
  257. /// The status value is one of the following:
  258. /// D2::COMMAND_SUCCESS - Command executed successfully
  259. /// D2::COMMAND_ERROR - Command is valid but suffered an operational
  260. /// failure.
  261. /// D2::COMMAND_INVALID - Command is not recognized as a valid custom
  262. /// controller command.
  263. virtual isc::data::ConstElementPtr customControllerCommand(
  264. const std::string& command, isc::data::ConstElementPtr args);
  265. /// @brief Virtual method which can be used to contribute derivation
  266. /// specific usage text. It is invoked by the usage() method under
  267. /// invalid usage conditions.
  268. ///
  269. /// @return returns the desired text.
  270. virtual const std::string getUsageText() const {
  271. return ("");
  272. }
  273. /// @brief Virtual method which returns a string containing the option
  274. /// letters for any custom command line options supported by the derivation.
  275. /// These are added to the stock options of "c" and "v" during command
  276. /// line interpretation.
  277. ///
  278. /// @return returns a string containing the custom option letters.
  279. virtual const std::string getCustomOpts() const {
  280. return ("");
  281. }
  282. /// @brief Application-level signal processing method.
  283. ///
  284. /// This method is the last step in processing a OS signal occurrence. It
  285. /// is invoked when an IOSignal's internal timer callback is executed by
  286. /// IOService. It currently supports the following signals as follows:
  287. /// -# SIGHUP - instigates reloading the configuration file
  288. /// -# SIGINT - instigates a graceful shutdown
  289. /// -# SIGTERM - instigates a graceful shutdown
  290. /// If it receives any other signal, it will issue a debug statement and
  291. /// discard it.
  292. /// Derivations wishing to support additional signals could override this
  293. /// method with one that: processes the signal if it is one of additional
  294. /// signals, otherwise invoke this method (DControllerBase::processSignal())
  295. /// with the signal value.
  296. /// @todo Provide a convenient way for derivations to register additional
  297. /// signals.
  298. virtual void processSignal(int signum);
  299. /// @brief Supplies whether or not verbose logging is enabled.
  300. ///
  301. /// @return returns true if verbose logging is enabled.
  302. bool isVerbose() const {
  303. return (verbose_);
  304. }
  305. /// @brief Method for enabling or disabling verbose logging.
  306. ///
  307. /// @param value is the new value to assign the flag.
  308. void setVerbose(bool value) {
  309. verbose_ = value;
  310. }
  311. /// @brief Getter for fetching the controller's IOService
  312. ///
  313. /// @return returns a pointer reference to the IOService.
  314. asiolink::IOServicePtr& getIOService() {
  315. return (io_service_);
  316. }
  317. /// @brief Getter for fetching the name of the controller's config spec
  318. /// file.
  319. ///
  320. /// @return returns the file name string.
  321. const std::string getSpecFileName() const {
  322. return (spec_file_name_);
  323. }
  324. /// @brief Setter for setting the name of the controller's config spec file.
  325. ///
  326. /// @param spec_file_name the file name string.
  327. void setSpecFileName(const std::string& spec_file_name) {
  328. spec_file_name_ = spec_file_name;
  329. }
  330. /// @brief Static getter which returns the singleton instance.
  331. ///
  332. /// @return returns a pointer reference to the private singleton instance
  333. /// member.
  334. static DControllerBasePtr& getController() {
  335. return (controller_);
  336. }
  337. /// @brief Static setter which sets the singleton instance.
  338. ///
  339. /// @param controller is a pointer to the singleton instance.
  340. ///
  341. /// @throw throws DControllerBase error if an attempt is made to set the
  342. /// instance a second time.
  343. static void setController(const DControllerBasePtr& controller);
  344. /// @brief Processes the command line arguments. It is the first step
  345. /// taken after the controller has been launched. It combines the stock
  346. /// list of options with those returned by getCustomOpts(), and uses
  347. /// cstdlib's getopt to loop through the command line.
  348. /// It handles stock options directly, and passes any custom options into
  349. /// the customOption method. Currently there are only two stock options
  350. /// -c for specifying the configuration file, and -v for verbose logging.
  351. ///
  352. /// @param argc is the number of command line arguments supplied
  353. /// @param argv is the array of string (char *) command line arguments
  354. ///
  355. /// @throw InvalidUsage when there are usage errors.
  356. /// @throw VersionMessage if the -v or -V arguments is given.
  357. void parseArgs(int argc, char* argv[]);
  358. /// @brief Instantiates the application process and then initializes it.
  359. /// This is the second step taken during launch, following successful
  360. /// command line parsing. It is used to invoke the derivation-specific
  361. /// implementation of createProcess, following by an invoking of the
  362. /// newly instantiated process's init method.
  363. ///
  364. /// @throw throws DControllerBaseError or indirectly DProcessBaseError
  365. /// if there is a failure creating or initializing the application process.
  366. void initProcess();
  367. /// @brief Invokes the application process's event loop,(DBaseProcess::run).
  368. /// It is called during launch only after successfully completing the
  369. /// requested setup: command line parsing, application initialization,
  370. /// and session establishment (if not stand-alone).
  371. /// The process event loop is expected to only return upon application
  372. /// shutdown either in response to the shutdown command or due to an
  373. /// unrecoverable error.
  374. ///
  375. // @throw throws DControllerBaseError or indirectly DProcessBaseError
  376. void runProcess();
  377. /// @brief Initiates shutdown procedure. This method is invoked
  378. /// by executeCommand in response to the shutdown command. It will invoke
  379. /// the application process's shutdown method which causes the process to
  380. /// to begin its shutdown process.
  381. ///
  382. /// Note, it is assumed that the process of shutting down is neither
  383. /// instantaneous nor synchronous. This method does not "block" waiting
  384. /// until the process has halted. Rather it is used to convey the
  385. /// need to shutdown. A successful return indicates that the shutdown
  386. /// has successfully commenced, but does not indicate that the process
  387. /// has actually exited.
  388. ///
  389. /// @return returns an Element that contains the results of shutdown
  390. /// command composed of an integer status value (0 means successful,
  391. /// non-zero means failure), and a string explanation of the outcome.
  392. ///
  393. /// @param args is a set of derivation-specific arguments (if any)
  394. /// for the shutdown command.
  395. isc::data::ConstElementPtr shutdownProcess(isc::data::ConstElementPtr args);
  396. /// @brief Initializes signal handling
  397. ///
  398. /// This method configures the controller to catch and handle signals.
  399. /// It instantiates an IOSignalQueue, registers @c osSignalHandler() as
  400. /// the SignalSet "on-receipt" handler, and lastly instantiates a SignalSet
  401. /// which listens for SIGHUP, SIGINT, and SIGTERM.
  402. void initSignalHandling();
  403. /// @brief Handler for processing OS-level signals
  404. ///
  405. /// This method is installed as the SignalSet "on-receipt" handler. Upon
  406. /// invocation, it uses the controller's IOSignalQueue to schedule an
  407. /// IOSignal with for the given signal value.
  408. ///
  409. /// @param signum OS signal value (e.g. SIGINT, SIGUSR1 ...) to received
  410. ///
  411. /// @return SignalSet "on-receipt" handlers are required to return a
  412. /// boolean indicating if the OS signal has been processed (true) or if it
  413. /// should be saved for deferred processing (false). Currently this
  414. /// method processes all received signals, so it always returns true.
  415. bool osSignalHandler(int signum);
  416. /// @brief Handler for processing IOSignals
  417. ///
  418. /// This method is supplied as the callback when IOSignals are scheduled.
  419. /// It fetches the IOSignal for the given sequence_id and then invokes
  420. /// the virtual method, @c processSignal() passing it the signal value
  421. /// obtained from the IOSignal. This allows derivations to supply a
  422. /// custom signal processing method, while ensuring IOSignalQueue
  423. /// integrity.
  424. ///
  425. /// @param sequence_id id of the IOSignal instance "received"
  426. void ioSignalHandler(IOSignalId sequence_id);
  427. /// @brief Fetches the current process
  428. ///
  429. /// @return a pointer to the current process instance.
  430. DProcessBasePtr getProcess() {
  431. return (process_);
  432. }
  433. /// @brief Prints the program usage text to std error.
  434. ///
  435. /// @param text is a string message which will preceded the usage text.
  436. /// This is intended to be used for specific usage violation messages.
  437. void usage(const std::string& text);
  438. private:
  439. /// @brief Name of the service under control.
  440. /// This name is used as the configuration module name and appears in log
  441. /// statements.
  442. std::string app_name_;
  443. /// @brief Name of the service executable.
  444. /// By convention this matches the executable name. It is also used to
  445. /// establish the logger name.
  446. std::string bin_name_;
  447. /// @brief Indicates if the verbose logging mode is enabled.
  448. bool verbose_;
  449. /// @brief The absolute file name of the JSON spec file.
  450. std::string spec_file_name_;
  451. /// @brief Pointer to the instance of the process.
  452. ///
  453. /// This is required for config and command handlers to gain access to
  454. /// the process
  455. DProcessBasePtr process_;
  456. /// @brief Shared pointer to an IOService object, used for ASIO operations.
  457. asiolink::IOServicePtr io_service_;
  458. /// @brief Set of registered signals to handle.
  459. util::SignalSetPtr signal_set_;
  460. /// @brief Queue for propagating caught signals to the IOService.
  461. IOSignalQueuePtr io_signal_queue_;
  462. /// @brief Singleton instance value.
  463. static DControllerBasePtr controller_;
  464. // DControllerTest is named a friend class to facilitate unit testing while
  465. // leaving the intended member scopes intact.
  466. friend class DControllerTest;
  467. };
  468. }; // namespace isc::d2
  469. }; // namespace isc
  470. #endif