Browse Source

[3974] Implemented configuration parser for lease expiration config.

Marcin Siodelski 9 years ago
parent
commit
5e4ab4506a

+ 2 - 0
src/lib/dhcpsrv/Makefile.am

@@ -132,6 +132,8 @@ libkea_dhcpsrv_la_SOURCES += parsers/dbaccess_parser.cc
 libkea_dhcpsrv_la_SOURCES += parsers/dbaccess_parser.h
 libkea_dhcpsrv_la_SOURCES += parsers/dhcp_parsers.cc
 libkea_dhcpsrv_la_SOURCES += parsers/dhcp_parsers.h
+libkea_dhcpsrv_la_SOURCES += parsers/expiration_config_parser.cc
+libkea_dhcpsrv_la_SOURCES += parsers/expiration_config_parser.h
 libkea_dhcpsrv_la_SOURCES += parsers/host_reservation_parser.cc
 libkea_dhcpsrv_la_SOURCES += parsers/host_reservation_parser.h
 libkea_dhcpsrv_la_SOURCES += parsers/host_reservations_list_parser.h

+ 80 - 0
src/lib/dhcpsrv/parsers/expiration_config_parser.cc

@@ -0,0 +1,80 @@
+// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <cc/data.h>
+#include <dhcpsrv/cfg_expiration.h>
+#include <dhcpsrv/cfgmgr.h>
+#include <dhcpsrv/parsers/expiration_config_parser.h>
+#include <boost/foreach.hpp>
+
+using namespace isc::data;
+
+namespace isc {
+namespace dhcp {
+
+ExpirationConfigParser::ExpirationConfigParser()
+    : DhcpConfigParser() {
+}
+
+void
+ExpirationConfigParser::build(ConstElementPtr expiration_config) {
+    CfgExpirationPtr cfg = CfgMgr::instance().getStagingCfg()->getCfgExpiration();
+
+    BOOST_FOREACH(ConfigPair config_element, expiration_config->mapValue()) {
+
+        // Get parameter name and value.
+        std::string param_name = config_element.first;
+        ConstElementPtr param_value = config_element.second;
+
+        try {
+            // Set configuration parameters.
+            if (param_name == "reclaim-timer-wait-time") {
+                cfg->setReclaimTimerWaitTime(param_value->intValue());
+
+            } else if (param_name == "flush-reclaimed-timer-wait-time") {
+                cfg->setFlushReclaimedTimerWaitTime(param_value->intValue());
+
+            } else if (param_name == "hold-reclaimed-time") {
+                cfg->setHoldReclaimedTime(param_value->intValue());
+
+            } else if (param_name == "max-reclaim-leases") {
+                cfg->setMaxReclaimLeases(param_value->intValue());
+
+            } else if (param_name == "max-reclaim-time") {
+                cfg->setMaxReclaimTime(param_value->intValue());
+
+            } else if (param_name == "unwarned-reclaim-cycles") {
+                cfg->setUnwarnedReclaimCycles(param_value->intValue());
+
+            } else {
+                isc_throw(DhcpConfigError, "unsupported parameter '"
+                          << param_name << "'");
+            }
+
+        } catch (const std::exception& ex) {
+            // Append position of the configuration parameter to the error
+            // message.
+            isc_throw(DhcpConfigError, ex.what() << " ("
+                      << param_value->getPosition() << ")");
+        }
+    }
+}
+
+void
+ExpirationConfigParser::commit() {
+    // Nothing to do.
+}
+
+} // end of namespace isc::dhcp
+} // end of namespace isc

+ 69 - 0
src/lib/dhcpsrv/parsers/expiration_config_parser.h

@@ -0,0 +1,69 @@
+// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef EXPIRATION_CONFIG_PARSER_H
+#define EXPIRATION_CONFIG_PARSER_H
+
+#include <dhcpsrv/parsers/dhcp_config_parser.h>
+
+namespace isc {
+namespace dhcp {
+
+
+/// @brief Parser for the configuration parameters pertaining to the
+/// processing of expired leases.
+///
+/// This parser iterates over parameters stored in the map and tries to
+/// set the appropriate values in the @c CfgExpiration object of the
+/// Configuration Manager.
+///
+/// Currently supported parameters are:
+/// - reclaim-timer-wait-time,
+/// - flush-reclaimed-timer-wait-time,
+/// - hold-reclaimed-time,
+/// - max-reclaim-leases,
+/// - max-reclaim-time,
+/// - unwarned-reclaim-cycles.
+///
+/// These parameters are optional and the default values are used for
+/// those that aren't specified.
+///
+/// The parser checks if the values of the specified parameters are within
+/// the allowed ranges and throws exception if they are. Each parameter
+/// has a corresponding maximum value defined in the @c CfgExpiration class.
+/// None of them may be negative.
+class ExpirationConfigParser : public DhcpConfigParser {
+public:
+
+    /// @brief Constructor
+    ExpirationConfigParser();
+
+    /// @brief Parses parameters in the JSON map, pertaining to the processing
+    /// of the expired leases.
+    ///
+    /// @param value pointer to the content of parsed values
+    ///
+    /// @throw DhcpConfigError if unknown parameter specified or the
+    /// parameter contains invalid value..
+    virtual void build(isc::data::ConstElementPtr value);
+
+    /// @brief Does nothing.
+    virtual void commit();
+
+};
+
+} // end of namespace isc::dhcp
+} // end of namespace isc
+
+#endif // EXPIRATION_CONFIG_PARSER_H

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

@@ -81,6 +81,7 @@ libdhcpsrv_unittests_SOURCES += d2_client_unittest.cc
 libdhcpsrv_unittests_SOURCES += d2_udp_unittest.cc
 libdhcpsrv_unittests_SOURCES += daemon_unittest.cc
 libdhcpsrv_unittests_SOURCES += dbaccess_parser_unittest.cc
+libdhcpsrv_unittests_SOURCES += expiration_config_parser_unittest.cc
 libdhcpsrv_unittests_SOURCES += host_mgr_unittest.cc
 libdhcpsrv_unittests_SOURCES += host_unittest.cc
 libdhcpsrv_unittests_SOURCES += host_reservation_parser_unittest.cc

+ 263 - 0
src/lib/dhcpsrv/tests/expiration_config_parser_unittest.cc

@@ -0,0 +1,263 @@
+// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+
+#include <cc/data.h>
+#include <dhcpsrv/cfgmgr.h>
+#include <dhcpsrv/cfg_expiration.h>
+#include <dhcpsrv/parsers/expiration_config_parser.h>
+#include <gtest/gtest.h>
+#include <sstream>
+#include <stdint.h>
+#include <string>
+
+using namespace isc::data;
+using namespace isc::dhcp;
+
+namespace {
+
+/// @brief Test fixture class for @c ExpirationConfigParser.
+class ExpirationConfigParserTest : public ::testing::Test {
+protected:
+
+    /// @brief Setup for each test.
+    ///
+    /// Clears the configuration in the @c CfgMgr.
+    virtual void SetUp();
+
+    /// @brief Cleans up after each test.
+    ///
+    /// Clears the configuration in the @c CfgMgr.
+    virtual void TearDown();
+
+    /// @brief Include a specified parameter in the configuration.
+    ///
+    /// If the specified parameter already exists, its value is replaced.
+    ///
+    /// @param param_name Parameter name.
+    /// @param value Parameter value.
+    void addParam(const std::string& param_name, const int64_t value);
+
+    /// @brief Creates configuration and parses it with the parser under test.
+    ///
+    /// This method creates the JSON configuration form the parameters
+    /// specified using the @c ExpirationConfigParserTest::addParam method.
+    /// It then uses the parser to parse this configuration. Any exceptions
+    /// emitted by the parser are propagated to the caller (they aren't
+    /// caught by this method).
+    ///
+    /// @return Pointer to the parsed configuration.
+    CfgExpirationPtr renderConfig() const;
+
+    /// @brief Tests that the out of range parameter value is not accepted.
+    ///
+    /// This test checks that the negative value and the value which is
+    /// greater than the maximum for the given parameter is not accepted.
+    ///
+    /// @param param Parameter name.
+    /// @param max_value Maximum value allowed for the parameter.
+    void testOutOfRange(const std::string& param, const uint64_t max_value);
+
+private:
+
+    /// @brief Holds configuration parameters specified for a test.
+    std::map<std::string, int64_t> config_params_;
+
+};
+
+void
+ExpirationConfigParserTest::SetUp() {
+    CfgMgr::instance().clear();
+}
+
+void
+ExpirationConfigParserTest::TearDown() {
+    CfgMgr::instance().clear();
+}
+
+void
+ExpirationConfigParserTest::addParam(const std::string& param_name,
+                                     const int64_t value) {
+    config_params_[param_name] = value;
+}
+
+CfgExpirationPtr
+ExpirationConfigParserTest::renderConfig() const {
+    std::ostringstream s;
+    // Create JSON configuration from the parameters in the map.
+    s << "{";
+    for (std::map<std::string, int64_t>::const_iterator param =
+             config_params_.begin(); param != config_params_.end();
+         ++param) {
+        // Include comma sign if we're at the subsequent parameter.
+        if (std::distance(config_params_.begin(), param) > 0) {
+            s << ",";
+        }
+        s << "\"" << param->first << "\": " << param->second;
+    }
+    s << "}";
+
+    ElementPtr config_element = Element::fromJSON(s.str());
+
+    // Parse the configuration. This may emit exceptions.
+    ExpirationConfigParser parser;
+    parser.build(config_element);
+
+    // No exception so return configuration.
+    return (CfgMgr::instance().getStagingCfg()->getCfgExpiration());
+}
+
+void
+ExpirationConfigParserTest::testOutOfRange(const std::string& param,
+                                           const uint64_t max_value) {
+    // Remove any existing parameters which would influence the
+    // behavior of the test.
+    config_params_.clear();
+
+    // Negative value is not allowed.
+    addParam(param, -3);
+    EXPECT_THROW(renderConfig(), DhcpConfigError)
+        << "test for negative value of '" << param << "' failed";
+
+    // Value greater than maximum is not allowed.
+    addParam(param, max_value + 1);
+    EXPECT_THROW(renderConfig(), DhcpConfigError)
+        << "test for out of range value of '" << param << "' failed";
+
+    // Value in range should be accepted.
+    addParam(param, max_value);
+    EXPECT_NO_THROW(renderConfig())
+        << "test for in range value of '" << param << "' failed";
+}
+
+
+// This test verifies that all parameters for the expiration may be configured.
+TEST_F(ExpirationConfigParserTest, allParameters) {
+    // Create configuration which overrides default values of all parameters.
+    addParam("reclaim-timer-wait-time", 20);
+    addParam("flush-reclaimed-timer-wait-time", 35);
+    addParam("hold-reclaimed-time", 1800);
+    addParam("max-reclaim-leases", 50);
+    addParam("max-reclaim-time", 100);
+    addParam("unwarned-reclaim-cycles", 10);
+
+    CfgExpirationPtr cfg;
+    ASSERT_NO_THROW(cfg = renderConfig());
+    EXPECT_EQ(20, cfg->getReclaimTimerWaitTime());
+    EXPECT_EQ(35, cfg->getFlushReclaimedTimerWaitTime());
+    EXPECT_EQ(1800, cfg->getHoldReclaimedTime());
+    EXPECT_EQ(50, cfg->getMaxReclaimLeases());
+    EXPECT_EQ(100, cfg->getMaxReclaimTime());
+    EXPECT_EQ(10, cfg->getUnwarnedReclaimCycles());
+}
+
+// This test verifies that default values are used if no parameter is
+// specified.
+TEST_F(ExpirationConfigParserTest, noParameters) {
+    CfgExpirationPtr cfg;
+    ASSERT_NO_THROW(cfg = renderConfig());
+    EXPECT_EQ(CfgExpiration::DEFAULT_RECLAIM_TIMER_WAIT_TIME,
+              cfg->getReclaimTimerWaitTime());
+    EXPECT_EQ(CfgExpiration::DEFAULT_FLUSH_RECLAIMED_TIMER_WAIT_TIME,
+              cfg->getFlushReclaimedTimerWaitTime());
+    EXPECT_EQ(CfgExpiration::DEFAULT_HOLD_RECLAIMED_TIME,
+              cfg->getHoldReclaimedTime());
+    EXPECT_EQ(CfgExpiration::DEFAULT_MAX_RECLAIM_LEASES,
+              cfg->getMaxReclaimLeases());
+    EXPECT_EQ(CfgExpiration::DEFAULT_MAX_RECLAIM_TIME,
+              cfg->getMaxReclaimTime());
+    EXPECT_EQ(CfgExpiration::DEFAULT_UNWARNED_RECLAIM_CYCLES,
+              cfg->getUnwarnedReclaimCycles());
+}
+
+// This test verifies that a subset of parameters may be specified and
+// that default values are used for those that aren't specified.
+TEST_F(ExpirationConfigParserTest, someParameters) {
+    addParam("reclaim-timer-wait-time", 15);
+    addParam("hold-reclaimed-time", 2000);
+    addParam("max-reclaim-time", 200);
+
+    CfgExpirationPtr cfg;
+    ASSERT_NO_THROW(cfg = renderConfig());
+    EXPECT_EQ(15, cfg->getReclaimTimerWaitTime());
+    EXPECT_EQ(CfgExpiration::DEFAULT_FLUSH_RECLAIMED_TIMER_WAIT_TIME,
+              cfg->getFlushReclaimedTimerWaitTime());
+    EXPECT_EQ(2000, cfg->getHoldReclaimedTime());
+    EXPECT_EQ(CfgExpiration::DEFAULT_MAX_RECLAIM_LEASES,
+              cfg->getMaxReclaimLeases());
+    EXPECT_EQ(200, cfg->getMaxReclaimTime());
+    EXPECT_EQ(CfgExpiration::DEFAULT_UNWARNED_RECLAIM_CYCLES,
+              cfg->getUnwarnedReclaimCycles());
+}
+
+// This test verifies that another subset of parameters may be specified
+// and that default values are used for those that aren't specified.
+TEST_F(ExpirationConfigParserTest, otherParameters) {
+    addParam("flush-reclaimed-timer-wait-time", 50);
+    addParam("max-reclaim-leases", 60);
+    addParam("unwarned-reclaim-cycles", 20);
+
+    CfgExpirationPtr cfg;
+    ASSERT_NO_THROW(cfg = renderConfig());
+
+    EXPECT_EQ(CfgExpiration::DEFAULT_RECLAIM_TIMER_WAIT_TIME,
+              cfg->getReclaimTimerWaitTime());
+    EXPECT_EQ(50, cfg->getFlushReclaimedTimerWaitTime());
+    EXPECT_EQ(CfgExpiration::DEFAULT_HOLD_RECLAIMED_TIME,
+              cfg->getHoldReclaimedTime());
+    EXPECT_EQ(60, cfg->getMaxReclaimLeases());
+    EXPECT_EQ(CfgExpiration::DEFAULT_MAX_RECLAIM_TIME,
+              cfg->getMaxReclaimTime());
+    EXPECT_EQ(20, cfg->getUnwarnedReclaimCycles());
+}
+
+// This test verifies that the exception is thrown if unsupported
+// parameter is specified.
+TEST_F(ExpirationConfigParserTest, invalidParameter) {
+   addParam("reclaim-timer-wait-time", 20);
+   addParam("invalid-parameter", 20);
+
+   EXPECT_THROW(renderConfig(), DhcpConfigError);
+}
+
+// This test verifies that negative parameter values are not allowed.
+TEST_F(ExpirationConfigParserTest, outOfRangeValues) {
+    testOutOfRange("reclaim-timer-wait-time",
+                   CfgExpiration::LIMIT_RECLAIM_TIMER_WAIT_TIME);
+    testOutOfRange("flush-reclaimed-timer-wait-time",
+                   CfgExpiration::LIMIT_FLUSH_RECLAIMED_TIMER_WAIT_TIME);
+    testOutOfRange("hold-reclaimed-time",
+                   CfgExpiration::LIMIT_HOLD_RECLAIMED_TIME);
+    testOutOfRange("max-reclaim-leases",
+                   CfgExpiration::LIMIT_MAX_RECLAIM_LEASES);
+    testOutOfRange("max-reclaim-time",
+                   CfgExpiration::LIMIT_MAX_RECLAIM_TIME);
+    testOutOfRange("unwarned-reclaim-cycles",
+                   CfgExpiration::LIMIT_UNWARNED_RECLAIM_CYCLES);
+}
+
+// This test verifies that it is not allowed to specify a value as
+// a text.
+TEST_F(ExpirationConfigParserTest, notNumberValue) {
+    // The value should not be in quotes.
+    std::string config = "{ \"reclaim-timer-wait-time\": \"10\" }";
+    ElementPtr config_element = Element::fromJSON(config);
+
+    // Parse the configuration. It should throw exception.
+    ExpirationConfigParser parser;
+    EXPECT_THROW(parser.build(config_element), DhcpConfigError);
+}
+
+} // end of anonymous namespace