diff --git a/src/lib/cc/stamped_value.h b/src/lib/cc/stamped_value.h index 4e0a2a46c0ee78998f2b0860b3494330c5b5ede8..7bb6ba5ab22d3ed0d8f6d0419b2d79e2bc6615bf 100644 --- a/src/lib/cc/stamped_value.h +++ b/src/lib/cc/stamped_value.h @@ -8,6 +8,10 @@ #define STAMPED_VALUE_H #include +#include +#include +#include +#include #include #include #include @@ -20,9 +24,6 @@ class StampedValue; /// @brief Pointer to the stamped value. typedef boost::shared_ptr StampedValuePtr; -/// @brief Collection of pointers to values. -typedef std::vector StampedValueCollection; - /// @brief This class represents string or signed integer configuration /// element associated with the modification timestamp. /// @@ -91,8 +92,43 @@ private: std::string value_; }; -/// @brief Pointer to the stamped value. -typedef boost::shared_ptr StampedValuePtr; +/// @name Definition of the multi index container for @c StampedValue. +/// +//@{ + +/// @brief Tag for the index for access by value name. +struct StampedValueNameIndexTag { }; + +/// @brief Tag for the index for access by modification time. +struct StampedValueModificationTimeIndexTag { }; + +/// @brief Multi index container for @c StampedValue. +typedef boost::multi_index_container< + StampedValuePtr, + boost::multi_index::indexed_by< + // Index used to access value by name. + boost::multi_index::hashed_non_unique< + boost::multi_index::tag, + boost::multi_index::const_mem_fun< + StampedValue, + std::string, + &StampedValue::getName + > + >, + + // Index used to access value by modification time. + boost::multi_index::ordered_non_unique< + boost::multi_index::tag, + boost::multi_index::const_mem_fun< + StampedElement, + boost::posix_time::ptime, + &StampedElement::getModificationTime + > + > + > +> StampedValueCollection; + +//@} } // end of namespace isc::data } // end of namespace isc diff --git a/src/lib/dhcp/option_definition.h b/src/lib/dhcp/option_definition.h index b0a311decee7c53dbea5b0aad88a6cd098d53656..2d05c7dfa55b2a42496f155cb07d3baf18e38b14 100644 --- a/src/lib/dhcp/option_definition.h +++ b/src/lib/dhcp/option_definition.h @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -811,6 +812,16 @@ typedef boost::multi_index_container< std::string, &OptionDefinition::getName > + >, + // Start definition of index #3 + boost::multi_index::ordered_non_unique< + // Use option definition modification time as the index key. + // This value is returned by the StampedElement::getModificationTime + boost::multi_index::const_mem_fun< + data::StampedElement, + boost::posix_time::ptime, + &data::StampedElement::getModificationTime + > > > > OptionDefContainer; diff --git a/src/lib/dhcpsrv/cfg_option.cc b/src/lib/dhcpsrv/cfg_option.cc index 1ef4d9061ac806ace2991d1d45462b7aa78e88ae..71a4d5a66de8fc72f48b4aa85b8e80f6fb9e7a95 100644 --- a/src/lib/dhcpsrv/cfg_option.cc +++ b/src/lib/dhcpsrv/cfg_option.cc @@ -189,6 +189,56 @@ CfgOption::getAll(const uint32_t vendor_id) const { return (vendor_options_.getItems(vendor_id)); } +size_t +CfgOption::del(const std::string& option_space, const uint16_t option_code) { + // Check for presence of options. + OptionContainerPtr options = getAll(option_space); + if (!options || options->empty()) { + // There are no options, so there is nothing to do. + return (0); + } + + // If this is not top level option we may also need to delete the + // option instance from options encapsulating the particular option + // space. + if ((option_space != DHCP4_OPTION_SPACE) && + (option_space != DHCP6_OPTION_SPACE)) { + // For each option space name iterate over the existing options. + auto option_space_names = getOptionSpaceNames(); + for (auto option_space_from_list : option_space_names) { + // Get all options within the particular option space. + auto options_in_space = getAll(option_space_from_list); + for (auto option_it = options_in_space->begin(); + option_it != options_in_space->end(); + ++option_it) { + + // Check if the option encapsulates our option space and + // it does, try to delete our option. + if (option_it->option_ && + (option_it->option_->getEncapsulatedSpace() == option_space)) { + option_it->option_->delOption(option_code); + } + } + } + } + + auto& idx = options->get<1>(); + return (idx.erase(option_code)); +} + +size_t +CfgOption::del(const uint32_t vendor_id, const uint16_t option_code) { + // Check for presence of options. + OptionContainerPtr vendor_options = getAll(vendor_id); + if (!vendor_options || vendor_options->empty()) { + // There are no options, so there is nothing to do. + return (0); + } + + auto& idx = vendor_options->get<1>(); + return (idx.erase(option_code)); +} + ElementPtr CfgOption::toElement() const { // option-data value is a list of maps diff --git a/src/lib/dhcpsrv/cfg_option.h b/src/lib/dhcpsrv/cfg_option.h index a3fa37066aee70e9860b21330659bc0e37068c83..92a6c4ee92e0c9cbb650dd9da551a722c44ff177 100644 --- a/src/lib/dhcpsrv/cfg_option.h +++ b/src/lib/dhcpsrv/cfg_option.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -198,6 +199,15 @@ typedef boost::multi_index_container< bool, &OptionDescriptor::persistent_ > + >, + // Start definition of index #3. + // Use StampedElement::getModificationTime as a key. + boost::multi_index::ordered_non_unique< + boost::multi_index::const_mem_fun< + data::StampedElement, + boost::posix_time::ptime, + &data::StampedElement::getModificationTime + > > > > OptionContainer; @@ -404,6 +414,26 @@ public: return (*od_itr); } + /// @brief Deletes option for the specified option space and option code. + /// + /// If the option is encapsulated within some non top level option space, + /// it is also deleted from all option instances encapsulating this + /// option space. + /// + /// @param option_space Option space name. + /// @param option_code Code of the option to be returned. + /// + /// @return Number of deleted options. + size_t del(const std::string& option_space, const uint16_t option_code); + + /// @brief Delets vendor option for the specified vendor id. + /// + /// @param vendor_id Vendor identifier. + /// @param option_code Option code. + /// + /// @return Number of deleted options. + size_t del(const uint32_t vendor_id, const uint16_t option_code); + /// @brief Returns a list of configured option space names. /// /// The returned option space names exclude vendor option spaces, diff --git a/src/lib/dhcpsrv/shared_network.h b/src/lib/dhcpsrv/shared_network.h index 25ab713f4dc94c1765064a9b0fbe4378c8722d01..fc0f9220ebdf710a56bccb7ea8ca15c7c2c253bf 100644 --- a/src/lib/dhcpsrv/shared_network.h +++ b/src/lib/dhcpsrv/shared_network.h @@ -34,6 +34,10 @@ struct SharedNetworkNameIndexTag { }; /// @brief A tag for accessing index by server identifier. struct SharedNetworkServerIdIndexTag { }; +/// @brief Tag for the index for searching by shared network modification +/// time. +struct SharedNetworkModificationTimeIndexTag { }; + /// @brief Shared network holding IPv4 subnets. /// /// Specialization of the @ref Network4 class for IPv4 shared networks. @@ -188,8 +192,14 @@ typedef boost::multi_index_container< boost::multi_index::tag, boost::multi_index::const_mem_fun + >, + // Fourth index allows for searching using subnet modification time. + boost::multi_index::ordered_non_unique< + boost::multi_index::tag, + boost::multi_index::const_mem_fun > - > > SharedNetwork4Collection; @@ -340,6 +350,13 @@ typedef boost::multi_index_container< boost::multi_index::tag, boost::multi_index::const_mem_fun + >, + // Third index allows for searching using subnet modification time. + boost::multi_index::ordered_non_unique< + boost::multi_index::tag, + boost::multi_index::const_mem_fun > > > SharedNetwork6Collection; diff --git a/src/lib/dhcpsrv/subnet.h b/src/lib/dhcpsrv/subnet.h index 308c673b30e0fe0564d420126adf60c5205223df..bd28c7ebfb074757e53335746db49b3f50ec8487 100644 --- a/src/lib/dhcpsrv/subnet.h +++ b/src/lib/dhcpsrv/subnet.h @@ -744,6 +744,9 @@ struct SubnetPrefixIndexTag { }; /// @brief Tag for the index for searching by server identifier. struct SubnetServerIdIndexTag { }; +/// @brief Tag for the index for searching by subnet modification time. +struct SubnetModificationTimeIndexTag { }; + /// @brief A collection of @c Subnet4 objects /// /// This container provides a set of indexes which can be used to retrieve @@ -788,11 +791,19 @@ typedef boost::multi_index_container< boost::multi_index::const_mem_fun >, - // Fourth index allows for searching using an output from getServerId + // Fourth index allows for searching using an output from getServerId. boost::multi_index::ordered_non_unique< boost::multi_index::tag, boost::multi_index::const_mem_fun + >, + + // Fifth index allows for searching using subnet modification time. + boost::multi_index::ordered_non_unique< + boost::multi_index::tag, + boost::multi_index::const_mem_fun > > > Subnet4Collection; @@ -838,6 +849,13 @@ typedef boost::multi_index_container< boost::multi_index::ordered_unique< boost::multi_index::tag, boost::multi_index::const_mem_fun + >, + // Fourth index allows for searching using subnet modification time. + boost::multi_index::ordered_non_unique< + boost::multi_index::tag, + boost::multi_index::const_mem_fun > > > Subnet6Collection; diff --git a/src/lib/dhcpsrv/tests/cfg_option_unittest.cc b/src/lib/dhcpsrv/tests/cfg_option_unittest.cc index 7d41f2779f584b24faa6f61d15e5aeead8e322b3..7439f70c3a000eb6990428bbd54a725fc31e962f 100644 --- a/src/lib/dhcpsrv/tests/cfg_option_unittest.cc +++ b/src/lib/dhcpsrv/tests/cfg_option_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2017 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2014-2018 Internet Systems Consortium, Inc. ("ISC") // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -399,6 +399,112 @@ TEST_F(CfgOptionTest, encapsulate) { } } +// This test verifies that an option can be deleted from the configuration. +TEST_F(CfgOptionTest, delFromOptionSpace) { + CfgOption cfg; + + generateEncapsulatedOptions(cfg); + + // Append options from "foo" and "bar" space as sub-options and options + // from "foo-subs" and "bar-subs" as sub-options of "foo" and "bar" + // options. + ASSERT_NO_THROW(cfg.encapsulate()); + + // The option with the code 5 should exist in the option space "foo". + ASSERT_TRUE(cfg.get("foo", 5).option_); + + // Because we called "encapsulate", this option should have been + // propagated to the options encapsulating option space "foo". + for (uint16_t code = 1000; code < 1020; ++code) { + OptionDescriptor top_level_option(false); + ASSERT_NO_THROW(top_level_option = cfg.get(DHCP6_OPTION_SPACE, code)); + // Make sure that the option with code 5 is there. + ASSERT_TRUE(top_level_option.option_); + ASSERT_TRUE(top_level_option.option_->getOption(5)); + + // Make sure that options belonging to space "foo-subs" should contain + // options with the code of 5. + for (uint16_t code_subs = 1; code_subs != 19; ++code_subs) { + OptionPtr sub_option; + ASSERT_NO_THROW(sub_option = top_level_option.option_->getOption(code_subs)); + ASSERT_TRUE(sub_option); + ASSERT_TRUE(sub_option->getOption(5)); + } + } + + // Delete option with the code 5 and belonging to option space "foo". + uint64_t deleted_num; + ASSERT_NO_THROW(deleted_num = cfg.del("foo", 5)); + EXPECT_EQ(1, deleted_num); + + // The option should now be gone from options config. + EXPECT_FALSE(cfg.get("foo", 5).option_); + // Option with the code of 5 in other option spaces should remain. + EXPECT_TRUE(cfg.get("foo-subs", 5).option_); + + // Iterate over the options encapsulating "foo" option space. Make sure + // that the option with code 5 is no longer encapsulated by these options. + for (uint16_t code = 1000; code < 1020; ++code) { + OptionDescriptor top_level_option(false); + ASSERT_NO_THROW(top_level_option = cfg.get(DHCP6_OPTION_SPACE, code)); + ASSERT_TRUE(top_level_option.option_); + EXPECT_FALSE(top_level_option.option_->getOption(5)); + // Other options should remain. + EXPECT_TRUE(top_level_option.option_->getOption(1)); + + // Iterate over options within foo-subs option space and make sure + // that they still contain options with the code of 5. + for (uint16_t code_subs = 1; code_subs != 19; ++code_subs) { + // There shouldn't be option with the code of 5 in the "foo" space. + if (code_subs == 5) { + continue; + } + + OptionPtr sub_option; + ASSERT_NO_THROW(sub_option = top_level_option.option_->getOption(code_subs)); + // Options belonging to option space "foo-subs" should include option + // with the code of 5. + ASSERT_TRUE(sub_option); + ASSERT_TRUE(sub_option->getOption(5)); + } + } +} + +// This test verifies that a vendor option can be deleted from the configuration. +TEST_F(CfgOptionTest, delVendorOption) { + CfgOption cfg; + + // Create multiple vendor options for vendor id 123. + for (uint16_t code = 100; code < 110; ++code) { + OptionPtr option(new Option(Option::V6, code, OptionBuffer(1, 0xFF))); + ASSERT_NO_THROW(cfg.add(option, false, "vendor-123")); + } + + // Create multiple vendor options for vendor id 234. + for (uint16_t code = 100; code < 110; ++code) { + OptionPtr option(new Option(Option::V6, code, OptionBuffer(1, 0xFF))); + ASSERT_NO_THROW(cfg.add(option, false, "vendor-234")); + } + + // Make sure that the option we're trying to delete is there. + ASSERT_TRUE(cfg.get(123, 105).option_); + // There should also be an option 105 for vendor id 234. + ASSERT_TRUE(cfg.get(234, 105).option_); + + // Delete the option for vendor id 123. + uint64_t deleted_num; + ASSERT_NO_THROW(deleted_num = cfg.del(123, 105)); + EXPECT_EQ(1, deleted_num); + + // Make sure the option is gone. + EXPECT_FALSE(cfg.get(123, 105).option_); + // Make sure that the option with code 105 is not affected for vendor id 234. + EXPECT_TRUE(cfg.get(234, 105).option_); + + // Other options, like 107, shouldn't be gone. + EXPECT_TRUE(cfg.get(123, 107).option_); +} + // This test verifies that single option can be retrieved from the configuration // using option code and option space. TEST_F(CfgOptionTest, get) { diff --git a/src/lib/dhcpsrv/testutils/test_config_backend.h b/src/lib/dhcpsrv/testutils/test_config_backend.h index 7c644eb9f1b0735e38e26981bf7c3610a485ebfe..b82cc00b6a77b5c29bd196831b5ccb2eccbb4247 100644 --- a/src/lib/dhcpsrv/testutils/test_config_backend.h +++ b/src/lib/dhcpsrv/testutils/test_config_backend.h @@ -52,7 +52,8 @@ public: /// @brief Returns backend type. /// /// @return string db_type name - virtual std::string getType() const { return (db_type_); + virtual std::string getType() const { + return (db_type_); } /// @brief Returns backend host. diff --git a/src/lib/dhcpsrv/testutils/test_config_backend_dhcp4.cc b/src/lib/dhcpsrv/testutils/test_config_backend_dhcp4.cc index 12c34e8ea2afe2df31d48a0316cc87de44987d99..212344830cc7f2f4d45714278d12cfce67008622 100644 --- a/src/lib/dhcpsrv/testutils/test_config_backend_dhcp4.cc +++ b/src/lib/dhcpsrv/testutils/test_config_backend_dhcp4.cc @@ -9,13 +9,15 @@ #include #include +using namespace isc::data; + namespace isc { namespace dhcp { namespace test { bool TestConfigBackendDHCPv4::registerBackendType(ConfigBackendDHCPv4Mgr& mgr, - const std::string& db_type) { + const std::string& db_type) { return(mgr.registerBackendFactory(db_type, [](const db::DatabaseConnection::ParameterMap& params) -> dhcp::ConfigBackendDHCPv4Ptr { @@ -26,54 +28,82 @@ TestConfigBackendDHCPv4::registerBackendType(ConfigBackendDHCPv4Mgr& mgr, void TestConfigBackendDHCPv4::unregisterBackendType(ConfigBackendDHCPv4Mgr& mgr, - const std::string& db_type) { + const std::string& db_type) { mgr.unregisterBackendFactory(db_type); } Subnet4Ptr TestConfigBackendDHCPv4::getSubnet4(const db::ServerSelector& /* server_selector */, - const std::string& /* subnet_prefix */) const{ - return (Subnet4Ptr()); + const std::string& subnet_prefix) const{ + const auto& index = subnets_.get(); + auto subnet_it = index.find(subnet_prefix); + return ((subnet_it != index.cend()) ? (*subnet_it) : Subnet4Ptr()); } Subnet4Ptr TestConfigBackendDHCPv4::getSubnet4(const db::ServerSelector& /* server_selector */, - const SubnetID& /* subnet_id */) const { - return (Subnet4Ptr()); + const SubnetID& subnet_id) const { + const auto& index = subnets_.get(); + auto subnet_it = index.find(subnet_id); + return ((subnet_it != index.cend()) ? (*subnet_it) : Subnet4Ptr()); } Subnet4Collection TestConfigBackendDHCPv4::getAllSubnets4(const db::ServerSelector& /* server_selector */) const { - return(subnets_); + return (subnets_); } Subnet4Collection TestConfigBackendDHCPv4::getModifiedSubnets4(const db::ServerSelector& /* server_selector */, - const boost::posix_time::ptime& /* modification_time */) const { - return(subnets_); + const boost::posix_time::ptime& modification_time) const { + const auto& index = subnets_.get(); + Subnet4Collection subnets; + auto lb = index.lower_bound(modification_time); + for (auto subnet = lb; subnet != index.end(); ++subnet) { + subnets.push_back(*subnet); + } + return (subnets); } SharedNetwork4Ptr TestConfigBackendDHCPv4::getSharedNetwork4(const db::ServerSelector& /* server_selector */, - const std::string& /* name */) const { - return(SharedNetwork4Ptr()); + const std::string& name) const { + const auto& index = shared_networks_.get(); + auto network_it = index.find(name); + return ((network_it != index.cend()) ? (*network_it) : SharedNetwork4Ptr()); } SharedNetwork4Collection TestConfigBackendDHCPv4::getAllSharedNetworks4(const db::ServerSelector& /* server_selector */) const{ - return(shared_networks_); + return (shared_networks_); } SharedNetwork4Collection TestConfigBackendDHCPv4::getModifiedSharedNetworks4(const db::ServerSelector& /* server_selector */, - const boost::posix_time::ptime& /* modification_time */) const { - return(shared_networks_); + const boost::posix_time::ptime& modification_time) const { + const auto& index = shared_networks_.get(); + SharedNetwork4Collection shared_networks; + auto lb = index.lower_bound(modification_time); + for (auto shared_network = lb; shared_network != index.end(); ++shared_network) { + shared_networks.push_back(*shared_network); + } + return (shared_networks); } OptionDefinitionPtr TestConfigBackendDHCPv4::getOptionDef4(const db::ServerSelector& /* server_selector */, - const uint16_t /* code */, - const std::string& /* space */) const { + const uint16_t code, + const std::string& space) const { + const auto& index = option_defs_.get<1>(); + auto option_def_it_pair = index.equal_range(code); + + for (auto option_def_it = option_def_it_pair.first; + option_def_it != option_def_it_pair.second; + ++option_def_it) { + if ((*option_def_it)->getOptionSpaceName() == space) { + return (*option_def_it); + } + } return (OptionDefinitionPtr()); } @@ -84,14 +114,30 @@ TestConfigBackendDHCPv4::getAllOptionDefs4(const db::ServerSelector& /* server_s OptionDefContainer TestConfigBackendDHCPv4::getModifiedOptionDefs4(const db::ServerSelector& /* server_selector */, - const boost::posix_time::ptime& /* modification_time */) const { - return (option_defs_); + const boost::posix_time::ptime& modification_time) const { + const auto& index = option_defs_.get<3>(); + OptionDefContainer option_defs; + auto lb = index.lower_bound(modification_time); + for (auto option_def = lb; option_def != index.end(); ++option_def) { + option_defs.push_back(*option_def); + } + return (option_defs); } OptionDescriptorPtr TestConfigBackendDHCPv4::getOption4(const db::ServerSelector& /* server_selector */, - const uint16_t /* code */, - const std::string& /* space */) const { + const uint16_t code, + const std::string& space) const { + const auto& index = options_.get<1>(); + auto option_it_pair = index.equal_range(code); + + for (auto option_it = option_it_pair.first; option_it != option_it_pair.second; + ++option_it) { + if (option_it->space_name_ == space) { + return (OptionDescriptorPtr(new OptionDescriptor(*option_it))); + } + } + return (OptionDescriptorPtr()); } @@ -102,153 +148,306 @@ TestConfigBackendDHCPv4::getAllOptions4(const db::ServerSelector& /* server_sele OptionContainer TestConfigBackendDHCPv4::getModifiedOptions4(const db::ServerSelector& /* server_selector */, - const boost::posix_time::ptime& /* modification_time */) const { - return (options_); + const boost::posix_time::ptime& modification_time) const { + const auto& index = options_.get<3>(); + OptionContainer options; + auto lb = index.lower_bound(modification_time); + for (auto option = lb; option != index.end(); ++option) { + options.push_back(*option); + } + return (options); } -data::StampedValuePtr +StampedValuePtr TestConfigBackendDHCPv4::getGlobalParameter4(const db::ServerSelector& /* server_selector */, - const std::string& /* name */) const { - return(data::StampedValuePtr()); + const std::string& name) const { + const auto& index = globals_.get(); + auto global_it = index.find(name); + return ((global_it != index.cend()) ? (*global_it) : StampedValuePtr()); } -data::StampedValueCollection +StampedValueCollection TestConfigBackendDHCPv4::getAllGlobalParameters4(const db::ServerSelector& /* server_selector */) const { return (globals_); } -data::StampedValueCollection +StampedValueCollection TestConfigBackendDHCPv4::getModifiedGlobalParameters4(const db::ServerSelector& /* server_selector */, - const boost::posix_time::ptime& /* modification_time */) const { - return (globals_); + const boost::posix_time::ptime& modification_time) const { + const auto& index = globals_.get(); + StampedValueCollection globals; + auto lb = index.lower_bound(modification_time); + for (auto global = lb; global != index.end(); ++global) { + globals.insert(*global); + } + return (globals); } void TestConfigBackendDHCPv4::createUpdateSubnet4(const db::ServerSelector& /* server_selector */, - const Subnet4Ptr& /* subnet */) { + const Subnet4Ptr& subnet) { + auto& index = subnets_.get(); + auto subnet_it = index.find(subnet->getID()); + + if (subnet_it != index.cend()) { + index.replace(subnet_it, subnet); + + } else { + index.insert(subnet); + } } void TestConfigBackendDHCPv4::createUpdateSharedNetwork4(const db::ServerSelector& /* server_selector */, - const SharedNetwork4Ptr& /* shared_network */) { + const SharedNetwork4Ptr& shared_network) { + auto& index = shared_networks_.get(); + auto network_it = index.find(shared_network->getName()); + + if (network_it != index.cend()) { + index.replace(network_it, shared_network); + + } else { + index.insert(shared_network); + } } void TestConfigBackendDHCPv4::createUpdateOptionDef4(const db::ServerSelector& /* server_selector */, - const OptionDefinitionPtr& /* option_def */) { + const OptionDefinitionPtr& option_def) { + auto& index = option_defs_.get<1>(); + auto option_def_it = index.find(option_def->getCode()); + + if (option_def_it != index.cend()) { + index.replace(option_def_it, option_def); + + } else { + index.insert(option_def); + } } void TestConfigBackendDHCPv4::createUpdateOption4(const db::ServerSelector& /* server_selector */, - const OptionDescriptorPtr& /* option */) { + const OptionDescriptorPtr& option) { + auto& index = options_.get<1>(); + auto option_it = index.find(option->option_->getType()); + + if (option_it != index.end()) { + index.replace(option_it, *option); + + } else { + index.insert(*option); + } } void TestConfigBackendDHCPv4::createUpdateOption4(const db::ServerSelector& /* server_selector */, - const std::string& /* shared_network_name */, - const OptionDescriptorPtr& /* option */) { + const std::string& shared_network_name, + const OptionDescriptorPtr& option) { + auto& index = shared_networks_.get(); + auto network_it = index.find(shared_network_name); + + if (network_it != index.end()) { + auto shared_network = *network_it; + shared_network->getCfgOption()->del(option->space_name_, option->option_->getType()); + shared_network->getCfgOption()->add(*option, option->space_name_); + + } else { + isc_throw(BadValue, "attempted to create or update option in a non existing " + "shared network " << shared_network_name); + } } void TestConfigBackendDHCPv4::createUpdateOption4(const db::ServerSelector& /* server_selector */, - const SubnetID& /* subnet_id */, - const OptionDescriptorPtr& /* option */) { + const SubnetID& subnet_id, + const OptionDescriptorPtr& option) { + auto& index = subnets_.get(); + auto subnet_it = index.find(subnet_id); + + if (subnet_it != index.cend()) { + auto subnet = *subnet_it; + subnet->getCfgOption()->del(option->space_name_, option->option_->getType()); + subnet->getCfgOption()->add(*option, option->space_name_); + + } else { + isc_throw(BadValue, "attempted to create or update option in a non existing " + "subnet ID " << subnet_id); + } } void TestConfigBackendDHCPv4::createUpdateOption4(const db::ServerSelector& /* server_selector */, - const asiolink::IOAddress& /* pool_start_address */, - const asiolink::IOAddress& /* pool_end_address */, - const OptionDescriptorPtr& /* option */) { + const asiolink::IOAddress& pool_start_address, + const asiolink::IOAddress& pool_end_address, + const OptionDescriptorPtr& option) { + for (auto subnet = subnets_.begin(); subnet != subnets_.end(); ++subnet) { + auto pool = (*subnet)->getPool(Lease::TYPE_V4, pool_start_address); + if (pool) { + pool->getCfgOption()->del(option->space_name_, option->option_->getType()); + pool->getCfgOption()->add(*option, option->space_name_); + + return; + } + } + + isc_throw(BadValue, "attempted to create or update option in a non existing " + "pool " << pool_start_address << " - " << pool_end_address); } void TestConfigBackendDHCPv4::createUpdateGlobalParameter4(const db::ServerSelector& /* server_selector */, - const data::StampedValuePtr& /* value */) { + const data::StampedValuePtr& value) { + auto& index = globals_.get(); + auto global_it = index.find(value->getName()); + + if (global_it != index.end()) { + index.replace(global_it, value); + + } else { + index.insert(value); + } } uint64_t TestConfigBackendDHCPv4::deleteSubnet4(const db::ServerSelector& /* server_selector */, - const std::string& /* subnet_prefix */) { - return (0); + const std::string& subnet_prefix) { + auto& index = subnets_.get(); + return (index.erase(subnet_prefix)); } uint64_t TestConfigBackendDHCPv4::deleteSubnet4(const db::ServerSelector& /* server_selector */, - const SubnetID& /* subnet_id */) { - return (0); + const SubnetID& subnet_id) { + auto& index = subnets_.get(); + return (index.erase(subnet_id)); } uint64_t TestConfigBackendDHCPv4::deleteAllSubnets4(const db::ServerSelector& /* server_selector */) { - return (0); + auto subnets_size = subnets_.size(); + subnets_.clear(); + return (subnets_size); } uint64_t TestConfigBackendDHCPv4::deleteSharedNetwork4(const db::ServerSelector& /* server_selector */, - const std::string& /* name */) { - return (0); + const std::string& name) { + auto& index = shared_networks_.get(); + return (index.erase(name)); } uint64_t TestConfigBackendDHCPv4::deleteAllSharedNetworks4(const db::ServerSelector& /* server_selector */) { - return (0); + auto shared_networks_size = shared_networks_.size(); + shared_networks_.clear(); + return (shared_networks_size); } uint64_t TestConfigBackendDHCPv4::deleteOptionDef4(const db::ServerSelector& /* server_selector */, - const uint16_t /* code */, - const std::string& /* space */) { - return (0); + const uint16_t code, + const std::string& space) { + uint64_t erased = 0; + for (auto option_def_it = option_defs_.begin(); option_def_it != option_defs_.end(); + ++option_def_it) { + if (((*option_def_it)->getCode() == code) && + ((*option_def_it)->getOptionSpaceName() == space)) { + option_def_it = option_defs_.erase(option_def_it); + ++erased; + } + } + return (erased); } uint64_t TestConfigBackendDHCPv4::deleteAllOptionDefs4(const db::ServerSelector& /* server_selector */) { - return (0); + auto option_defs_size = option_defs_.size(); + option_defs_.clear(); + return (option_defs_size); } uint64_t TestConfigBackendDHCPv4::deleteOption4(const db::ServerSelector& /* server_selector */, - const uint16_t /* code */, - const std::string& /* space */) { - return (0); + const uint16_t code, + const std::string& space) { + uint64_t erased = 0; + for (auto option_it = options_.begin(); option_it != options_.end(); + ++option_it) { + if ((option_it->option_->getType() == code) && + (option_it->space_name_ == space)) { + option_it = options_.erase(option_it); + ++erased; + } + } + return (erased); } uint64_t TestConfigBackendDHCPv4::deleteOption4(const db::ServerSelector& /* server_selector */, - const std::string& /* shared_network_name */, - const uint16_t /* code */, - const std::string& /* space */) { - return (0); + const std::string& shared_network_name, + const uint16_t code, + const std::string& space) { + auto& index = shared_networks_.get(); + auto network_it = index.find(shared_network_name); + + if (network_it != index.end()) { + auto shared_network = *network_it; + return (shared_network->getCfgOption()->del(space, code)); + + } else { + isc_throw(BadValue, "attempted to delete an option in a non existing " + "shared network " << shared_network_name); + } } uint64_t TestConfigBackendDHCPv4::deleteOption4(const db::ServerSelector& /* server_selector */, - const SubnetID& /* subnet_id */, - const uint16_t /* code */, - const std::string& /* space */) { - return (0); + const SubnetID& subnet_id, + const uint16_t code, + const std::string& space) { + auto& index = subnets_.get(); + auto subnet_it = index.find(subnet_id); + + if (subnet_it != index.cend()) { + auto subnet = *subnet_it; + return (subnet->getCfgOption()->del(space, code)); + + } else { + isc_throw(BadValue, "attempted to delete an option in a non existing " + "subnet ID " << subnet_id); + } } uint64_t TestConfigBackendDHCPv4::deleteOption4(const db::ServerSelector& /* server_selector */, - const asiolink::IOAddress& /* pool_start_address */, - const asiolink::IOAddress& /* pool_end_address */, - const uint16_t /* code */, - const std::string& /* space */) { - return (0); + const asiolink::IOAddress& pool_start_address, + const asiolink::IOAddress& pool_end_address, + const uint16_t code, + const std::string& space) { + for (auto subnet = subnets_.begin(); subnet != subnets_.end(); ++subnet) { + auto pool = (*subnet)->getPool(Lease::TYPE_V4, pool_start_address); + if (pool) { + return (pool->getCfgOption()->del(space, code)); + } + } + + isc_throw(BadValue, "attempted to delete an option in a non existing " + "pool " << pool_start_address << " - " << pool_end_address); } uint64_t TestConfigBackendDHCPv4::deleteGlobalParameter4(const db::ServerSelector& /* server_selector */, - const std::string& /* name */) { - return (0); + const std::string& name) { + auto& index = globals_.get(); + return (index.erase(name)); } uint64_t TestConfigBackendDHCPv4::deleteAllGlobalParameters4(const db::ServerSelector& /* server_selector */) { - return (0); + auto globals_size = globals_.size(); + globals_.clear(); + return (globals_size); } } // namespace test diff --git a/src/lib/dhcpsrv/testutils/test_config_backend_dhcp4.h b/src/lib/dhcpsrv/testutils/test_config_backend_dhcp4.h index 44f95dca90b450ddf9d6ac6ffac2aea9b9b85901..bd2aba62dce2e804a61ab6e7506410a57d5a539d 100644 --- a/src/lib/dhcpsrv/testutils/test_config_backend_dhcp4.h +++ b/src/lib/dhcpsrv/testutils/test_config_backend_dhcp4.h @@ -14,25 +14,26 @@ #include #include -#include + +#include +#include namespace isc { namespace dhcp { namespace test { -/// @brief Test backend that implements all of the DHCPv4 API calls +/// @brief Test config backend that implements all of the DHCPv4 API calls /// -/// Currently all API get calls which return a single entry, will return an -/// empty pointer of appropriate type. API calls which return a collection of -/// entires will return an empty collection of the appropriate type. +/// This backend should be used for unit testing the DHCPv4 server and the +/// commands which manpiluate the configuration information stored in the +/// database. /// -/// In addition provides static register and unregister methods so it may be -/// registered with a configuration backend manager. +/// This backend stores server configuration information in memory. class TestConfigBackendDHCPv4 : public TestConfigBackend { public: /// @brief Constructor /// - /// + /// @param params Database connection parameters. TestConfigBackendDHCPv4(const db::DatabaseConnection::ParameterMap& params) : TestConfigBackend(params) { }