LCOV - code coverage report
Current view: top level - config - ccsession.h (source / functions) Hit Total Coverage
Test: report.info Lines: 6 8 75.0 %
Date: 2012-05-15 Functions: 3 6 50.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 7 18 38.9 %

           Branch data     Line data    Source code
       1                 :            : // Copyright (C) 2009  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                 :            : 
      15                 :            : #ifndef __CCSESSION_H
      16                 :            : #define __CCSESSION_H 1
      17                 :            : 
      18                 :            : #include <string>
      19                 :            : 
      20                 :            : #include <config/config_data.h>
      21                 :            : #include <config/module_spec.h>
      22                 :            : #include <cc/session.h>
      23                 :            : #include <cc/data.h>
      24                 :            : 
      25                 :            : namespace isc {
      26                 :            : namespace config {
      27                 :            : 
      28                 :            : ///
      29                 :            : /// \brief Creates a standard config/command level success answer message
      30                 :            : ///        (i.e. of the form { "result": [ 0 ] }
      31                 :            : /// \return Standard command/config success answer message
      32                 :            : isc::data::ConstElementPtr createAnswer();
      33                 :            : 
      34                 :            : ///
      35                 :            : /// \brief Creates a standard config/command level answer message
      36                 :            : ///        (i.e. of the form { "result": [ rcode, arg ] }
      37                 :            : /// If rcode != 0, arg must be a StringElement
      38                 :            : ///
      39                 :            : /// \param rcode The return code (0 for success)
      40                 :            : /// \param arg For rcode == 0, this is an optional argument of any
      41                 :            : ///            Element type. For rcode == 1, this argument is mandatory,
      42                 :            : ///            and must be a StringElement containing an error description
      43                 :            : /// \return Standard command/config answer message
      44                 :            : isc::data::ConstElementPtr createAnswer(const int rcode,
      45                 :            :                                         isc::data::ConstElementPtr arg);
      46                 :            : 
      47                 :            : ///
      48                 :            : /// \brief Creates a standard config/command level answer message
      49                 :            : /// (i.e. of the form { "result": [ rcode, arg ] }
      50                 :            : ///
      51                 :            : /// \param rcode The return code (0 for success)
      52                 :            : /// \param arg A string to put into the StringElement argument
      53                 :            : /// \return Standard command/config answer message
      54                 :            : isc::data::ConstElementPtr createAnswer(const int rcode,
      55                 :            :                                         const std::string& arg);
      56                 :            : 
      57                 :            : ///
      58                 :            : /// Parses a standard config/command level answer message
      59                 :            : /// 
      60                 :            : /// \param rcode This value will be set to the return code contained in
      61                 :            : ///              the message
      62                 :            : /// \param msg The message to parse
      63                 :            : /// \return The optional argument in the message, or an empty ElementPtr
      64                 :            : ///         if there was no argument. If rcode != 0, this contains a
      65                 :            : ///         StringElement with the error description.
      66                 :            : isc::data::ConstElementPtr parseAnswer(int &rcode,
      67                 :            :                                        isc::data::ConstElementPtr msg);
      68                 :            : 
      69                 :            : ///
      70                 :            : /// \brief Creates a standard config/command command message with no
      71                 :            : /// argument (of the form { "command": [ "my_command" ] }
      72                 :            : /// 
      73                 :            : /// \param command The command string
      74                 :            : /// \return The created message
      75                 :            : isc::data::ConstElementPtr createCommand(const std::string& command);
      76                 :            : 
      77                 :            : ///
      78                 :            : /// \brief Creates a standard config/command command message with the
      79                 :            : /// given argument (of the form { "command": [ "my_command", arg ] }
      80                 :            : /// 
      81                 :            : /// \param command The command string
      82                 :            : /// \param arg The optional argument for the command. This can be of 
      83                 :            : ///        any Element type, but it should conform to the .spec file.
      84                 :            : /// \return The created message
      85                 :            : isc::data::ConstElementPtr createCommand(const std::string& command,
      86                 :            :                                          isc::data::ConstElementPtr arg);
      87                 :            : 
      88                 :            : ///
      89                 :            : /// \brief Parses the given command into a string containing the actual
      90                 :            : ///        command and an ElementPtr containing the optional argument.
      91                 :            : ///
      92                 :            : /// Raises a CCSessionError if this is not a well-formed command
      93                 :            : ///
      94                 :            : /// Example code: (command_message is a ConstElementPtr that is
      95                 :            : /// passed here)
      96                 :            : /// \code
      97                 :            : /// ElementPtr command_message = Element::fromJSON("{ \"command\": [\"foo\", { \"bar\": 123 } ] }");
      98                 :            : /// try {
      99                 :            : ///     ConstElementPtr args;
     100                 :            : ///     std::string command_str = parseCommand(args, command_message);
     101                 :            : ///     if (command_str == "foo") {
     102                 :            : ///         std::cout << "The command 'foo' was given" << std::endl;
     103                 :            : ///         if (args->contains("bar")) {
     104                 :            : ///             std::cout << "It had argument name 'bar' set, which has"
     105                 :            : ///                       << "value " 
     106                 :            : ///                       << args->get("bar")->intValue();
     107                 :            : ///         }
     108                 :            : ///     } else {
     109                 :            : ///         std::cout << "Unknown command '" << command_str << std::endl;
     110                 :            : ///     }
     111                 :            : /// } catch (CCSessionError cse) {
     112                 :            : ///     std::cerr << "Bad command in CC Session: "
     113                 :            : ///     << cse.what() << std::endl;
     114                 :            : /// }
     115                 :            : /// \endcode
     116                 :            : /// 
     117                 :            : /// \param arg This value will be set to the ElementPtr pointing to
     118                 :            : ///        the argument, or to an empty Map (ElementPtr) if there was none.
     119                 :            : /// \param command The command message containing the command (as made
     120                 :            : ///        by createCommand()
     121                 :            : /// \return The command name
     122                 :            : std::string parseCommand(isc::data::ConstElementPtr& arg,
     123                 :            :                          isc::data::ConstElementPtr command);
     124                 :            : 
     125                 :            : 
     126                 :            : ///
     127                 :            : /// \brief A standard cc session exception that is thrown if a function
     128                 :            : /// is there is a problem with one of the messages
     129                 :            : ///
     130                 :            : // todo: include types and called function in the exception
     131                 :         51 : class CCSessionError : public isc::Exception {
     132                 :            : public:
     133                 :         27 :     CCSessionError(const char* file, size_t line, const char* what) :
     134 [ +  - ][ +  - ]:         51 :         isc::Exception(file, line, what) {}
         [ +  - ][ +  - ]
     135                 :            : };
     136                 :            : 
     137                 :            : ///
     138                 :            : /// \brief This exception is thrown if the constructor fails
     139                 :            : ///
     140                 :          3 : class CCSessionInitError : public isc::Exception {
     141                 :            : public:
     142                 :            :     CCSessionInitError(const char* file, size_t line, const char* what) :
     143 [ #  # ][ +  - ]:          3 :         isc::Exception(file, line, what) {}
         [ +  - ][ #  # ]
                 [ -  + ]
     144                 :            : };
     145                 :            : 
     146                 :            : ///
     147                 :            : /// \brief This module keeps a connection to the command channel,
     148                 :            : /// holds configuration information, and handles messages from
     149                 :            : /// the command channel
     150                 :            : ///
     151                 :            : class ModuleCCSession : public ConfigData {
     152                 :            : public:
     153                 :            :     /**
     154                 :            :      * Initialize a config/command session
     155                 :            :      *
     156                 :            :      * @param spec_file_name The name of the file containing the
     157                 :            :      *                        module specification.
     158                 :            :      * @param session A Session object over which configuration and command
     159                 :            :      * data are exchanged.
     160                 :            :      * @param config_handler A callback function pointer to be called when
     161                 :            :      * configuration of the local module needs to be updated.
     162                 :            :      * This must refer to a valid object of a concrete derived class of
     163                 :            :      * AbstractSession without establishing the session.
     164                 :            :      *
     165                 :            :      * Note: the design decision on who is responsible for establishing the
     166                 :            :      * session is in flux, and may change in near future.
     167                 :            :      *
     168                 :            :      * \exception CCSessionInitError when the initialization fails,
     169                 :            :      *            either because the file cannot be read or there is
     170                 :            :      *            a communication problem with the config manager.
     171                 :            :      *
     172                 :            :      * @param command_handler A callback function pointer to be called when
     173                 :            :      * a control command from a remote agent needs to be performed on the
     174                 :            :      * local module.
     175                 :            :      * @param start_immediately If true (default), start listening to new commands
     176                 :            :      * and configuration changes asynchronously at the end of the constructor;
     177                 :            :      * if false, it will be delayed until the start() method is explicitly
     178                 :            :      * called. (This is a short term workaround for an initialization trouble.
     179                 :            :      * We'll need to develop a cleaner solution, and then remove this knob)
     180                 :            :      * @param handle_logging If true, the ModuleCCSession will automatically
     181                 :            :      * take care of logging configuration through the virtual Logging config
     182                 :            :      * module. Defaults to true.
     183                 :            :      */
     184                 :            :     ModuleCCSession(const std::string& spec_file_name,
     185                 :            :                     isc::cc::AbstractSession& session,
     186                 :            :                     isc::data::ConstElementPtr(*config_handler)(
     187                 :            :                         isc::data::ConstElementPtr new_config) = NULL,
     188                 :            :                     isc::data::ConstElementPtr(*command_handler)(
     189                 :            :                         const std::string& command,
     190                 :            :                         isc::data::ConstElementPtr args) = NULL,
     191                 :            :                     bool start_immediately = true,
     192                 :            :                     bool handle_logging = true
     193                 :            :                     );
     194                 :            : 
     195                 :            :     ///
     196                 :            :     /// Destructor
     197                 :            :     ///
     198                 :            :     /// The destructor automatically calls sendStopping(), which sends
     199                 :            :     /// a message to the ConfigManager that this module is stopping
     200                 :            :     ///
     201                 :            :     virtual ~ModuleCCSession();
     202                 :            : 
     203                 :            :     /// Start receiving new commands and configuration changes asynchronously.
     204                 :            :     ///
     205                 :            :     /// This method must be called only once, and only when the ModuleCCSession
     206                 :            :     /// was constructed with start_immediately being false.  Otherwise
     207                 :            :     /// CCSessionError will be thrown.
     208                 :            :     ///
     209                 :            :     /// As noted in the constructor, this method should be considered a short
     210                 :            :     /// term workaround and will be removed in future.
     211                 :            :     void start();
     212                 :            : 
     213                 :            :     /**
     214                 :            :      * Optional optimization for checkCommand loop; returns true
     215                 :            :      * if there are unhandled queued messages in the cc session.
     216                 :            :      * (if either this is true or there is data on the socket found
     217                 :            :      * by the select() call on getSocket(), run checkCommand())
     218                 :            :      * 
     219                 :            :      * @return true if there are unhandled queued messages
     220                 :            :      */
     221                 :            :     bool hasQueuedMsgs() const;
     222                 :            : 
     223                 :            :     /**
     224                 :            :      * Check if there is a command or config change on the command
     225                 :            :      * session. If so, the appropriate handler is called if set.
     226                 :            :      * If not set, a default answer is returned.
     227                 :            :      * This is a non-blocking read; if there is nothing this function
     228                 :            :      * will return 0.
     229                 :            :      */
     230                 :            :     int checkCommand();
     231                 :            : 
     232                 :            :     /**
     233                 :            :      * The config handler function should expect an ElementPtr containing
     234                 :            :      * the full configuration where non-default values have been set.
     235                 :            :      * Later we might want to think about more granular control
     236                 :            :      * (i.e. this does not scale to for instance lists containing
     237                 :            :      * 100000 zones, where the whole list is passed every time a single
     238                 :            :      * thing changes)
     239                 :            :      */
     240                 :            :     void setConfigHandler(isc::data::ConstElementPtr(*config_handler)(
     241                 :            :                               isc::data::ConstElementPtr new_config))
     242                 :            :     {
     243                 :            :         config_handler_ = config_handler;
     244                 :            :     }
     245                 :            : 
     246                 :            :     /**
     247                 :            :      * Set a command handler; the function that is passed takes an
     248                 :            :      * ElementPtr, pointing to a list element, containing
     249                 :            :      * [ module_name, command_name, arg1, arg2, ... ]
     250                 :            :      * The returned ElementPtr should look like
     251                 :            :      * { "result": [ return_value, result_value ] }
     252                 :            :      * result value here is optional and depends on the command
     253                 :            :      *
     254                 :            :      * This protocol is very likely to change.
     255                 :            :      */
     256                 :          0 :     void setCommandHandler(isc::data::ConstElementPtr(*command_handler)(
     257                 :            :                                const std::string& command,
     258                 :            :                                isc::data::ConstElementPtr args))
     259                 :            :     {
     260                 :          1 :         command_handler_ = command_handler;
     261                 :          0 :     }
     262                 :            : 
     263                 :            :     /**
     264                 :            :      * Gives access to the configuration values of a different module
     265                 :            :      * Once this function has been called with the name of the specification
     266                 :            :      * file or the module you want the configuration of, you can use
     267                 :            :      * \c getRemoteConfigValue() to get a specific setting.
     268                 :            :      * Changes are automatically updated, and you can specify handlers
     269                 :            :      * for those changes. This function will subscribe to the relevant module
     270                 :            :      * channel.
     271                 :            :      *
     272                 :            :      * This method must be called before calling the \c start() method on the
     273                 :            :      * ModuleCCSession (it also implies the ModuleCCSession must have been
     274                 :            :      * constructed with start_immediately being false).
     275                 :            :      *
     276                 :            :      * \param spec_name This specifies the module to add. It is either a
     277                 :            :      *                  filename of the spec file to use or a name of module
     278                 :            :      *                  (in case it's a module name, the spec data is
     279                 :            :      *                  downloaded from the configuration manager, therefore
     280                 :            :      *                  the configuration manager must know it). If
     281                 :            :      *                  spec_is_filename is true (the default), then a
     282                 :            :      *                  filename is assumed, otherwise a module name.
     283                 :            :      * \param handler The handler function called whenever there's a change.
     284                 :            :      *                Called once initally from this function. May be NULL
     285                 :            :      *                if you don't want any handler to be called and you're
     286                 :            :      *                fine with requesting the data through
     287                 :            :      *                getRemoteConfigValue() each time.
     288                 :            :      *
     289                 :            :      *                The handler should not throw, or it'll fall trough and
     290                 :            :      *                the exception will get into strange places, probably
     291                 :            :      *                aborting the application.
     292                 :            :      * \param spec_is_filename Says if spec_name is filename or module name.
     293                 :            :      * \return The name of the module specified in the given specification
     294                 :            :      *         file
     295                 :            :      */
     296                 :            :     std::string addRemoteConfig(const std::string& spec_name,
     297                 :            :                                 void (*handler)(const std::string& module_name,
     298                 :            :                                                 isc::data::ConstElementPtr
     299                 :            :                                                 update,
     300                 :            :                                                 const ConfigData& config_data) = NULL,
     301                 :            :                                 bool spec_is_filename = true);
     302                 :            : 
     303                 :            :     /**
     304                 :            :      * Removes the module with the given name from the remote config
     305                 :            :      * settings. If the module was not added with \c addRemoteConfig(),
     306                 :            :      * nothing happens. If there was a handler for this config, it is
     307                 :            :      * removed as well.
     308                 :            :      */
     309                 :            :     void removeRemoteConfig(const std::string& module_name);
     310                 :            : 
     311                 :            :     /**
     312                 :            :      * Returns the current configuration value for the given module
     313                 :            :      * name at the given identifier. See \c ConfigData::getValue() for
     314                 :            :      * more details.
     315                 :            :      * Raises a ModuleCCSessionError if the module name is unknown
     316                 :            :      * Raises a DataNotFoundError if the identifier does not exist
     317                 :            :      * in the specification.
     318                 :            :      *
     319                 :            :      * \param module_name The name of the module to get a config value for
     320                 :            :      * \param identifier The identifier of the config value
     321                 :            :      * \return The configuration setting at the given identifier
     322                 :            :      */
     323                 :            :     isc::data::ConstElementPtr getRemoteConfigValue(
     324                 :            :         const std::string& module_name,
     325                 :            :         const std::string& identifier) const;
     326                 :            : 
     327                 :            :     /**
     328                 :            :      * Send a message to the underlying CC session.
     329                 :            :      * This has the same interface as isc::cc::Session::group_sendmsg()
     330                 :            :      *
     331                 :            :      * \param msg see isc::cc::Session::group_sendmsg()
     332                 :            :      * \param group see isc::cc::Session::group_sendmsg()
     333                 :            :      * \param instance see isc::cc::Session::group_sendmsg()
     334                 :            :      * \param to see isc::cc::Session::group_sendmsg()
     335                 :            :      * \return see isc::cc::Session::group_sendmsg()
     336                 :            :      */
     337                 :            :     int groupSendMsg(isc::data::ConstElementPtr msg,
     338                 :            :                      std::string group,
     339                 :            :                      std::string instance = "*",
     340                 :            :                      std::string to = "*") {
     341                 :            :         return (session_.group_sendmsg(msg, group, instance, to));
     342                 :            :     };
     343                 :            : 
     344                 :            :     /**
     345                 :            :      * Receive a message from the underlying CC session.
     346                 :            :      * This has the same interface as isc::cc::Session::group_recvmsg()
     347                 :            :      *
     348                 :            :      * \param envelope see isc::cc::Session::group_recvmsg()
     349                 :            :      * \param msg see isc::cc::Session::group_recvmsg()
     350                 :            :      * \param nonblock see isc::cc::Session::group_recvmsg()
     351                 :            :      * \param seq see isc::cc::Session::group_recvmsg()
     352                 :            :      * \return see isc::cc::Session::group_recvmsg()
     353                 :            :      */
     354                 :            :     bool groupRecvMsg(isc::data::ConstElementPtr& envelope,
     355                 :            :                       isc::data::ConstElementPtr& msg,
     356                 :            :                       bool nonblock = true,
     357                 :            :                       int seq = -1) {
     358                 :            :         return (session_.group_recvmsg(envelope, msg, nonblock, seq));
     359                 :            :     };
     360                 :            : 
     361                 :            : private:
     362                 :            :     ModuleSpec readModuleSpecification(const std::string& filename);
     363                 :            :     void startCheck();
     364                 :            :     void sendStopping();
     365                 :            : 
     366                 :            :     bool started_;
     367                 :            :     std::string module_name_;
     368                 :            :     isc::cc::AbstractSession& session_;
     369                 :            :     ModuleSpec module_specification_;
     370                 :            :     isc::data::ConstElementPtr handleConfigUpdate(
     371                 :            :         isc::data::ConstElementPtr new_config);
     372                 :            : 
     373                 :            :     isc::data::ConstElementPtr checkConfigUpdateCommand(
     374                 :            :         const std::string& target_module,
     375                 :            :         isc::data::ConstElementPtr arg);
     376                 :            : 
     377                 :            :     isc::data::ConstElementPtr checkModuleCommand(
     378                 :            :         const std::string& cmd_str,
     379                 :            :         const std::string& target_module,
     380                 :            :         isc::data::ConstElementPtr arg) const;
     381                 :            : 
     382                 :            :     isc::data::ConstElementPtr(*config_handler_)(
     383                 :            :         isc::data::ConstElementPtr new_config);
     384                 :            :     isc::data::ConstElementPtr(*command_handler_)(
     385                 :            :         const std::string& command,
     386                 :            :         isc::data::ConstElementPtr args);
     387                 :            : 
     388                 :            :     typedef void (*RemoteHandler)(const std::string&,
     389                 :            :                                   isc::data::ConstElementPtr,
     390                 :            :                                   const ConfigData&);
     391                 :            :     std::map<std::string, ConfigData> remote_module_configs_;
     392                 :            :     std::map<std::string, RemoteHandler> remote_module_handlers_;
     393                 :            : 
     394                 :            :     void updateRemoteConfig(const std::string& module_name,
     395                 :            :                             isc::data::ConstElementPtr new_config);
     396                 :            : 
     397                 :            :     ModuleSpec fetchRemoteSpec(const std::string& module, bool is_filename);
     398                 :            : };
     399                 :            : 
     400                 :            : /// \brief Default handler for logging config updates
     401                 :            : ///
     402                 :            : /// When CCSession is initialized with handle_logging set to true,
     403                 :            : /// this callback will be used to update the logger when a configuration
     404                 :            : /// change comes in.
     405                 :            : ///
     406                 :            : /// This function updates the (global) loggers by initializing a
     407                 :            : /// LoggerManager and passing the settings as specified in the given
     408                 :            : /// configuration update.
     409                 :            : ///
     410                 :            : /// \param module_name The name of the module
     411                 :            : /// \param new_config The modified configuration values
     412                 :            : /// \param config_data The full config data for the (remote) logging
     413                 :            : ///                    module.
     414                 :            : void
     415                 :            : default_logconfig_handler(const std::string& module_name,
     416                 :            :                           isc::data::ConstElementPtr new_config,
     417                 :            :                           const ConfigData& config_data);
     418                 :            : 
     419                 :            : 
     420                 :            : /// \brief Returns the loggers related to this module
     421                 :            : ///
     422                 :            : /// This function does two things;
     423                 :            : /// - it drops the configuration parts for loggers for other modules.
     424                 :            : /// - it replaces the '*' in the name of the loggers by the name of
     425                 :            : ///   this module, but *only* if the expanded name is not configured
     426                 :            : ///   explicitly.
     427                 :            : ///
     428                 :            : /// Examples: if this is the module b10-resolver,
     429                 :            : /// For the config names ['*', 'b10-auth']
     430                 :            : /// The '*' is replaced with 'b10-resolver', and this logger is used.
     431                 :            : /// 'b10-auth' is ignored (of course, it will not be in the b10-auth
     432                 :            : /// module).
     433                 :            : ///
     434                 :            : /// For ['*', 'b10-resolver']
     435                 :            : /// The '*' is ignored, and only 'b10-resolver' is used.
     436                 :            : ///
     437                 :            : /// For ['*.reslib', 'b10-resolver']
     438                 :            : /// Or ['b10-resolver.reslib', '*']
     439                 :            : /// Both are used, where the * will be expanded to b10-resolver
     440                 :            : ///
     441                 :            : /// \note This is a public function at this time, but mostly for
     442                 :            : /// the purposes of testing. Once we can directly test what loggers
     443                 :            : /// are running, this function may be moved to the unnamed namespace
     444                 :            : ///
     445                 :            : /// \param loggers the original 'loggers' config list
     446                 :            : /// \return ListElement containing only loggers relevant for this
     447                 :            : ///         module, where * is replaced by the root logger name
     448                 :            : isc::data::ConstElementPtr
     449                 :            : getRelatedLoggers(isc::data::ConstElementPtr loggers);
     450                 :            : 
     451                 :            : } // namespace config
     452                 :            : 
     453                 :            : } // namespace isc
     454                 :            : #endif // __CCSESSION_H
     455                 :            : 
     456                 :            : // Local Variables:
     457                 :            : // mode: c++
     458                 :            : // End:

Generated by: LCOV version 1.9