From: Franciszek Gorski Date: Fri, 5 Jul 2019 15:18:50 +0000 (+0200) Subject: New command for manipulating Observation's limits X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=bb46b20dfcec1991142cc951a61006f8de4504c3;p=thirdparty%2Fkea.git New command for manipulating Observation's limits --- diff --git a/src/bin/dhcp4/ctrl_dhcp4_srv.cc b/src/bin/dhcp4/ctrl_dhcp4_srv.cc index 3964a1a3fb..c983c34dd5 100644 --- a/src/bin/dhcp4/ctrl_dhcp4_srv.cc +++ b/src/bin/dhcp4/ctrl_dhcp4_srv.cc @@ -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 (...) { diff --git a/src/bin/dhcp6/ctrl_dhcp6_srv.cc b/src/bin/dhcp6/ctrl_dhcp6_srv.cc index 8cb2737cce..41be37fdaa 100644 --- a/src/bin/dhcp6/ctrl_dhcp6_srv.cc +++ b/src/bin/dhcp6/ctrl_dhcp6_srv.cc @@ -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() { diff --git a/src/lib/stats/stats_mgr.cc b/src/lib/stats/stats_mgr.cc index 3ae30e24ed..b32c0ab360 100644 --- a/src/lib/stats/stats_mgr.cc +++ b/src/lib/stats/stats_mgr.cc @@ -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); +} + }; }; diff --git a/src/lib/stats/stats_mgr.h b/src/lib/stats/stats_mgr.h index 44401762b0..cb73e7e5db 100644 --- a/src/lib/stats/stats_mgr.h +++ b/src/lib/stats/stats_mgr.h @@ -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_; }; diff --git a/src/lib/stats/tests/stats_mgr_unittest.cc b/src/lib/stats/tests/stats_mgr_unittest.cc index 29f9cc9e57..f0513bc75e 100644 --- a/src/lib/stats/tests/stats_mgr_unittest.cc +++ b/src/lib/stats/tests/stats_mgr_unittest.cc @@ -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(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(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(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(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()); +} + };