Browse Source

[2862] Hack in a way to receive foreign commands

Provide a callback to receive commands for foreign modules. The current
implementation is somewhat broken and unsatisfactory, but let's leave
that up for later. We need a way now.
Michal 'vorner' Vaner 11 years ago
parent
commit
661dae35e3

+ 2 - 0
src/lib/config/ccsession.cc

@@ -595,6 +595,8 @@ ModuleCCSession::checkModuleCommand(const std::string& cmd_str,
                                  "Command given but no "
                                  "command handler for module"));
         }
+    } else if (unhandled_callback_) {
+        unhandled_callback_(cmd_str, target_module, arg);
     }
     return (ElementPtr());
 }

+ 32 - 0
src/lib/config/ccsession.h

@@ -589,6 +589,36 @@ public:
         session_.unsubscribe(group, isc::cc::CC_INSTANCE_WILDCARD);
     }
 
+    /// \brief Callback type for unhandled commands
+    ///
+    /// The type of functions that are not handled by the ModuleCCSession
+    /// because they are not aimed at the module.
+    ///
+    /// The parameters are:
+    /// - Name of the command.
+    /// - The module it was aimed for (may be empty).
+    /// - The parameters of the command.
+    typedef boost::function<void (const std::string&, const std::string&,
+                                  const isc::data::ConstElementPtr&)>
+        UnhandledCallback;
+
+    /// \brief Register a callback for messages sent to foreign modules.
+    ///
+    /// Usually, a command aimed at foreign module (or sent directly)
+    /// is discarded. By registering a callback here, these can be
+    /// examined.
+    ///
+    /// \note A callback overwrites the previous one set.
+    /// \todo This is a temporary, unclean, solution. A more generic
+    ///     one needs to be designed. Also, a solution that is able
+    ///     to send an answer would be great.
+    ///
+    /// \param callback The new callback to use. It may be an empty
+    ///     function.
+    void setUnhandledCallback(const UnhandledCallback& callback) {
+        unhandled_callback_ = callback;
+    }
+
 private:
     ModuleSpec readModuleSpecification(const std::string& filename);
     void startCheck();
@@ -638,6 +668,8 @@ private:
                             isc::data::ConstElementPtr new_config);
 
     ModuleSpec fetchRemoteSpec(const std::string& module, bool is_filename);
+
+    UnhandledCallback unhandled_callback_;
 };
 
 /// \brief Default handler for logging config updates

+ 26 - 0
src/lib/config/tests/ccsession_unittests.cc

@@ -697,6 +697,16 @@ TEST_F(CCSessionTest, remoteConfig) {
     }
 }
 
+void
+callback(std::string* command, std::string* target, ConstElementPtr *params,
+         const std::string& command_real, const std::string& target_real,
+         const ConstElementPtr& params_real)
+{
+    *command = command_real;
+    *target = target_real;
+    *params = params_real;
+}
+
 TEST_F(CCSessionTest, ignoreRemoteConfigCommands) {
     // client will ask for config
     session.getMessages()->add(createAnswer(0, el("{  }")));
@@ -732,6 +742,22 @@ TEST_F(CCSessionTest, ignoreRemoteConfigCommands) {
     result = mccs.checkCommand();
     EXPECT_EQ(0, session.getMsgQueue()->size());
     EXPECT_EQ(0, result);
+
+    // Check that we can get the ignored commands by registering a callback
+    std::string command, target;
+    ConstElementPtr params;
+    mccs.setUnhandledCallback(boost::bind(&callback, &command, &target,
+                                          &params, _1, _2, _3));
+    session.addMessage(el("{ \"command\": [ \"good_command\","
+                          "{\"param\": true} ] }"), "Spec1", "*");
+    EXPECT_EQ(1, session.getMsgQueue()->size());
+    result = mccs.checkCommand();
+    EXPECT_EQ(0, session.getMsgQueue()->size());
+    EXPECT_EQ(0, result);
+
+    EXPECT_EQ("good_command", command);
+    EXPECT_EQ("Spec1", target);
+    EXPECT_TRUE(params && el("{\"param\": true}")->equals(*params));
 }
 
 TEST_F(CCSessionTest, initializationFail) {