Browse Source

[3880] Implemented handlers for statistic-* commands.

Tomek Mrugalski 10 years ago
parent
commit
a3856901aa

+ 1 - 1
src/lib/Makefile.am

@@ -1,3 +1,3 @@
 # The following build order must be maintained.
-SUBDIRS = exceptions util log hooks cryptolink dns cc stats dhcp config \
+SUBDIRS = exceptions util log hooks cryptolink dns cc dhcp config stats \
           asiolink asiodns testutils dhcp_ddns dhcpsrv

+ 1 - 0
src/lib/stats/Makefile.am

@@ -11,6 +11,7 @@ libkea_stats_la_SOURCES += stats_mgr.h stats_mgr.cc
 
 libkea_stats_la_CPPFLAGS = $(AM_CPPFLAGS)
 libkea_stats_la_LIBADD  = $(top_builddir)/src/lib/cc/libkea-cc.la
+libkea_stats_la_LIBADD += $(top_builddir)/src/lib/config/libkea-cfgclient.la
 libkea_stats_la_LIBADD += $(top_builddir)/src/lib/util/libkea-util.la
 
 libkea_stats_includedir = $(includedir)/$(PACKAGE_NAME)/stats

+ 93 - 0
src/lib/stats/stats_mgr.cc

@@ -14,8 +14,12 @@
 
 #include <exceptions/exceptions.h>
 #include <stats/stats_mgr.h>
+#include <cc/data.h>
+#include <config/command_interpreter.h>
 
 using namespace std;
+using namespace isc::data;
+using namespace isc::config;
 
 namespace isc {
 namespace stats {
@@ -142,6 +146,95 @@ size_t StatsMgr::count() const {
     return (global_->stats_.size());
 }
 
+isc::data::ConstElementPtr
+StatsMgr::statisticGetHandler(const std::string& /*name*/,
+                              const isc::data::ConstElementPtr& params) {
+    if (!params) {
+        return (createAnswer(CONTROL_RESULT_ERROR,
+                             "Missing mandatory 'name' parameter."));
+    }
+    ConstElementPtr stat_name = params->get("name");
+    if (!stat_name) {
+        return (createAnswer(CONTROL_RESULT_ERROR,
+                             "Missing mandatory 'name' parameter."));
+    }
+    if (stat_name->getType() != Element::string) {
+        return (createAnswer(CONTROL_RESULT_ERROR,
+                             "'name' parameter expected to be a string."));
+    }
+    return (createAnswer(CONTROL_RESULT_SUCCESS, get(stat_name->stringValue())));
+}
+
+isc::data::ConstElementPtr
+StatsMgr::statisticResetHandler(const std::string& /*name*/,
+                                const isc::data::ConstElementPtr& params) {
+    if (!params) {
+        return (createAnswer(CONTROL_RESULT_ERROR,
+                             "Missing mandatory 'name' parameter."));
+    }
+    ConstElementPtr stat_name = params->get("name");
+    if (!stat_name) {
+        return (createAnswer(CONTROL_RESULT_ERROR,
+                             "Missing mandatory 'name' parameter."));
+    }
+    if (stat_name->getType() != Element::string) {
+        return (createAnswer(CONTROL_RESULT_ERROR,
+                             "'name' parameter expected to be a string."));
+    }
+
+    if (reset(stat_name->stringValue())) {
+        return (createAnswer(CONTROL_RESULT_SUCCESS,
+                             "Statistic '" + stat_name->stringValue() + "' reset."));
+    } else {
+        return (createAnswer(CONTROL_RESULT_ERROR,
+                             "No '" + stat_name->stringValue() + "' statistic found"));
+    }
+}
+
+isc::data::ConstElementPtr
+StatsMgr::statisticRemoveHandler(const std::string& /*name*/,
+                                 const isc::data::ConstElementPtr& params) {
+    if (!params) {
+        return (createAnswer(CONTROL_RESULT_ERROR,
+                             "Missing mandatory 'name' parameter."));
+    }
+    ConstElementPtr stat_name = params->get("name");
+    if (!stat_name) {
+        return (createAnswer(CONTROL_RESULT_ERROR,
+                             "Missing mandatory 'name' parameter."));
+    }
+    if (del(stat_name->stringValue())) {
+        return (createAnswer(CONTROL_RESULT_SUCCESS,
+                             "Statistic '" + stat_name->stringValue() + "' removed."));
+    } else {
+        return (createAnswer(CONTROL_RESULT_ERROR,
+                             "No '" + stat_name->stringValue() + "' statistic found"));
+    }
+
+}
+
+isc::data::ConstElementPtr
+StatsMgr::statisticRemoveAllHandler(const std::string& /*name*/,
+                                    const isc::data::ConstElementPtr& /*params*/) {
+    removeAll();
+    return (createAnswer(CONTROL_RESULT_SUCCESS,
+                         "All statistics removed."));
+}
+
+isc::data::ConstElementPtr
+StatsMgr::statisticGetAllHandler(const std::string& /*name*/,
+                                 const isc::data::ConstElementPtr& /*params*/) {
+    ConstElementPtr all_stats = getAll();
+    return (createAnswer(CONTROL_RESULT_SUCCESS, all_stats));
+}
+
+isc::data::ConstElementPtr
+StatsMgr::statisticResetAllHandler(const std::string& /*name*/,
+                                   const isc::data::ConstElementPtr& /*params*/) {
+    resetAll();
+    return (createAnswer(CONTROL_RESULT_SUCCESS,
+                         "All statistics reset to neutral values."));
+}
 
 
 };

+ 98 - 0
src/lib/stats/stats_mgr.h

@@ -197,6 +197,104 @@ class StatsMgr : public boost::noncopyable {
     /// @return Pointer to the Observation object
     ObservationPtr getObservation(const std::string& name) const;
 
+    /// @defgroup command_methods Methods are used to handle commands.
+    ///
+    /// @brief The following methods are used to handle commands:
+    ///
+    /// @{
+
+    /// @brief Handles statistic-get command
+    ///
+    /// This method handles statistic-get command, which returns value
+    /// of a given statistic). It expects one parameter stored in params map:
+    /// name: name-of-the-statistic
+    ///
+    /// Example params structure:
+    /// {
+    ///     "name": "packets-received"
+    /// }
+    ///
+    /// @param name name of the command (ignored, should be "statistic-get")
+    /// @param params structure containing a map that contains "name"
+    /// @param return answer containing details of specified statistic
+    isc::data::ConstElementPtr
+    statisticGetHandler(const std::string& name,
+                        const isc::data::ConstElementPtr& params);
+
+    /// @param Handles statistic-reset command
+    ///
+    /// This method handles statistic-reset command, which resets value
+    /// of a given statistic. It expects one parameter stored in params map:
+    /// name: name-of-the-statistic
+    ///
+    /// Example params structure:
+    /// {
+    ///     "name": "packets-received"
+    /// }
+    ///
+    /// @param name name of the command (ignored, should be "statistic-reset")
+    /// @param params structure containing a map that contains "name"
+    /// @param return answer containing confirmation
+    isc::data::ConstElementPtr
+    statisticResetHandler(const std::string& name,
+                          const isc::data::ConstElementPtr& params);
+
+    /// @param Handles statistic-remove command
+    ///
+    /// This method handles statistic-reset command, which removes a given
+    /// statistic completely. It expects one parameter stored in params map:
+    /// name: name-of-the-statistic
+    ///
+    /// Example params structure:
+    /// {
+    ///     "name": "packets-received"
+    /// }
+    ///
+    /// @param name name of the command (ignored, should be "statistic-remove")
+    /// @param params structure containing a map that contains "name" element
+    /// @param return answer containing confirmation
+    isc::data::ConstElementPtr
+    statisticRemoveHandler(const std::string& name,
+                           const isc::data::ConstElementPtr& params);
+
+    /// @brief Handles statistic-get-all command
+    ///
+    /// This method handles statistic-get-all command, which returns values
+    /// of all statistics. Params parameter is ignored.
+    ///
+    /// @param name name of the command (ignored, should be "statistic-get-all")
+    /// @param params ignored
+    /// @param return answer containing values of all statistic
+    isc::data::ConstElementPtr
+    statisticGetAllHandler(const std::string& name,
+                           const isc::data::ConstElementPtr& params);
+
+    /// @brief Handles statistic-reset-all command
+    ///
+    /// This method handles statistic-reset-all command, which sets values of
+    /// all statistics back to zero. Params parameter is ignored.
+    ///
+    /// @param name name of the command (ignored, should be "statistic-reset-all")
+    /// @param params ignored
+    /// @param return answer confirming success of this operation
+    isc::data::ConstElementPtr
+    statisticResetAllHandler(const std::string& name,
+                             const isc::data::ConstElementPtr& params);
+
+    /// @brief Handles statistic-remove-all command
+    ///
+    /// This method handles statistic-remove-all command, which removes all
+    /// statistics. Params parameter is ignored.
+    ///
+    /// @param name name of the command (ignored, should be "statistic-remove-all")
+    /// @param params ignored
+    /// @param return answer confirming success of this operation
+    isc::data::ConstElementPtr
+    statisticRemoveAllHandler(const std::string& name,
+                              const isc::data::ConstElementPtr& params);
+
+    /// @}
+
  private:
 
     /// @brief Sets a given statistic to specified value (internal version).

+ 1 - 0
src/lib/stats/tests/Makefile.am

@@ -24,6 +24,7 @@ libstats_unittests_CXXFLAGS = $(AM_CXXFLAGS)
 
 libstats_unittests_LDADD  = $(top_builddir)/src/lib/stats/libkea-stats.la
 libstats_unittests_LDADD += $(top_builddir)/src/lib/cc/libkea-cc.la
+libstats_unittests_LDADD += $(top_builddir)/src/lib/config/libkea-cfgclient.la
 libstats_unittests_LDADD += $(top_builddir)/src/lib/log/libkea-log.la
 libstats_unittests_LDADD += $(top_builddir)/src/lib/util/libkea-util.la
 libstats_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libkea-exceptions.la

+ 273 - 0
src/lib/stats/tests/stats_mgr_unittest.cc

@@ -17,6 +17,7 @@
 #include <stats/stats_mgr.h>
 #include <exceptions/exceptions.h>
 #include <cc/data.h>
+#include <config/command_interpreter.h>
 #include <util/boost_time_utils.h>
 #include <boost/date_time/posix_time/posix_time_types.hpp>
 #include <boost/shared_ptr.hpp>
@@ -28,6 +29,7 @@
 using namespace isc;
 using namespace isc::data;
 using namespace isc::stats;
+using namespace isc::config;
 using namespace boost::posix_time;
 
 namespace {
@@ -42,6 +44,7 @@ public:
     /// Makes sure that the Statistics Manager is instantiated.
     StatsMgrTest() {
         StatsMgr::instance();
+        StatsMgr::instance().removeAll();
     }
 
     /// @brief Destructor
@@ -397,4 +400,274 @@ TEST_F(StatsMgrTest, DISABLED_performanceMultipleSet) {
               << " times took: " << isc::util::durationToText(dur) << std::endl;
 }
 
+// Test checks if statistic-get handler is able to return specified statistic.
+TEST_F(StatsMgrTest, commandStatisticGet) {
+    StatsMgr::instance().setValue("alpha", static_cast<uint64_t>(1234));
+
+    ElementPtr params = Element::createMap();
+    params->set("name", Element::create("alpha"));
+
+    ConstElementPtr rsp = StatsMgr::instance().statisticGetHandler("statistic-get",
+                                                                   params);
+
+    ObservationPtr alpha;
+    EXPECT_NO_THROW(alpha = StatsMgr::instance().getObservation("alpha"));
+    ASSERT_TRUE(alpha);
+
+    std::string exp = "{ \"alpha\": [ [ 1234, \""
+        + isc::util::ptimeToText(alpha->getInteger().second) + "\" ] ] }";
+
+    EXPECT_EQ("{ \"arguments\": " + exp + ", \"result\": 0 }", rsp->str());
+}
+
+// Test checks if statistic-get is able to handle:
+// - a request without parameters
+// - a request with missing statistic name
+// - a request for non-existing statistic.
+TEST_F(StatsMgrTest, commandStatisticGetNegative) {
+
+    // Case 1: a request without parameters
+    ConstElementPtr rsp = StatsMgr::instance().statisticGetHandler("statistic-get",
+                                                                   ElementPtr());
+    int status_code;
+    ASSERT_NO_THROW(parseAnswer(status_code, rsp));
+    EXPECT_EQ(status_code, CONTROL_RESULT_ERROR);
+
+    // Case 2: a request with missing statistic name
+    ElementPtr params = Element::createMap();
+    rsp = StatsMgr::instance().statisticGetHandler("statistic-get", params);
+    ASSERT_NO_THROW(parseAnswer(status_code, rsp));
+    EXPECT_EQ(status_code, CONTROL_RESULT_ERROR);
+
+    // Case 3: a request for non-existing statistic
+    params->set("name", Element::create("alpha"));
+    rsp = StatsMgr::instance().statisticGetHandler("statistic-get", params);
+    EXPECT_EQ("{ \"arguments\": {  }, \"result\": 0 }", rsp->str());
+}
+
+// This test checks whether statistc-get-all command returns all statistics
+// correctly.
+TEST_F(StatsMgrTest, commandGetAll) {
+
+    // Set a couple of statistics
+    StatsMgr::instance().setValue("alpha", static_cast<uint64_t>(1234));
+    StatsMgr::instance().setValue("beta", 12.34);
+    StatsMgr::instance().setValue("gamma", time_duration(1,2,3,4));
+    StatsMgr::instance().setValue("delta", "Lorem ipsum");
+
+    // Now get them. They're used to generate expected output
+    ConstElementPtr rep_alpha = StatsMgr::instance().get("alpha");
+    ConstElementPtr rep_beta = StatsMgr::instance().get("beta");
+    ConstElementPtr rep_gamma = StatsMgr::instance().get("gamma");
+    ConstElementPtr rep_delta = StatsMgr::instance().get("delta");
+
+    ASSERT_TRUE(rep_alpha);
+    ASSERT_TRUE(rep_beta);
+    ASSERT_TRUE(rep_gamma);
+    ASSERT_TRUE(rep_delta);
+
+    std::string exp_str_alpha = "[ [ 1234, \""
+        + isc::util::ptimeToText(StatsMgr::instance().getObservation("alpha")
+                                   ->getInteger().second) + "\" ] ]";
+    std::string exp_str_beta = "[ [ 12.34, \""
+        + isc::util::ptimeToText(StatsMgr::instance().getObservation("beta")
+                                   ->getFloat().second) + "\" ] ]";
+    std::string exp_str_gamma = "[ [ \"01:02:03.000004\", \""
+        + isc::util::ptimeToText(StatsMgr::instance().getObservation("gamma")
+                                   ->getDuration().second) + "\" ] ]";
+    std::string exp_str_delta = "[ [ \"Lorem ipsum\", \""
+        + isc::util::ptimeToText(StatsMgr::instance().getObservation("delta")
+                                   ->getString().second) + "\" ] ]";
+
+    // Check that all of them can be reported at once
+    ConstElementPtr rsp = StatsMgr::instance().statisticGetAllHandler(
+        "statistic-get-all", ElementPtr());
+    ASSERT_TRUE(rsp);
+    int status_code;
+    ConstElementPtr rep_all = parseAnswer(status_code, rsp);
+    ASSERT_EQ(0, status_code);
+    ASSERT_TRUE(rep_all);
+
+    // Verifying this is a bit more involved, as we don't know whether the
+    // order would be preserved or not.
+    EXPECT_EQ(4, rep_all->size());
+    ASSERT_TRUE(rep_all->get("alpha"));
+    ASSERT_TRUE(rep_all->get("beta"));
+    ASSERT_TRUE(rep_all->get("delta"));
+    ASSERT_TRUE(rep_all->get("gamma"));
+    EXPECT_FALSE(rep_all->get("epsilon"));
+
+    EXPECT_EQ(exp_str_alpha, rep_all->get("alpha")->str());
+    EXPECT_EQ(exp_str_beta, rep_all->get("beta")->str());
+    EXPECT_EQ(exp_str_gamma, rep_all->get("gamma")->str());
+    EXPECT_EQ(exp_str_delta, rep_all->get("delta")->str());
+}
+
+// Test checks if statistic-reset handler is able to reset specified statistic.
+TEST_F(StatsMgrTest, commandStatisticReset) {
+    StatsMgr::instance().setValue("alpha", static_cast<uint64_t>(1234));
+
+    ElementPtr params = Element::createMap();
+    params->set("name", Element::create("alpha"));
+
+    ConstElementPtr rsp =
+        StatsMgr::instance().statisticResetHandler("statistic-reset", params);
+    int status_code;
+    ASSERT_NO_THROW(parseAnswer(status_code, rsp));
+    EXPECT_EQ(CONTROL_RESULT_SUCCESS, status_code);
+
+    ObservationPtr alpha;
+    EXPECT_NO_THROW(alpha = StatsMgr::instance().getObservation("alpha"));
+    ASSERT_TRUE(alpha);
+
+    // Check that it was indeed reset
+    EXPECT_EQ(0, alpha->getInteger().first);
+}
+
+// Test checks if statistic-reset is able to handle:
+// - a request without parameters
+// - a request with missing statistic name
+// - a request for non-existing statistic.
+TEST_F(StatsMgrTest, commandStatisticResetNegative) {
+
+    // Case 1: a request without parameters
+    ConstElementPtr rsp =
+        StatsMgr::instance().statisticResetHandler("statistic-reset", ElementPtr());
+    int status_code;
+    ASSERT_NO_THROW(parseAnswer(status_code, rsp));
+    EXPECT_EQ(status_code, CONTROL_RESULT_ERROR);
+
+    // Case 2: a request with missing statistic name
+    ElementPtr params = Element::createMap();
+    rsp = StatsMgr::instance().statisticResetHandler("statistic-reset", params);
+    ASSERT_NO_THROW(parseAnswer(status_code, rsp));
+    EXPECT_EQ(status_code, CONTROL_RESULT_ERROR);
+
+    // Case 3: a request for non-existing statistic
+    params->set("name", Element::create("alpha"));
+    rsp = StatsMgr::instance().statisticResetHandler("statistic-reset", params);
+    EXPECT_EQ("{ \"result\": 1, \"text\": \"No 'alpha' statistic found\" }",
+              rsp->str());
+}
+
+// This test checks whether statistic-reset-all command really resets all
+// statistics correctly.
+TEST_F(StatsMgrTest, commandResetAll) {
+
+    // Set a couple of statistics
+    StatsMgr::instance().setValue("alpha", static_cast<uint64_t>(1234));
+    StatsMgr::instance().setValue("beta", 12.34);
+    StatsMgr::instance().setValue("gamma", time_duration(1,2,3,4));
+    StatsMgr::instance().setValue("delta", "Lorem ipsum");
+
+    // Now get them. They're used to generate expected output
+    ConstElementPtr rep_alpha = StatsMgr::instance().get("alpha");
+    ConstElementPtr rep_beta = StatsMgr::instance().get("beta");
+    ConstElementPtr rep_gamma = StatsMgr::instance().get("gamma");
+    ConstElementPtr rep_delta = StatsMgr::instance().get("delta");
+
+    ASSERT_TRUE(rep_alpha);
+    ASSERT_TRUE(rep_beta);
+    ASSERT_TRUE(rep_gamma);
+    ASSERT_TRUE(rep_delta);
+
+    std::string exp_str_alpha = "[ [ 1234, \""
+        + isc::util::ptimeToText(StatsMgr::instance().getObservation("alpha")
+                                   ->getInteger().second) + "\" ] ]";
+    std::string exp_str_beta = "[ [ 12.34, \""
+        + isc::util::ptimeToText(StatsMgr::instance().getObservation("beta")
+                                   ->getFloat().second) + "\" ] ]";
+    std::string exp_str_gamma = "[ [ \"01:02:03.000004\", \""
+        + isc::util::ptimeToText(StatsMgr::instance().getObservation("gamma")
+                                   ->getDuration().second) + "\" ] ]";
+    std::string exp_str_delta = "[ [ \"Lorem ipsum\", \""
+        + isc::util::ptimeToText(StatsMgr::instance().getObservation("delta")
+                                   ->getString().second) + "\" ] ]";
+
+    // Check that all of them can be reset at once
+    ConstElementPtr rsp = StatsMgr::instance().statisticResetAllHandler(
+        "statistic-reset-all", ElementPtr());
+    ASSERT_TRUE(rsp);
+    int status_code;
+    ConstElementPtr rep_all = parseAnswer(status_code, rsp);
+    ASSERT_EQ(0, status_code);
+    ASSERT_TRUE(rep_all);
+
+    // Check that they're indeed reset
+    EXPECT_EQ(0, StatsMgr::instance().getObservation("alpha")->getInteger().first);
+    EXPECT_EQ(0.0f,
+              StatsMgr::instance().getObservation("beta")->getFloat().first);
+    EXPECT_EQ(time_duration(0,0,0,0),
+              StatsMgr::instance().getObservation("gamma")->getDuration().first);
+    EXPECT_EQ("",
+              StatsMgr::instance().getObservation("delta")->getString().first);
+}
+
+// Test checks if statistic-remove handler is able to remove a statistic.
+TEST_F(StatsMgrTest, commandStatisticRemove) {
+    StatsMgr::instance().setValue("alpha", static_cast<uint64_t>(1234));
+
+    ElementPtr params = Element::createMap();
+    params->set("name", Element::create("alpha"));
+
+    ConstElementPtr rsp =
+        StatsMgr::instance().statisticRemoveHandler("statistic-remove", params);
+    int status_code;
+    ASSERT_NO_THROW(parseAnswer(status_code, rsp));
+    EXPECT_EQ(CONTROL_RESULT_SUCCESS, status_code);
+
+    // It should be gone.
+    EXPECT_FALSE(StatsMgr::instance().getObservation("alpha"));
+}
+
+// Test checks if statistic-remove is able to handle:
+// - a request without parameters
+// - a request with missing statistic name
+// - a request for non-existing statistic.
+TEST_F(StatsMgrTest, commandStatisticRemoveNegative) {
+
+    // Case 1: a request without parameters
+    ConstElementPtr rsp =
+        StatsMgr::instance().statisticRemoveHandler("statistic-remove", ElementPtr());
+    int status_code;
+    ASSERT_NO_THROW(parseAnswer(status_code, rsp));
+    EXPECT_EQ(status_code, CONTROL_RESULT_ERROR);
+
+    // Case 2: a request with missing statistic name
+    ElementPtr params = Element::createMap();
+    rsp = StatsMgr::instance().statisticRemoveHandler("statistic-remove", params);
+    ASSERT_NO_THROW(parseAnswer(status_code, rsp));
+    EXPECT_EQ(status_code, CONTROL_RESULT_ERROR);
+
+    // Case 3: a request for non-existing statistic
+    params->set("name", Element::create("alpha"));
+    rsp = StatsMgr::instance().statisticRemoveHandler("statistic-remove", params);
+    EXPECT_EQ("{ \"result\": 1, \"text\": \"No 'alpha' statistic found\" }",
+              rsp->str());
+}
+
+// This test checks whether statistic-remove-all command really resets all
+// statistics correctly.
+TEST_F(StatsMgrTest, commandRemoveAll) {
+
+    // Set a couple of statistics
+    StatsMgr::instance().setValue("alpha", static_cast<uint64_t>(1234));
+    StatsMgr::instance().setValue("beta", 12.34);
+    StatsMgr::instance().setValue("gamma", time_duration(1,2,3,4));
+    StatsMgr::instance().setValue("delta", "Lorem ipsum");
+
+    // Check that all of them can be reset at once
+    ConstElementPtr rsp = StatsMgr::instance().statisticRemoveAllHandler(
+        "statistic-remove-all", ElementPtr());
+    ASSERT_TRUE(rsp);
+    int status_code;
+    ConstElementPtr rep_all = parseAnswer(status_code, rsp);
+    ASSERT_EQ(0, status_code);
+
+    EXPECT_FALSE(StatsMgr::instance().getObservation("alpha"));
+    EXPECT_FALSE(StatsMgr::instance().getObservation("beta"));
+    EXPECT_FALSE(StatsMgr::instance().getObservation("gamma"));
+    EXPECT_FALSE(StatsMgr::instance().getObservation("delta"));
+}
+
 };