From: Marcin Siodelski Date: Mon, 8 Oct 2018 14:32:16 +0000 (+0200) Subject: [#93,!63] Implemented server selection for global parameters in MySQL. X-Git-Tag: 153-netconf-configs_base~19 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=bffc9fae2cc7bacde76ddb23e7c95534f732cd00;p=thirdparty%2Fkea.git [#93,!63] Implemented server selection for global parameters in MySQL. --- diff --git a/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.cc b/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.cc index 1a44182085..d770ac7329 100644 --- a/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.cc +++ b/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.cc @@ -71,6 +71,7 @@ public: GET_OPTION4_POOL_ID_CODE_SPACE, GET_OPTION4_SHARED_NETWORK_CODE_SPACE, INSERT_GLOBAL_PARAMETER4, + INSERT_GLOBAL_PARAMETER4_SERVER, INSERT_SUBNET4, INSERT_POOL4, INSERT_SHARED_NETWORK4, @@ -156,12 +157,17 @@ public: /// doesn't exist. StampedValuePtr getGlobalParameter4(const ServerSelector& /* server_selector */, const std::string& name) { - MySqlBindingCollection in_bindings = { - MySqlBinding::createString(name) - }; - StampedValueCollection parameters; - getGlobalParameters4(GET_GLOBAL_PARAMETER4, in_bindings, parameters); + + auto tags = getServerTags(server_selector); + for (auto tag : tags) { + MySqlBindingCollection in_bindings = { + MySqlBinding::createString(tag), + MySqlBinding::createString(name) + }; + + getGlobalParameters4(GET_GLOBAL_PARAMETER4, in_bindings, parameters); + } return (parameters.empty() ? StampedValuePtr() : *parameters.begin()); } @@ -173,10 +179,27 @@ public: /// @param value Value of the global parameter. void createUpdateGlobalParameter4(const db::ServerSelector& /* server_selector */, const StampedValuePtr& value) { + MySqlTransaction transaction(conn_); + + auto tags = getServerTags(server_selector); + + /// @todo Currently we allow only one server tag for creation and update + /// of the global parameters. If we allow more, this is getting very tricky, + /// because we combine updates and insertions. We have to define how we + /// want to update an object shared by multiple servers. What if selector + /// contains one tag, but the parameter is shared by multiple? Should it + /// update one or all?. + if (tags.size() != 1) { + isc_throw(InvalidOperation, "expected exactly one server tag to be" + " specified while creating or updating global configuration" + " parameter. Got: " << getServerTagsAsText(server_selector)); + } + MySqlBindingCollection in_bindings = { MySqlBinding::createString(value->getName()), MySqlBinding::createString(value->getValue()), MySqlBinding::createTimestamp(value->getModificationTime()), + MySqlBinding::createString(*tags.begin()), MySqlBinding::createString(value->getName()) }; @@ -189,7 +212,27 @@ public: in_bindings.pop_back(); conn_.insertQuery(MySqlConfigBackendDHCPv4Impl::INSERT_GLOBAL_PARAMETER4, in_bindings); + + // Successfully inserted global parameter. Now, we have to associate it + // with the server tag. + + // Let's first get the primary key of the global parameter. + uint64_t id = mysql_insert_id(conn_.mysql_); + + // Create bindings for inserting the association into + // dhcp4_global_parameter_server table. + MySqlBindingCollection in_server_bindings = { + MySqlBinding::createInteger(id), // parameter_id + MySqlBinding::createString(*tags.begin()), // tag used to obtain server_id + MySqlBinding::createTimestamp(value->getModificationTime()), // modification_ts + }; + + // Insert association. + conn_.insertQuery(MySqlConfigBackendDHCPv4Impl::INSERT_GLOBAL_PARAMETER4_SERVER, + in_server_bindings); } + + transaction.commit(); } /// @brief Sends query to the database to retrieve multiple subnets. @@ -1519,36 +1562,49 @@ TaggedStatementArray tagged_statements = { { // Select global parameter by name. { MySqlConfigBackendDHCPv4Impl::GET_GLOBAL_PARAMETER4, "SELECT" - " id," - " name," - " value," - " modification_ts " - "FROM dhcp4_global_parameter " - "WHERE name = ? " - "ORDER BY id" + " g.id," + " g.name," + " g.value," + " g.modification_ts " + "FROM dhcp4_global_parameter AS g " + "INNER JOIN dhcp4_global_parameter_server AS a " + " ON g.id = a.parameter_id " + "INNER JOIN dhcp4_server AS s " + " ON a.server_id = s.id " + "WHERE s.tag = ? AND g.name = ? " + "ORDER BY g.id" }, // Select all global parameters. { MySqlConfigBackendDHCPv4Impl::GET_ALL_GLOBAL_PARAMETERS4, "SELECT" - " id," - " name," - " value," - " modification_ts " - "FROM dhcp4_global_parameter " - "ORDER BY id" + " g.id," + " g.name," + " g.value," + " g.modification_ts " + "FROM dhcp4_global_parameter AS g " + "INNER JOIN dhcp4_global_parameter_server AS a " + " ON g.id = a.parameter_id " + "INNER JOIN dhcp4_server AS s " + " ON a.server_id = s.id " + "WHERE s.tag = ? " + "ORDER BY g.id" }, // Select modified global parameters. { MySqlConfigBackendDHCPv4Impl::GET_MODIFIED_GLOBAL_PARAMETERS4, "SELECT" - " id," - " name," - " value," - " modification_ts " - "FROM dhcp4_global_parameter " - "WHERE modification_ts > ? " - "ORDER BY id" + " g.id," + " g.name," + " g.value," + " g.modification_ts " + "FROM dhcp4_global_parameter AS g " + "INNER JOIN dhcp4_global_parameter_server AS a " + " ON g.id = a.parameter_id " + "INNER JOIN dhcp4_server AS s " + " ON a.server_id = s.id " + "WHERE s.tag = ? AND g.modification_ts > ? " + "ORDER BY g.id" }, // Select subnet by id. @@ -2088,6 +2144,14 @@ TaggedStatementArray tagged_statements = { { " modification_ts" ") VALUES (?, ?, ?)" }, + // Insert association of the global parameter with a server. + { MySqlConfigBackendDHCPv4Impl::INSERT_GLOBAL_PARAMETER4_SERVER, + "INSERT INTO dhcp4_global_parameter_server(" + " parameter_id," + " server_id," + " modification_ts" + ") VALUES (?, (SELECT id FROM dhcp4_server WHERE tag = ?), ?)" }, + // Insert a subnet. { MySqlConfigBackendDHCPv4Impl::INSERT_SUBNET4, "INSERT INTO dhcp4_subnet(" @@ -2173,11 +2237,17 @@ TaggedStatementArray tagged_statements = { { // Update existing global parameter. { MySqlConfigBackendDHCPv4Impl::UPDATE_GLOBAL_PARAMETER4, - "UPDATE dhcp4_global_parameter SET" - " name = ?," - " value = ?," - " modification_ts = ? " - "WHERE name = ?" }, + "UPDATE dhcp4_global_parameter AS g " + "INNER JOIN dhcp4_global_parameter_server AS a" + " ON g.id = a.parameter_id " + "INNER JOIN dhcp4_server AS s" + " ON a.server_id = s.id " + "SET" + " g.name = ?," + " g.value = ?," + " g.modification_ts = ? " + "WHERE s.tag = ? AND g.name = ?" + }, // Update existing subnet. { MySqlConfigBackendDHCPv4Impl::UPDATE_SUBNET4, @@ -2514,10 +2584,14 @@ MySqlConfigBackendDHCPv4::getGlobalParameter4(const ServerSelector& server_selec StampedValueCollection MySqlConfigBackendDHCPv4::getAllGlobalParameters4(const ServerSelector& /* server_selector */) const { - MySqlBindingCollection in_bindings; StampedValueCollection parameters; - impl_->getGlobalParameters4(MySqlConfigBackendDHCPv4Impl::GET_ALL_GLOBAL_PARAMETERS4, - in_bindings, parameters); + + auto tags = impl_->getServerTags(server_selector); + for (auto tag : tags) { + MySqlBindingCollection in_bindings = { MySqlBinding::createString(tag) }; + impl_->getGlobalParameters4(MySqlConfigBackendDHCPv4Impl::GET_ALL_GLOBAL_PARAMETERS4, + in_bindings, parameters); + } return (parameters); } @@ -2525,12 +2599,18 @@ StampedValueCollection MySqlConfigBackendDHCPv4:: getModifiedGlobalParameters4(const db::ServerSelector& /* server_selector */, const boost::posix_time::ptime& modification_time) const { - MySqlBindingCollection in_bindings = { - MySqlBinding::createTimestamp(modification_time) - }; StampedValueCollection parameters; - impl_->getGlobalParameters4(MySqlConfigBackendDHCPv4Impl::GET_MODIFIED_GLOBAL_PARAMETERS4, - in_bindings, parameters); + + auto tags = impl_->getServerTags(server_selector); + for (auto tag : tags) { + MySqlBindingCollection in_bindings = { + MySqlBinding::createString(tag), + MySqlBinding::createTimestamp(modification_time) + }; + impl_->getGlobalParameters4(MySqlConfigBackendDHCPv4Impl::GET_MODIFIED_GLOBAL_PARAMETERS4, + in_bindings, parameters); + } + return (parameters); } diff --git a/src/hooks/dhcp/mysql_cb/mysql_cb_impl.cc b/src/hooks/dhcp/mysql_cb/mysql_cb_impl.cc index 94ec71f0ca..f08059d21f 100644 --- a/src/hooks/dhcp/mysql_cb/mysql_cb_impl.cc +++ b/src/hooks/dhcp/mysql_cb/mysql_cb_impl.cc @@ -15,6 +15,7 @@ #include #include #include +#include #include using namespace isc::cb; @@ -67,6 +68,40 @@ MySqlConfigBackendImpl::~MySqlConfigBackendImpl() { } } +std::set +MySqlConfigBackendImpl::getServerTags(const ServerSelector& server_selector) const { + std::set tags; + switch (server_selector.getType()) { + case ServerSelector::Type::UNASSIGNED: + tags.insert("unassigned"); + return (tags); + + case ServerSelector::Type::ALL: + tags.insert("all"); + return (tags); + + default: + return (server_selector.getTags()); + } + + // Impossible condition. + return (tags); +} + +std::string +MySqlConfigBackendImpl::getServerTagsAsText(const db::ServerSelector& server_selector) const { + std::ostringstream s; + auto server_tags = getServerTags(server_selector); + for (auto tag : server_tags) { + if (s.tellp() != 0) { + s << ", "; + } + s << tag; + } + + return (s.str()); +} + uint64_t MySqlConfigBackendImpl::deleteFromTable(const int index) { MySqlBindingCollection 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 dff9de8282..09e127c6d1 100644 --- a/src/hooks/dhcp/mysql_cb/mysql_cb_impl.h +++ b/src/hooks/dhcp/mysql_cb/mysql_cb_impl.h @@ -8,12 +8,14 @@ #define MYSQL_CONFIG_BACKEND_IMPL_H #include +#include #include #include #include #include #include #include +#include #include namespace isc { @@ -35,6 +37,18 @@ public: /// @brief Destructor. ~MySqlConfigBackendImpl(); + /// @brief Returns server tags associated with the particular selector. + /// + /// @param server_selector Server selector. + /// @return Set of server tags. + std::set getServerTags(const db::ServerSelector& server_selector) const; + + /// @brief Returns server tags associated with the particular selector + /// as text. + /// + /// This method is useful for logging purposes. + std::string getServerTagsAsText(const db::ServerSelector& server_selector) const; + /// @brief Sends query to delete rows from a table. /// /// @param index Index of the statement to be executed. 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 edfadc1dc8..662a3e7b8f 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 @@ -306,6 +306,8 @@ public: // deleted. TEST_F(MySqlConfigBackendDHCPv4Test, createUpdateDeleteGlobalParameter4) { StampedValuePtr server_tag = StampedValue::create("server-tag", "whale"); + StampedValuePtr original_server_tag = server_tag; + // Explicitly set modification time to make sure that the time // returned from the database is correct. server_tag->setModificationTime(timestamps_["yesterday"]); @@ -321,6 +323,25 @@ TEST_F(MySqlConfigBackendDHCPv4Test, createUpdateDeleteGlobalParameter4) { EXPECT_TRUE(returned_server_tag->getModificationTime() == server_tag->getModificationTime()); + // Check that the parameter is not returned when the server tag is not + // matching. + returned_server_tag = cbptr_->getGlobalParameter4(ServerSelector::ALL(), + "server-tag"); + EXPECT_FALSE(returned_server_tag); + + // Check that the parameter is not updated when the server tag is not + // matching. + server_tag = StampedValue::create("server-tag", "fish"); + cbptr_->createUpdateGlobalParameter4(ServerSelector::ALL(), + server_tag); + returned_server_tag = cbptr_->getGlobalParameter4(ServerSelector::UNASSIGNED() + , "server-tag"); + ASSERT_TRUE(returned_server_tag); + EXPECT_EQ("server-tag", returned_server_tag->getName()); + EXPECT_EQ("whale", returned_server_tag->getValue()); + EXPECT_TRUE(returned_server_tag->getModificationTime() == + original_server_tag->getModificationTime()); + // Check that the parameter is udpated when it already exists in // the database. server_tag = StampedValue::create("server-tag", "fish");