]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
New command for manipulating Observation's limits
authorFranciszek Gorski <fagorski9@gmail.com>
Fri, 5 Jul 2019 15:18:50 +0000 (17:18 +0200)
committerRazvan Becheriu <razvan@isc.org>
Mon, 15 Jul 2019 12:32:16 +0000 (15:32 +0300)
src/bin/dhcp4/ctrl_dhcp4_srv.cc
src/bin/dhcp6/ctrl_dhcp6_srv.cc
src/lib/stats/stats_mgr.cc
src/lib/stats/stats_mgr.h
src/lib/stats/tests/stats_mgr_unittest.cc

index 3964a1a3fb08c557a93d2f3e40342b9f1157240f..c983c34dd5a911f9123db63f66319441a79a6d9e 100644 (file)
@@ -838,6 +838,12 @@ ControlledDhcpv4Srv::ControlledDhcpv4Srv(uint16_t server_port /*= DHCP4_SERVER_P
     CommandMgr::instance().registerCommand("statistic-remove",
         boost::bind(&StatsMgr::statisticRemoveHandler, _1, _2));
 
+    //CommandMgr::instance().registerCommand("statistic-setMaxSampleAge",
+    //    boost::bind(&StatsMgr::statisticSetMaxSampleAgeHandler, _1, _2));
+
+    //CommandMgr::instance().registerCommand("statistic-setMaxSampleCount",
+    //    boost::bind(&StatsMgr::statisticSetMaxSampleCountHandler, _1, _2));
+
     CommandMgr::instance().registerCommand("statistic-get-all",
         boost::bind(&StatsMgr::statisticGetAllHandler, _1, _2));
 
@@ -885,6 +891,8 @@ ControlledDhcpv4Srv::~ControlledDhcpv4Srv() {
         CommandMgr::instance().deregisterCommand("statistic-remove-all");
         CommandMgr::instance().deregisterCommand("statistic-reset");
         CommandMgr::instance().deregisterCommand("statistic-reset-all");
+        //CommandMgr::instance().deregisterCommand("statistic-setMaxSampleAge");
+        //CommandMgr::instance().deregisterCommand("statistic-setMaxSampleCount");
         CommandMgr::instance().deregisterCommand("version-get");
 
     } catch (...) {
index 8cb2737cce81f30cd2d3f6ad3066fdc6a0666a81..41be37fdaa9dd1473fcebb73c2ef4cfc8af9af06 100644 (file)
@@ -870,6 +870,12 @@ ControlledDhcpv6Srv::ControlledDhcpv6Srv(uint16_t server_port,
 
     CommandMgr::instance().registerCommand("statistic-remove-all",
         boost::bind(&StatsMgr::statisticRemoveAllHandler, _1, _2));
+
+    CommandMgr::instance().registerCommand("statistic-setMaxSampleAge",
+        boost::bind(&StatsMgr::statisticSetMaxSampleAgeHandler, _1, _2));
+
+    CommandMgr::instance().registerCommand("statistic-setMaxSampleCount",
+        boost::bind(&StatsMgr::statisticSetMaxSampleCountHandler, _1, _2));
 }
 
 void ControlledDhcpv6Srv::shutdown() {
index 3ae30e24edb403d14aadcbc7412e4a8fc3d63ee1..b32c0ab36091294ce7212129b84d209762b4fbc1 100644 (file)
@@ -164,6 +164,48 @@ size_t StatsMgr::count() const {
     return (global_->stats_.size());
 }
 
+isc::data::ConstElementPtr
+StatsMgr::statisticSetMaxSampleAgeHandler(const std::string& /*name*/,
+                              const isc::data::ConstElementPtr& params) {
+    std::string name, error;
+    StatsDuration duration;
+    if (!getStatName(params, name, error)) {
+        return (createAnswer(CONTROL_RESULT_ERROR, error));
+    }
+    if (!getStatDuration(params, duration, error)) {
+        return (createAnswer(CONTROL_RESULT_ERROR, error));
+    }
+    if (instance().setMaxSampleAge(name, duration)) {
+        return (createAnswer(CONTROL_RESULT_SUCCESS,
+                            "Statistic '" + name + "' duration limit is set."));
+                            //"Statistic '" + name + "' duration limit is set to " + std::to_string(duration) + "."));
+    } else {
+        return (createAnswer(CONTROL_RESULT_ERROR,
+                             "No '" + name + "' statistic found"));
+    }
+}
+
+isc::data::ConstElementPtr
+StatsMgr::statisticSetMaxSampleCountHandler(const std::string& /*name*/,
+                            const isc::data::ConstElementPtr& params) {
+    std::string name, error;
+    uint32_t max_samples;
+    if (!getStatName(params, name, error)) {
+        return (createAnswer(CONTROL_RESULT_ERROR, error));
+    }
+    if (!getStatMaxSamples(params, max_samples, error)) {
+        return (createAnswer(CONTROL_RESULT_ERROR, error));
+    }
+    if (instance().setMaxSampleCount(name, max_samples)) {
+        return (createAnswer(CONTROL_RESULT_SUCCESS,
+                            "Statistic '" + name + "' count limit is set."));
+                            //"Statistic '" + name + "' count limit is set to " + std::to_string(max_samples) + "."));
+    } else {
+        return (createAnswer(CONTROL_RESULT_ERROR,
+                           "No '" + name + "' statistic found"));
+    }
+}
+
 isc::data::ConstElementPtr
 StatsMgr::statisticGetHandler(const std::string& /*name*/,
                               const isc::data::ConstElementPtr& params) {
@@ -254,5 +296,79 @@ StatsMgr::getStatName(const isc::data::ConstElementPtr& params,
     return (true);
 }
 
+bool
+StatsMgr::getStatDuration(const isc::data::ConstElementPtr& params,
+                      StatsDuration& duration,
+                      std::string& reason) {
+    if (!params) {
+        reason = "Missing mandatory 'duration' parameters.";
+        return (false);
+    }
+    ConstElementPtr stat_hours = params->get("hours");
+    if (!stat_hours) {
+        reason = "Missing mandatory 'hours' parameter.";
+        return (false);
+    }
+    if (stat_hours->getType() != Element::integer) {
+        reason = "'hours' parameter expected to be an integer.";
+        return (false);
+    }
+    ConstElementPtr stat_minutes = params->get("minutes");
+    if (!stat_minutes) {
+        reason = "Missing mandatory 'minutes' parameter.";
+        return (false);
+    }
+    if (stat_minutes->getType() != Element::integer) {
+        reason = "'minutes' parameter expected to be an integer.";
+        return (false);
+    }
+    ConstElementPtr stat_seconds = params->get("seconds");
+    if (!stat_seconds) {
+        reason = "Missing mandatory 'seconds' parameter.";
+        return (false);
+    }
+    if (stat_seconds->getType() != Element::integer) {
+        reason = "'seconds' parameter expected to be an integer.";
+        return (false);
+    }
+    ConstElementPtr stat_milliseconds = params->get("milliseconds");
+    if (!stat_milliseconds) {
+        reason = "Missing mandatory 'milliseconds' parameter.";
+        return (false);
+    }
+    if (stat_milliseconds->getType() != Element::integer) {
+        reason = "'milliseconds' parameter expected to be an integer.";
+        return (false);
+    }
+    int64_t hours = stat_hours->intValue();
+    int64_t minutes = stat_minutes->intValue();
+    int64_t seconds = stat_seconds->intValue();
+    int64_t milliseconds = stat_milliseconds->intValue();
+    duration = boost::posix_time::time_duration(hours,minutes,seconds,milliseconds);
+    return (true);
+}
+
+bool
+StatsMgr::getStatMaxSamples(const isc::data::ConstElementPtr& params,
+                      uint32_t& max_samples,
+                      std::string& reason) {
+    if (!params) {
+        reason = "Missing mandatory 'max_samples' parameter.";
+        return (false);
+    }
+    ConstElementPtr stat_max_samples = params->get("max_samples");
+    if (!stat_max_samples) {
+        reason = "Missing mandatory 'max_samples' parameter.";
+        return (false);
+    }
+    if (stat_max_samples->getType() != Element::integer) {
+        reason = "'max_samples' parameter expected to be an integer.";
+        return (false);
+    }
+
+    max_samples = stat_max_samples->intValue();
+    return (true);
+}
+
 };
 };
index 44401762b0a424c7d4a981c882d6171191f119c7..cb73e7e5db58b5664cd705b83a4161c7e4ab7fb6 100644 (file)
@@ -300,6 +300,52 @@ class StatsMgr : public boost::noncopyable {
     statisticRemoveHandler(const std::string& name,
                            const isc::data::ConstElementPtr& params);
 
+    /// @brief Handles statistic-setMaxSampleAge command
+    ///
+    /// This method handles statistic-setMaxSampleAge command, which set max_sample_age
+    /// limit of a given statistic and leaves max_sample_count disabled.
+    /// It expects five parameters stored in params map:
+    /// name: name-of-the-statistic
+    /// duration limit of gathering samples given in four parameters:
+    /// hours, minutes, seconds and milliseconds
+    ///
+    /// Example params structure:
+    /// {
+    ///     "name": "packets-received",
+    ///     "hours": 0,
+    ///     "minutes": 5,
+    ///     "seconds": 0,
+    ///     "milliseconds": 0
+    /// }
+    ///
+    /// @param name name of the command (ignored, should be "statistic-setMaxSampleAge")
+    /// @param params structure containing a map that contains "name" and "duration"
+    /// @return answer containing information about current statistic's limits
+    static isc::data::ConstElementPtr
+    statisticSetMaxSampleAgeHandler(const std::string& name,
+                            const isc::data::ConstElementPtr& params);
+
+    /// @brief Handles statistic-setMaxSampleAge command
+    ///
+    /// This method handles statistic-setMaxSampleAge command, which set max_sample_age
+    /// limit of a given statistic and leaves max_sample_age disabled.
+    /// It expects two parameters stored in params map:
+    /// name: name-of-the-statistic
+    /// duration: duration limit of gathering samples
+    ///
+    /// Example params structure:
+    /// {
+    ///     "name": "packets-received",
+    ///     "max_samples": 15
+    /// }
+    ///
+    /// @param name name of the command (ignored, should be "statistic-setMaxSampleCount")
+    /// @param params structure containing a map that contains "name" and "max_samples"
+    /// @return answer containing information about current statistic's limits
+    static isc::data::ConstElementPtr
+    statisticSetMaxSampleCountHandler(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
@@ -433,6 +479,45 @@ private:
                             std::string& name,
                             std::string& reason);
 
+    /// @brief Utility method that attempts to extract duration limit for
+    /// a given statistic
+    ///
+    /// This method attempts to extract duration limit for a given statistic
+    /// from the params structure.
+    /// It is expected to be a map that contains four 'duration' elements: 'hours',
+    /// 'minutes', 'seconds' and 'milliseconds'
+    /// all are of type int. If present as expected, statistic duration
+    /// limit is set and true is returned.
+    /// If any of these four parameters is missing or is of incorrect type,
+    /// the reason is specified in reason parameter and false is returned.
+    ///
+    /// @param params parameters structure received in command
+    /// @param duration [out] duration limit for the statistic (if no error detected)
+    /// @param reason [out] failure reason (if error is detected)
+    /// @return true (if everything is ok), false otherwise
+    static bool getStatDuration(const isc::data::ConstElementPtr& params,
+                            StatsDuration& duration,
+                            std::string& reason);
+
+    /// @brief Utility method that attempts to extract count limit for
+    /// a given statistic
+    ///
+    /// This method attempts to extract count limit for a given statistic
+    /// from the params structure.
+    /// It is expected to be a map that contains 'max_samples' element,
+    /// that is of type int. If present as expected, statistic count
+    /// limit (max_samples) is set and true is returned.
+    /// If missing or is of incorrect type, the reason is specified in reason
+    /// parameter and false is returned.
+    ///
+    /// @param params parameters structure received in command
+    /// @param max_samples [out] count limit for the statistic (if no error detected)
+    /// @param reason [out] failure reason (if error is detected)
+    /// @return true (if everything is ok), false otherwise
+    static bool getStatMaxSamples(const isc::data::ConstElementPtr& params,
+                            uint32_t& max_samples,
+                            std::string& reason);
+
     // This is a global context. All statistics will initially be stored here.
     StatContextPtr global_;
 };
index 29f9cc9e5724cd9205b2e585fa5682bccf198947..f0513bc75efd535093aa07da3a9921dbe472304e 100644 (file)
@@ -718,4 +718,132 @@ TEST_F(StatsMgrTest, commandRemoveAll) {
     EXPECT_EQ(0, StatsMgr::instance().count());
 }
 
+// This test checks whether statistic-setMaxSampleAge command really set
+// max_sample_age limit correctly.
+TEST_F(StatsMgrTest, commandSetMaxSampleAge) {
+    StatsMgr::instance().setValue("alpha", static_cast<int64_t>(1234));
+
+    ElementPtr params = Element::createMap();
+    params->set("name", Element::create("alpha"));
+    params->set("hours", Element::create(0));
+    params->set("minutes", Element::create(0));
+    params->set("seconds", Element::create(1));
+    params->set("milliseconds", Element::create(0));
+
+    ConstElementPtr rsp =
+        StatsMgr::instance().statisticSetMaxSampleAgeHandler("statistic-setMaxSampleAge", params);
+    int status_code;
+    ASSERT_NO_THROW(parseAnswer(status_code, rsp));
+    EXPECT_EQ(CONTROL_RESULT_SUCCESS, status_code);
+
+    // Now check if time limit work
+    for (uint32_t i = 0; i < 10; ++i) {
+        if (i == 5) {
+            sleep(1); // wait one second to force exceeding the time limit
+        }
+        StatsMgr::instance().setValue("alpha", static_cast<int64_t>(i));
+    }
+
+    // It should be equal
+    EXPECT_EQ(StatsMgr::instance().getSize("alpha"), 5);
+}
+
+// Test checks if statistic-setMaxSampleAge is able to handle:
+// - a request without parameters
+// - a request without at least one of duration parameters
+// - a request with missing statistic name
+// - a request for non-existing statistic.
+TEST_F(StatsMgrTest, commandSetMaxSampleAgeNegative) {
+
+    // Case 1: a request without parameters
+    ConstElementPtr rsp =
+        StatsMgr::instance().statisticSetMaxSampleAgeHandler("statistic-setMaxSampleAge", ElementPtr());
+    int status_code;
+    ASSERT_NO_THROW(parseAnswer(status_code, rsp));
+    EXPECT_EQ(status_code, CONTROL_RESULT_ERROR);
+
+    // Case 2: a request without at least one of duration parameters
+    ElementPtr params = Element::createMap();
+    params->set("seconds", Element::create(2));
+    params->set("milliseconds", Element::create(3));
+    rsp = StatsMgr::instance().statisticSetMaxSampleAgeHandler("statistic-setMaxSampleAge", params);
+    ASSERT_NO_THROW(parseAnswer(status_code, rsp));
+    EXPECT_EQ(status_code, CONTROL_RESULT_ERROR);
+
+    // Case 3: a request with missing statistic name
+    params = Element::createMap();
+    params->set("hours", Element::create(0));
+    params->set("minutes", Element::create(1));
+    params->set("seconds", Element::create(2));
+    params->set("milliseconds", Element::create(3));
+    rsp = StatsMgr::instance().statisticSetMaxSampleAgeHandler("statistic-setMaxSampleAge", params);
+    ASSERT_NO_THROW(parseAnswer(status_code, rsp));
+    EXPECT_EQ(status_code, CONTROL_RESULT_ERROR);
+
+    // Case 4: a request for non-existing statistic
+    params->set("name", Element::create("alpha"));
+    rsp = StatsMgr::instance().statisticSetMaxSampleAgeHandler("statistic-setMaxSampleAge", params);
+    EXPECT_EQ("{ \"result\": 1, \"text\": \"No 'alpha' statistic found\" }",
+              rsp->str());
+}
+
+// This test checks whether statistic-setMaxSampleCount command really set
+// max_sample_count limit correctly.
+TEST_F(StatsMgrTest, commandSetMaxSampleCount) {
+    StatsMgr::instance().setValue("alpha", static_cast<int64_t>(1234));
+
+    ElementPtr params = Element::createMap();
+    params->set("name", Element::create("alpha"));
+    params->set("max_samples", Element::create(15));
+
+    ConstElementPtr rsp =
+        StatsMgr::instance().statisticSetMaxSampleCountHandler("statistic-setMaxSampleCount", params);
+    int status_code;
+    ASSERT_NO_THROW(parseAnswer(status_code, rsp));
+    EXPECT_EQ(CONTROL_RESULT_SUCCESS, status_code);
+
+    // Now check if time limit work
+    for (uint32_t i = 0; i < 15; ++i) {
+        StatsMgr::instance().setValue("alpha", static_cast<int64_t>(i));
+    }
+
+    // It should be equal
+    EXPECT_EQ(StatsMgr::instance().getSize("alpha"), 15);
+}
+
+// Test checks if statistic-setMaxSampleAge is able to handle:
+// - a request without parameters
+// - a request without max_samples parameter
+// - a request with missing statistic name
+// - a request for non-existing statistic.
+TEST_F(StatsMgrTest, commandSetMaxSampleCountNegative) {
+
+    // Case 1: a request without parameters
+    ConstElementPtr rsp =
+        StatsMgr::instance().statisticSetMaxSampleCountHandler("statistic-setMaxSampleCount", ElementPtr());
+    int status_code;
+    ASSERT_NO_THROW(parseAnswer(status_code, rsp));
+    EXPECT_EQ(status_code, CONTROL_RESULT_ERROR);
+
+    // Case 2: a request without max_samples parameter
+    ElementPtr params = Element::createMap();
+    params->set("name", Element::create("beta"));
+    rsp = StatsMgr::instance().statisticSetMaxSampleCountHandler("statistic-setMaxSampleCount", params);
+    ASSERT_NO_THROW(parseAnswer(status_code, rsp));
+    EXPECT_EQ(status_code, CONTROL_RESULT_ERROR);
+
+    // Case 3: a request with missing statistic name
+    params = Element::createMap();
+    params->set("max_samples", Element::create(10));
+    rsp = StatsMgr::instance().statisticSetMaxSampleCountHandler("statistic-setMaxSampleCount", params);
+    ASSERT_NO_THROW(parseAnswer(status_code, rsp));
+    EXPECT_EQ(status_code, CONTROL_RESULT_ERROR);
+
+    // Case 4: a request for non-existing statistic
+    params->set("name", Element::create("alpha"));
+    rsp = StatsMgr::instance().statisticSetMaxSampleCountHandler("statistic-setMaxSampleCount", params);
+    EXPECT_EQ("{ \"result\": 1, \"text\": \"No 'alpha' statistic found\" }",
+              rsp->str());
+}
+
 };