From: Marcin Siodelski Date: Wed, 10 Oct 2018 11:23:43 +0000 (+0200) Subject: [#93,!63] Server selection partially working for subnets. X-Git-Tag: 153-netconf-configs_base~16 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a520942300414725c12cee512d1f9645ea8ba5fe;p=thirdparty%2Fkea.git [#93,!63] Server selection partially working for subnets. --- diff --git a/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.cc b/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.cc index be0868e99a..df4f0408cf 100644 --- a/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.cc +++ b/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.cc @@ -73,6 +73,7 @@ public: INSERT_GLOBAL_PARAMETER4, INSERT_GLOBAL_PARAMETER4_SERVER, INSERT_SUBNET4, + INSERT_SUBNET4_SERVER, INSERT_POOL4, INSERT_SHARED_NETWORK4, INSERT_OPTION_DEF4, @@ -476,13 +477,19 @@ public: /// /// @return Pointer to the returned subnet or NULL if such subnet /// doesn't exist. - Subnet4Ptr getSubnet4(const ServerSelector& /* server_selector */, + Subnet4Ptr getSubnet4(const ServerSelector& server_selector, const SubnetID& subnet_id) { - MySqlBindingCollection in_bindings; - in_bindings.push_back(MySqlBinding::createInteger(subnet_id)); - Subnet4Collection subnets; - getSubnets4(GET_SUBNET4_ID, in_bindings, subnets); + + auto tags = getServerTags(server_selector); + for (auto tag : tags) { + MySqlBindingCollection in_bindings = { + MySqlBinding::createString(tag), + MySqlBinding::createInteger(subnet_id) + }; + + getSubnets4(GET_SUBNET4_ID, in_bindings, subnets); + } return (subnets.empty() ? Subnet4Ptr() : *subnets.begin()); } @@ -496,17 +503,62 @@ public: /// /// @return Pointer to the returned subnet or NULL if such subnet /// doesn't exist. - Subnet4Ptr getSubnet4(const ServerSelector& /* server_selector */, + Subnet4Ptr getSubnet4(const ServerSelector& server_selector, const std::string& subnet_prefix) { - MySqlBindingCollection in_bindings; - in_bindings.push_back(MySqlBinding::createString(subnet_prefix)); - Subnet4Collection subnets; - getSubnets4(GET_SUBNET4_PREFIX, in_bindings, subnets); + + auto tags = getServerTags(server_selector); + for (auto tag : tags) { + MySqlBindingCollection in_bindings = { + MySqlBinding::createString(tag), + MySqlBinding::createString(subnet_prefix) + }; + + getSubnets4(GET_SUBNET4_PREFIX, in_bindings, subnets); + } return (subnets.empty() ? Subnet4Ptr() : *subnets.begin()); } + /// @brief Sends query to retrieve all subnets. + /// + /// @param server_selector Server selector. + /// @param [out] subnets Reference to the subnet collection structure where + /// subnets should be inserted. + void getAllSubnets4(const ServerSelector& server_selector, + Subnet4Collection& subnets) { + auto tags = getServerTags(server_selector); + + for (auto tag : tags) { + MySqlBindingCollection in_bindings = { + MySqlBinding::createString(tag) + }; + + getSubnets4(GET_ALL_SUBNETS4, in_bindings, subnets); + } + } + + /// @brief Sends query to retrieve modified subnets. + /// + /// @param server_selector Server selector. + /// @param modification_ts Lower bound modification timestamp. + /// @param [out] subnets Reference to the subnet collection structure where + /// subnets should be inserted. + void getModifiedSubnets4(const ServerSelector& server_selector, + const boost::posix_time::ptime& modification_ts, + Subnet4Collection& subnets) { + auto tags = getServerTags(server_selector); + + for (auto tag : tags) { + MySqlBindingCollection in_bindings = { + MySqlBinding::createString(tag), + MySqlBinding::createTimestamp(modification_ts) + }; + + getSubnets4(GET_MODIFIED_SUBNETS4, in_bindings, subnets); + } + } + /// @brief Sends query to retrieve multiple pools. /// /// Query should order pools by id. @@ -611,6 +663,16 @@ public: /// @param subnet Pointer to the subnet to be inserted or updated. void createUpdateSubnet4(const ServerSelector& server_selector, const Subnet4Ptr& subnet) { + + auto tags = getServerTags(server_selector); + + /// @todo Extend support to multiple server tags. + if (tags.size() != 1) { + isc_throw(InvalidOperation, "expected exactly one server tag to be" + " specified while creating or updating subnet configuration." + " Got: " << getServerTagsAsText(server_selector)); + } + // Convert DHCPv4o6 interface id to text. OptionPtr dhcp4o6_interface_id = subnet->get4o6().getInterfaceId(); std::string dhcp4o6_interface_id_text; @@ -679,6 +741,19 @@ public: conn_.insertQuery(MySqlConfigBackendDHCPv4Impl::INSERT_SUBNET4, in_bindings); + // Create bindings for inserting the association into + // dhcp4_subnet_server table. + MySqlBindingCollection in_server_bindings = { + MySqlBinding::createInteger(subnet->getID()), // subnet_id + MySqlBinding::createString(*tags.begin()), // tag used to obtain server_id + MySqlBinding::createTimestamp(subnet->getModificationTime()), // modification_ts + }; + + // Insert association. + conn_.insertQuery(MySqlConfigBackendDHCPv4Impl::INSERT_SUBNET4_SERVER, + in_server_bindings); + + } catch (const DuplicateEntry&) { deletePools4(subnet); deleteOptions4(subnet); @@ -743,13 +818,10 @@ public: /// @param server_selector Server selector. /// @param subnet_id Identifier of the subnet to be deleted. /// @return Number of deleted subnets. - uint64_t deleteSubnet4(const ServerSelector& /* server_selector */, + uint64_t deleteSubnet4(const ServerSelector& server_selector, const SubnetID& subnet_id) { - MySqlBindingCollection in_bindings; - in_bindings.push_back(MySqlBinding::createInteger(subnet_id)); - - // Run DELETE. - return (conn_.updateDeleteQuery(DELETE_SUBNET4_ID, in_bindings)); + return (deleteFromTable(DELETE_SUBNET4_ID, server_selector, + subnet_id)); } /// @brief Deletes pools belonging to a subnet from the database. @@ -1604,7 +1676,7 @@ TaggedStatementArray tagged_statements = { { " ON g.id = a.parameter_id " "INNER JOIN dhcp4_server AS s " " ON (a.server_id = s.id) OR (a.server_id = 1) " - "WHERE (s.tag = ? OR s.id=1) AND g.modification_ts > ? " + "WHERE (s.tag = ? OR s.id = 1) AND (g.modification_ts > ?) " "ORDER BY g.id" }, @@ -1661,10 +1733,14 @@ TaggedStatementArray tagged_statements = { { " o.pool_id," " o.modification_ts " "FROM dhcp4_subnet AS s " + "INNER JOIN dhcp4_subnet_server AS a " + " ON s.subnet_id = a.subnet_id " + "INNER JOIN dhcp4_server AS srv " + " ON (a.server_id = srv.id) OR (a.server_id = 1) " "LEFT JOIN dhcp4_pool AS p ON s.subnet_id = p.subnet_id " "LEFT JOIN dhcp4_options AS x ON x.scope_id = 5 AND p.id = x.pool_id " "LEFT JOIN dhcp4_options AS o ON o.scope_id = 1 AND s.subnet_id = o.dhcp4_subnet_id " - "WHERE s.subnet_id = ? " + "WHERE (srv.tag = ? OR srv.id = 1) AND s.subnet_id = ? " "ORDER BY s.subnet_id, p.id, x.option_id, o.option_id" }, // Select subnet by prefix. @@ -1720,10 +1796,14 @@ TaggedStatementArray tagged_statements = { { " o.pool_id," " o.modification_ts " "FROM dhcp4_subnet AS s " + "INNER JOIN dhcp4_subnet_server AS a " + " ON s.subnet_id = a.subnet_id " + "INNER JOIN dhcp4_server AS srv " + " ON (a.server_id = srv.id) OR (a.server_id = 1) " "LEFT JOIN dhcp4_pool AS p ON s.subnet_id = p.subnet_id " "LEFT JOIN dhcp4_options AS x ON x.scope_id = 5 AND p.id = x.pool_id " "LEFT JOIN dhcp4_options AS o ON o.scope_id = 1 AND s.subnet_id = o.dhcp4_subnet_id " - "WHERE s.subnet_prefix = ? " + "WHERE (srv.tag = ? OR srv.id = 1) AND s.subnet_prefix = ? " "ORDER BY s.subnet_id, p.id, x.option_id, o.option_id" }, // Select all subnets. @@ -1779,9 +1859,14 @@ TaggedStatementArray tagged_statements = { { " o.pool_id," " o.modification_ts " "FROM dhcp4_subnet AS s " + "INNER JOIN dhcp4_subnet_server AS a " + " ON s.subnet_id = a.subnet_id " + "INNER JOIN dhcp4_server AS srv " + " ON (a.server_id = srv.id) OR (a.server_id = 1) " "LEFT JOIN dhcp4_pool AS p ON s.subnet_id = p.subnet_id " "LEFT JOIN dhcp4_options AS x ON x.scope_id = 5 AND p.id = x.pool_id " "LEFT JOIN dhcp4_options AS o ON o.scope_id = 1 AND s.subnet_id = o.dhcp4_subnet_id " + "WHERE (srv.tag = ? OR srv.id = 1) " "ORDER BY s.subnet_id, p.id, x.option_id, o.option_id" }, // Select subnets having modification time later than X. @@ -1837,10 +1922,14 @@ TaggedStatementArray tagged_statements = { { " o.pool_id," " o.modification_ts " "FROM dhcp4_subnet AS s " + "INNER JOIN dhcp4_subnet_server AS a " + " ON s.subnet_id = a.subnet_id " + "INNER JOIN dhcp4_server AS srv " + " ON (a.server_id = srv.id) OR (a.server_id = 1) " "LEFT JOIN dhcp4_pool AS p ON s.subnet_id = p.subnet_id " "LEFT JOIN dhcp4_options AS x ON x.scope_id = 5 AND p.id = x.pool_id " "LEFT JOIN dhcp4_options AS o ON o.scope_id = 1 AND s.subnet_id = o.dhcp4_subnet_id " - "WHERE s.modification_ts > ? " + "WHERE (srv.tag = ? OR srv.id = 1) AND s.modification_ts > ? " "ORDER BY s.subnet_id, p.id, x.option_id, o.option_id" }, // Select pool by address range. @@ -2179,6 +2268,14 @@ TaggedStatementArray tagged_statements = { { ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?," "?, ?, ?, ?, ?, ?, ?, ?)" }, + // Insert association of the subnet with a server. + { MySqlConfigBackendDHCPv4Impl::INSERT_SUBNET4_SERVER, + "INSERT INTO dhcp4_subnet_server(" + " subnet_id," + " server_id," + " modification_ts" + ") VALUES (?, (SELECT id FROM dhcp4_server WHERE tag = ?), ?)" }, + // Insert pool for a subnet. { MySqlConfigBackendDHCPv4Impl::INSERT_POOL4, "INSERT INTO dhcp4_pool(" @@ -2400,17 +2497,30 @@ TaggedStatementArray tagged_statements = { { // Delete subnet by id. { MySqlConfigBackendDHCPv4Impl::DELETE_SUBNET4_ID, - "DELETE FROM dhcp4_subnet " - "WHERE subnet_id = ?" }, + "DELETE s FROM dhcp4_subnet AS s " + "INNER JOIN dhcp4_subnet_server AS a " + " ON s.subnet_id = a.subnet_id " + "INNER JOIN dhcp4_server AS srv" + " ON a.server_id = srv.id " + "WHERE srv.tag = ? AND s.subnet_id = ?" }, // Delete subnet by prefix. { MySqlConfigBackendDHCPv4Impl::DELETE_SUBNET4_PREFIX, - "DELETE FROM dhcp4_subnet " - "WHERE subnet_prefix = ?" }, + "DELETE s FROM dhcp4_subnet AS s " + "INNER JOIN dhcp4_subnet_server AS a " + " ON s.subnet_id = a.subnet_id " + "INNER JOIN dhcp4_server AS srv" + " ON a.server_id = srv.id " + "WHERE srv.tag = ? AND s.subnet_prefix = ?" }, // Delete all subnets. { MySqlConfigBackendDHCPv4Impl::DELETE_ALL_SUBNETS4, - "DELETE FROM dhcp4_subnet" }, + "DELETE s FROM dhcp4_subnet AS s " + "INNER JOIN dhcp4_subnet_server AS a " + " ON s.subnet_id = a.subnet_id " + "INNER JOIN dhcp4_server AS srv" + " ON a.server_id = srv.id " + "WHERE srv.tag = ?" }, // Delete pools for a subnet. { MySqlConfigBackendDHCPv4Impl::DELETE_POOLS4_SUBNET_ID, @@ -2500,23 +2610,17 @@ MySqlConfigBackendDHCPv4::getSubnet4(const ServerSelector& server_selector, } Subnet4Collection -MySqlConfigBackendDHCPv4::getAllSubnets4(const ServerSelector& /* server_selector */) const { +MySqlConfigBackendDHCPv4::getAllSubnets4(const ServerSelector& server_selector) const { Subnet4Collection subnets; - MySqlBindingCollection in_bindings; - impl_->getSubnets4(MySqlConfigBackendDHCPv4Impl::GET_ALL_SUBNETS4, - in_bindings, subnets); + impl_->getAllSubnets4(server_selector, subnets); return (subnets); } Subnet4Collection -MySqlConfigBackendDHCPv4::getModifiedSubnets4(const ServerSelector& /* server_selector */, +MySqlConfigBackendDHCPv4::getModifiedSubnets4(const ServerSelector& server_selector, const boost::posix_time::ptime& modification_time) const { Subnet4Collection subnets; - MySqlBindingCollection in_bindings = { - MySqlBinding::createTimestamp(modification_time) - }; - impl_->getSubnets4(MySqlConfigBackendDHCPv4Impl::GET_MODIFIED_SUBNETS4, - in_bindings, subnets); + impl_->getModifiedSubnets4(server_selector, modification_time, subnets); return (subnets); } @@ -2678,10 +2782,10 @@ MySqlConfigBackendDHCPv4::createUpdateGlobalParameter4(const ServerSelector& ser } uint64_t -MySqlConfigBackendDHCPv4::deleteSubnet4(const ServerSelector& /* server_selector */, +MySqlConfigBackendDHCPv4::deleteSubnet4(const ServerSelector& server_selector, const std::string& subnet_prefix) { return(impl_->deleteFromTable(MySqlConfigBackendDHCPv4Impl::DELETE_SUBNET4_PREFIX, - subnet_prefix)); + server_selector, subnet_prefix)); } uint64_t @@ -2691,8 +2795,9 @@ MySqlConfigBackendDHCPv4::deleteSubnet4(const ServerSelector& server_selector, } uint64_t -MySqlConfigBackendDHCPv4::deleteAllSubnets4(const ServerSelector& /* server_selector */) { - return (impl_->deleteFromTable(MySqlConfigBackendDHCPv4Impl::DELETE_ALL_SUBNETS4)); +MySqlConfigBackendDHCPv4::deleteAllSubnets4(const ServerSelector& server_selector) { + return (impl_->deleteFromTable(MySqlConfigBackendDHCPv4Impl::DELETE_ALL_SUBNETS4, + server_selector)); } uint64_t diff --git a/src/hooks/dhcp/mysql_cb/mysql_cb_impl.cc b/src/hooks/dhcp/mysql_cb/mysql_cb_impl.cc index 5498eacc38..06f55e846d 100644 --- a/src/hooks/dhcp/mysql_cb/mysql_cb_impl.cc +++ b/src/hooks/dhcp/mysql_cb/mysql_cb_impl.cc @@ -114,8 +114,7 @@ MySqlConfigBackendImpl::deleteFromTable(const int index, const std::string& key) uint64_t MySqlConfigBackendImpl::deleteFromTable(const int index, - const ServerSelector& server_selector, - const std::string& key) { + const ServerSelector& server_selector) { uint64_t deleted_entries = 0; auto tags = getServerTags(server_selector); @@ -124,11 +123,6 @@ MySqlConfigBackendImpl::deleteFromTable(const int index, MySqlBinding::createString(tag) }; - // Optionally add the key. - if (!key.empty()) { - in_bindings.push_back(MySqlBinding::createString(key)); - } - deleted_entries += conn_.updateDeleteQuery(index, in_bindings); } diff --git a/src/hooks/dhcp/mysql_cb/mysql_cb_impl.h b/src/hooks/dhcp/mysql_cb/mysql_cb_impl.h index 5b4c64e64c..2c0e0913bc 100644 --- a/src/hooks/dhcp/mysql_cb/mysql_cb_impl.h +++ b/src/hooks/dhcp/mysql_cb/mysql_cb_impl.h @@ -60,7 +60,7 @@ public: /// @param index Index of the statement to be executed. /// @param key String value to be used as input binding to the delete /// statement - /// @return number of deleted rows. + /// @return Number of deleted rows. uint64_t deleteFromTable(const int index, const std::string& key); @@ -68,13 +68,45 @@ public: /// /// @param index Index of the statement to be executed. /// @param server_selector Server selector. - /// @param key String value to be used as input binding to the delete + /// @return Number of deleted rows. + uint64_t deleteFromTable(const int index, + const db::ServerSelector& server_selector); + + /// @brief Sends query to delete rows from a table. + /// + /// @tparam KeyType Type of the key used as the second binding. The + /// server tag is used as first binding. + /// + /// @param index Index of the statement to be executed. + /// @param server_selector Server selector. + /// @param key Value to be used as input binding to the delete /// statement. The default value is empty which indicates that the /// key should not be used in the query. - /// @return number of deleted rows. + /// @return Number of deleted rows. + template uint64_t deleteFromTable(const int index, const db::ServerSelector& server_selector, - const std::string& key = ""); + KeyType key) { + uint64_t deleted_entries = 0; + + auto tags = getServerTags(server_selector); + for (auto tag : tags) { + db::MySqlBindingCollection in_bindings = { + db::MySqlBinding::createString(tag) + }; + + if (db::MySqlBindingTraits::column_type == MYSQL_TYPE_STRING) { + in_bindings.push_back(db::MySqlBinding::createString(key)); + + } else { + in_bindings.push_back(db::MySqlBinding::createInteger(key)); + } + + deleted_entries += conn_.updateDeleteQuery(index, in_bindings); + } + + return (deleted_entries); + } /// @brief Sends query to the database to retrieve multiple option /// definitions. diff --git a/src/hooks/dhcp/mysql_cb/tests/mysql_cb_dhcp4_unittest.cc b/src/hooks/dhcp/mysql_cb/tests/mysql_cb_dhcp4_unittest.cc index 193e3e50fb..b3c4cd7b6e 100644 --- a/src/hooks/dhcp/mysql_cb/tests/mysql_cb_dhcp4_unittest.cc +++ b/src/hooks/dhcp/mysql_cb/tests/mysql_cb_dhcp4_unittest.cc @@ -448,6 +448,12 @@ TEST_F(MySqlConfigBackendDHCPv4Test, getSubnet4) { returned_subnet = cbptr_->getSubnet4(ServerSelector::ALL(), SubnetID(1024)); EXPECT_EQ(subnet2->toElement()->str(), returned_subnet->toElement()->str()); + + // Fetching the subnet for an explicitly specified server tag should + // succeeed too. + returned_subnet = cbptr_->getSubnet4(ServerSelector::ONE("server1"), + SubnetID(1024)); + EXPECT_EQ(subnet2->toElement()->str(), returned_subnet->toElement()->str()); } // Test that subnet can be associated with a shared network. @@ -492,6 +498,12 @@ TEST_F(MySqlConfigBackendDHCPv4Test, getSubnet4ByPrefix) { // Verify subnet contents. EXPECT_EQ(subnet->toElement()->str(), returned_subnet->toElement()->str()); + + // Fetching the subnet for an explicitly specified server tag should + // succeeed too. + returned_subnet = cbptr_->getSubnet4(ServerSelector::ONE("server1"), + "192.0.2.0/24"); + EXPECT_EQ(subnet->toElement()->str(), returned_subnet->toElement()->str()); } // Test that all subnets can be fetched and then deleted. @@ -506,6 +518,10 @@ TEST_F(MySqlConfigBackendDHCPv4Test, getAllSubnets4) { Subnet4Collection subnets = cbptr_->getAllSubnets4(ServerSelector::ALL()); ASSERT_EQ(test_subnets_.size() - 1, subnets.size()); + // All subnets should also be returned for explicitly specified server tag. + subnets = cbptr_->getAllSubnets4(ServerSelector::ONE("server1")); + ASSERT_EQ(test_subnets_.size() - 1, subnets.size()); + // See if the subnets are returned ok. for (auto i = 0; i < subnets.size(); ++i) { EXPECT_EQ(test_subnets_[i + 1]->toElement()->str(), @@ -519,6 +535,18 @@ TEST_F(MySqlConfigBackendDHCPv4Test, getAllSubnets4) { // All subnets should be still there. ASSERT_EQ(test_subnets_.size() - 1, subnets.size()); + // Should not delete the subnet for explicit server tag because + // out subnet is for all servers. + EXPECT_EQ(0, cbptr_->deleteSubnet4(ServerSelector::ONE("server1"), + test_subnets_[1]->getID())); + + // Also, verify that behavior when deleting by prefix. + EXPECT_EQ(0, cbptr_->deleteSubnet4(ServerSelector::ONE("server1"), + test_subnets_[2]->toText())); + + // Same for all subnets. + EXPECT_EQ(0, cbptr_->deleteAllSubnets4(ServerSelector::ONE("server1"))); + // Delete first subnet by id and verify that it is gone. EXPECT_EQ(1, cbptr_->deleteSubnet4(ServerSelector::ALL(), test_subnets_[1]->getID())); @@ -560,6 +588,11 @@ TEST_F(MySqlConfigBackendDHCPv4Test, getModifiedSubnets4) { timestamps_["today"]); ASSERT_EQ(1, subnets.size()); + // All subnets should also be returned for explicitly specified server tag. + subnets = cbptr_->getModifiedSubnets4(ServerSelector::ONE("server1"), + timestamps_["today"]); + ASSERT_EQ(1, subnets.size()); + // Fetch subnets with timestamp later than yesterday. We should get // two subnets. subnets = cbptr_->getModifiedSubnets4(ServerSelector::ALL(),