From: Marcin Siodelski Date: Mon, 18 Aug 2014 11:17:35 +0000 (+0200) Subject: [3477] Summary of subnets returned by the Configuration object as text. X-Git-Tag: trac3482_base~29^2~4 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=32b9a1362f211a1cafffdc157e01c994679db896;p=thirdparty%2Fkea.git [3477] Summary of subnets returned by the Configuration object as text. --- diff --git a/src/lib/dhcpsrv/Makefile.am b/src/lib/dhcpsrv/Makefile.am index b10d269a4f..68deaa5d14 100644 --- a/src/lib/dhcpsrv/Makefile.am +++ b/src/lib/dhcpsrv/Makefile.am @@ -60,7 +60,7 @@ libkea_dhcpsrv_la_SOURCES += lease.cc lease.h libkea_dhcpsrv_la_SOURCES += lease_mgr.cc lease_mgr.h libkea_dhcpsrv_la_SOURCES += lease_mgr_factory.cc lease_mgr_factory.h libkea_dhcpsrv_la_SOURCES += logging.cc logging.h -libkea_dhcpsrv_la_SOURCES += configuration.h +libkea_dhcpsrv_la_SOURCES += configuration.h configuration.cc libkea_dhcpsrv_la_SOURCES += memfile_lease_mgr.cc memfile_lease_mgr.h if HAVE_MYSQL diff --git a/src/lib/dhcpsrv/cfgmgr.h b/src/lib/dhcpsrv/cfgmgr.h index b572dd8265..9c70a621b1 100644 --- a/src/lib/dhcpsrv/cfgmgr.h +++ b/src/lib/dhcpsrv/cfgmgr.h @@ -250,12 +250,12 @@ public: /// completely new? void deleteSubnets6(); - /// @brief returns const reference to all subnets6 + /// @brief Returns pointer to the collection of all IPv4 subnets. /// /// This is used in a hook (subnet4_select), where the hook is able /// to choose a different subnet. Server code has to offer a list /// of possible choices (i.e. all subnets). - /// @return a pointer to const Subnet6 collection + /// @return a pointer to const Subnet4 collection const Subnet4Collection* getSubnets4() const { return (&subnets4_); } diff --git a/src/lib/dhcpsrv/configuration.cc b/src/lib/dhcpsrv/configuration.cc new file mode 100644 index 0000000000..92b2c9cf25 --- /dev/null +++ b/src/lib/dhcpsrv/configuration.cc @@ -0,0 +1,59 @@ +// Copyright (C) 2014 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 +#include +#include + +namespace isc { +namespace dhcp { + +std::string +Configuration::getConfigSummary(const uint32_t selection) const { + std::ostringstream s; + size_t subnets_num; + if ((selection & CFGSEL_SUBNET4) == CFGSEL_SUBNET4) { + subnets_num = CfgMgr::instance().getSubnets4()->size(); + if (subnets_num > 0) { + s << "added IPv4 subnets: " << subnets_num; + } else { + s << "no IPv4 subnets!"; + } + s << "; "; + } + + if ((selection & CFGSEL_SUBNET6) == CFGSEL_SUBNET6) { + subnets_num = CfgMgr::instance().getSubnets6()->size(); + if (subnets_num > 0) { + s << "added IPv6 subnets: " << subnets_num; + } else { + s << "no IPv6 subnets!"; + } + s << "; "; + } + + if (s.tellp() == 0) { + s << "no config details available"; + } + + std::string summary = s.str(); + size_t last_separator_pos = summary.find_last_of(";"); + if (last_separator_pos == summary.length() - 2) { + summary.erase(last_separator_pos); + } + return (summary); +} + +} +} diff --git a/src/lib/dhcpsrv/configuration.h b/src/lib/dhcpsrv/configuration.h index 860644b730..4294129165 100644 --- a/src/lib/dhcpsrv/configuration.h +++ b/src/lib/dhcpsrv/configuration.h @@ -23,6 +23,8 @@ namespace isc { namespace dhcp { +class CfgMgr; + /// @brief Defines single logging destination /// /// This structure is used to keep log4cplus configuration parameters. @@ -33,7 +35,7 @@ struct LoggingDestination { /// Values accepted are: stdout, stderr, syslog, syslog:name. /// Any other destination will be considered a file name. std::string output_; - + /// @brief Maximum number of log files in rotation int maxver_; @@ -53,10 +55,10 @@ struct LoggingDestination { /// "maxver": 8, /// "maxsize": 204800 /// } -/// ], +/// ], /// "severity": "WARN", /// "debuglevel": 99 -/// }, +/// }, struct LoggingInfo { /// @brief logging name @@ -82,8 +84,31 @@ typedef std::vector LoggingInfoStorage; /// @todo Migrate all other configuration parameters from cfgmgr.h here struct Configuration { + static const uint16_t CFGSEL_NONE = 0x00000000; + static const uint16_t CFGSEL_SUBNET4 = 0x00000001; + static const uint16_t CFGSEL_SUBNET6 = 0x00000002; + static const uint16_t CFGSEL_ALL4 = 0x00000001; + static const uint16_t CFGSEL_ALL6 = 0x00000002; + static const uint16_t CFGSEL_ALL = 0x00000003; + /// @brief logging specific information LoggingInfoStorage logging_info_; + + /// @brief Returns summary of the configuration in the textual format. + /// + /// This method returns the brief text describing the current configuration. + /// It may be use for logging purposes, e.g. when the new configuration is + /// committed to notify a user about the changes in configuration. + /// + /// @todo Currently this method uses @c CfgMgr accessors to get the + /// configuration parameters. Once these parameters are migrated from the + /// @c CfgMgr this method will have to be modified accordingly. + /// + /// @param selection Is a bitfield which describes the parts of the + /// configuration to be returned. + /// + /// @return Summary of the configuration in the textual format. + std::string getConfigSummary(const uint32_t selection) const; }; /// @brief pointer to the configuration diff --git a/src/lib/dhcpsrv/tests/configuration_unittest.cc b/src/lib/dhcpsrv/tests/configuration_unittest.cc index 8daba2fbac..6770595c67 100644 --- a/src/lib/dhcpsrv/tests/configuration_unittest.cc +++ b/src/lib/dhcpsrv/tests/configuration_unittest.cc @@ -14,9 +14,12 @@ #include +#include #include +#include #include +using namespace isc::asiolink; using namespace isc::dhcp; // Those are the tests for Configuration storage. Right now they are minimal, @@ -25,18 +28,126 @@ using namespace isc::dhcp; namespace { -// Check that by default there are no logging entries -TEST(ConfigurationTest, basic) { - Configuration x; +/// @brief Number of IPv4 and IPv6 subnets to be created for a test. +const int TEST_SUBNETS_NUM = 3; + +/// @brief Test fixture class for testing configuration data storage. +class ConfigurationTest : public ::testing::Test { +public: + /// @brief Constructor. + /// + /// Creates IPv4 and IPv6 subnets for unit test. The number of subnets + /// is @c TEST_SUBNETS_NUM for IPv4 and IPv6 each. + ConfigurationTest() { + // Remove any subnets dangling from previous unit tests. + clearSubnets(); + // Create IPv4 subnets. + for (int i = 0; i < TEST_SUBNETS_NUM; ++i) { + // Default triplet carried undefined value. + Triplet def_triplet; + // Create a collection of subnets: 192.0.X.0/24 where X is + // 0, 1, 2 etc. + Subnet4Ptr subnet(new Subnet4(IOAddress(0xC0000000 | (i << 2)), + 24, def_triplet, def_triplet, + 4000)); + test_subnets4_.push_back(subnet); + } + // Create IPv6 subnets. + for (int i = 0; i < TEST_SUBNETS_NUM; ++i) { + // This is a base prefix. All other prefixes will be created by + // modifying this one. + IOAddress prefix("2001:db8:1::0"); + std::vector prefix_bytes = prefix.toBytes(); + // Modify 5th byte of the prefix, so 2001:db8:1::0 becomes + // 2001:db8:2::0 etc. + ++prefix_bytes[5]; + prefix = IOAddress::fromBytes(prefix.getFamily(), &prefix_bytes[0]); + Subnet6Ptr subnet(new Subnet6(prefix, 64, 1000, 2000, 3000, 4000)); + test_subnets6_.push_back(subnet); + } + } + + /// @brief Destructor. + /// + /// Removes any dangling configuration. + virtual ~ConfigurationTest() { + clearSubnets(); + } + + /// @brief Convenience function which adds IPv4 subnet to the configuration. + /// + /// @param index Index of the subnet in the @c test_subnets4_ collection + /// which should be added to the configuration. The configuration is stored + /// in the @ conf_ member. This value must be lower than + /// @c TEST_SUBNETS_NUM. + /// + /// @todo Until the subnets configuration is migrated from the @c CfgMgr to + /// the @c Configuration object, this function adds the subnet to the + /// @c CfgMgr. Once, the subnet configuration is held in the + /// @c Configuration this function must be modified to store the subnets in + /// the @c conf_ object. + void addSubnet4(const unsigned int index); + + /// @brief Convenience function which adds IPv6 subnet to the configuration. + /// + /// @param index Index of the subnet in the @c test_subnets6_ collection + /// which should be added to the configuration. The configuration is stored + /// in the @ conf_ member. This value must be lower than + /// @c TEST_SUBNETS_NUM. + /// + /// @todo Until the subnets configuration is migrated from the @c CfgMgr to + /// the @c Configuration object, this function adds the subnet to the + /// @c CfgMgr. Once, the subnet configuration is held in the + /// @c Configuration this function must be modified to store the subnets in + /// @c conf_ object. + void addSubnet6(const unsigned int index); + + /// @brief Removes all subnets from the configuration. + /// + /// @todo Modify this function once the subnet configuration is migrated + /// from @c CfgMgr to @c Configuration. + void clearSubnets(); + + /// @brief Stores configuration. + Configuration conf_; + /// @brief A collection of IPv4 subnets used by unit tests. + Subnet4Collection test_subnets4_; + /// @brief A collection of IPv6 subnets used by unit tests. + Subnet6Collection test_subnets6_; + +}; + +void +ConfigurationTest::addSubnet4(const unsigned int index) { + if (index >= TEST_SUBNETS_NUM) { + FAIL() << "Subnet index " << index << "out of range (0.." + << TEST_SUBNETS_NUM << "): " << "unable to add IPv4 subnet"; + } + CfgMgr::instance().addSubnet4(test_subnets4_[index]); +} - EXPECT_TRUE(x.logging_info_.empty()); +void +ConfigurationTest::addSubnet6(const unsigned int index) { + if (index >= TEST_SUBNETS_NUM) { + FAIL() << "Subnet index " << index << "out of range (0.." + << TEST_SUBNETS_NUM << "): " << "unable to add IPv6 subnet"; + } + CfgMgr::instance().addSubnet6(test_subnets6_[index]); } -// Check that Configuration can store logging information. -TEST(ConfigurationTest, loggingInfo) { +void +ConfigurationTest::clearSubnets() { + CfgMgr::instance().deleteSubnets4(); + CfgMgr::instance().deleteSubnets6(); +} - Configuration x; +// Check that by default there are no logging entries +TEST_F(ConfigurationTest, basic) { + EXPECT_TRUE(conf_.logging_info_.empty()); +} +// Check that Configuration can store logging information. +TEST_F(ConfigurationTest, loggingInfo) { LoggingInfo log1; log1.name_ = "foo"; log1.severity_ = isc::log::WARN; @@ -49,15 +160,69 @@ TEST(ConfigurationTest, loggingInfo) { log1.destinations_.push_back(dest); - x.logging_info_.push_back(log1); + conf_.logging_info_.push_back(log1); - EXPECT_EQ("foo", x.logging_info_[0].name_); - EXPECT_EQ(isc::log::WARN, x.logging_info_[0].severity_); - EXPECT_EQ(77, x.logging_info_[0].debuglevel_); + EXPECT_EQ("foo", conf_.logging_info_[0].name_); + EXPECT_EQ(isc::log::WARN, conf_.logging_info_[0].severity_); + EXPECT_EQ(77, conf_.logging_info_[0].debuglevel_); + + EXPECT_EQ("some-logfile.txt", conf_.logging_info_[0].destinations_[0].output_); + EXPECT_EQ(5, conf_.logging_info_[0].destinations_[0].maxver_); + EXPECT_EQ(2097152, conf_.logging_info_[0].destinations_[0].maxsize_); +} - EXPECT_EQ("some-logfile.txt", x.logging_info_[0].destinations_[0].output_); - EXPECT_EQ(5, x.logging_info_[0].destinations_[0].maxver_); - EXPECT_EQ(2097152, x.logging_info_[0].destinations_[0].maxsize_); +// Check that the configuration summary including information about added +// subnets is returned. +TEST_F(ConfigurationTest, summarySubnets) { + EXPECT_EQ("no config details available", + conf_.getConfigSummary(Configuration::CFGSEL_NONE)); + + // Initially, there are no subnets added but it should be explicitly + // reported when we query for information about the subnets. + EXPECT_EQ("no IPv4 subnets!; no IPv6 subnets!", + conf_.getConfigSummary(Configuration::CFGSEL_ALL)); + + // If we just want information about IPv4 subnets, there should be no + // mention of IPv6 subnets, even though there are none added. + EXPECT_EQ("no IPv4 subnets!", + conf_.getConfigSummary(Configuration::CFGSEL_ALL4)); + + // If we just want information about IPv6 subnets, there should be no + // mention of IPv4 subnets, even though there are none added. + EXPECT_EQ("no IPv6 subnets!", + conf_.getConfigSummary(Configuration::CFGSEL_ALL6)); + + // Add IPv4 subnet and make sure it is reported. + addSubnet4(0); + EXPECT_EQ("added IPv4 subnets: 1", + conf_.getConfigSummary(Configuration::CFGSEL_ALL4)); + EXPECT_EQ("added IPv4 subnets: 1; no IPv6 subnets!", + conf_.getConfigSummary(Configuration::CFGSEL_ALL)); + + // Add IPv6 subnet and make sure it is reported. + addSubnet6(0); + EXPECT_EQ("added IPv6 subnets: 1", + conf_.getConfigSummary(Configuration::CFGSEL_ALL6)); + EXPECT_EQ("added IPv4 subnets: 1; added IPv6 subnets: 1", + conf_.getConfigSummary(Configuration::CFGSEL_ALL)); + + // Add one more subnet and make sure the bumped value is only + // for IPv4, but not for IPv6. + addSubnet4(1); + EXPECT_EQ("added IPv4 subnets: 2; added IPv6 subnets: 1", + conf_.getConfigSummary(Configuration::CFGSEL_ALL)); + EXPECT_EQ("added IPv4 subnets: 2", + conf_.getConfigSummary(Configuration::CFGSEL_ALL4)); + + addSubnet6(1); + EXPECT_EQ("added IPv4 subnets: 2; added IPv6 subnets: 2", + conf_.getConfigSummary(Configuration::CFGSEL_ALL)); + + // Remove all subnets and make sure that there are no reported subnets + // back again. + clearSubnets(); + EXPECT_EQ("no IPv4 subnets!; no IPv6 subnets!", + conf_.getConfigSummary(Configuration::CFGSEL_ALL)); } } // end of anonymous namespace