Commit bffc9fae authored by Marcin Siodelski's avatar Marcin Siodelski

[#93,!63] Implemented server selection for global parameters in MySQL.

parent 73ba94b1
...@@ -71,6 +71,7 @@ public: ...@@ -71,6 +71,7 @@ public:
GET_OPTION4_POOL_ID_CODE_SPACE, GET_OPTION4_POOL_ID_CODE_SPACE,
GET_OPTION4_SHARED_NETWORK_CODE_SPACE, GET_OPTION4_SHARED_NETWORK_CODE_SPACE,
INSERT_GLOBAL_PARAMETER4, INSERT_GLOBAL_PARAMETER4,
INSERT_GLOBAL_PARAMETER4_SERVER,
INSERT_SUBNET4, INSERT_SUBNET4,
INSERT_POOL4, INSERT_POOL4,
INSERT_SHARED_NETWORK4, INSERT_SHARED_NETWORK4,
...@@ -156,12 +157,17 @@ public: ...@@ -156,12 +157,17 @@ public:
/// doesn't exist. /// doesn't exist.
StampedValuePtr getGlobalParameter4(const ServerSelector& /* server_selector */, StampedValuePtr getGlobalParameter4(const ServerSelector& /* server_selector */,
const std::string& name) { const std::string& name) {
MySqlBindingCollection in_bindings = {
MySqlBinding::createString(name)
};
StampedValueCollection parameters; 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()); return (parameters.empty() ? StampedValuePtr() : *parameters.begin());
} }
...@@ -173,10 +179,27 @@ public: ...@@ -173,10 +179,27 @@ public:
/// @param value Value of the global parameter. /// @param value Value of the global parameter.
void createUpdateGlobalParameter4(const db::ServerSelector& /* server_selector */, void createUpdateGlobalParameter4(const db::ServerSelector& /* server_selector */,
const StampedValuePtr& value) { 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 = { MySqlBindingCollection in_bindings = {
MySqlBinding::createString(value->getName()), MySqlBinding::createString(value->getName()),
MySqlBinding::createString(value->getValue()), MySqlBinding::createString(value->getValue()),
MySqlBinding::createTimestamp(value->getModificationTime()), MySqlBinding::createTimestamp(value->getModificationTime()),
MySqlBinding::createString(*tags.begin()),
MySqlBinding::createString(value->getName()) MySqlBinding::createString(value->getName())
}; };
...@@ -189,7 +212,27 @@ public: ...@@ -189,7 +212,27 @@ public:
in_bindings.pop_back(); in_bindings.pop_back();
conn_.insertQuery(MySqlConfigBackendDHCPv4Impl::INSERT_GLOBAL_PARAMETER4, conn_.insertQuery(MySqlConfigBackendDHCPv4Impl::INSERT_GLOBAL_PARAMETER4,
in_bindings); 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<uint64_t>(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. /// @brief Sends query to the database to retrieve multiple subnets.
...@@ -1519,36 +1562,49 @@ TaggedStatementArray tagged_statements = { { ...@@ -1519,36 +1562,49 @@ TaggedStatementArray tagged_statements = { {
// Select global parameter by name. // Select global parameter by name.
{ MySqlConfigBackendDHCPv4Impl::GET_GLOBAL_PARAMETER4, { MySqlConfigBackendDHCPv4Impl::GET_GLOBAL_PARAMETER4,
"SELECT" "SELECT"
" id," " g.id,"
" name," " g.name,"
" value," " g.value,"
" modification_ts " " g.modification_ts "
"FROM dhcp4_global_parameter " "FROM dhcp4_global_parameter AS g "
"WHERE name = ? " "INNER JOIN dhcp4_global_parameter_server AS a "
"ORDER BY id" " 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. // Select all global parameters.
{ MySqlConfigBackendDHCPv4Impl::GET_ALL_GLOBAL_PARAMETERS4, { MySqlConfigBackendDHCPv4Impl::GET_ALL_GLOBAL_PARAMETERS4,
"SELECT" "SELECT"
" id," " g.id,"
" name," " g.name,"
" value," " g.value,"
" modification_ts " " g.modification_ts "
"FROM dhcp4_global_parameter " "FROM dhcp4_global_parameter AS g "
"ORDER BY id" "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. // Select modified global parameters.
{ MySqlConfigBackendDHCPv4Impl::GET_MODIFIED_GLOBAL_PARAMETERS4, { MySqlConfigBackendDHCPv4Impl::GET_MODIFIED_GLOBAL_PARAMETERS4,
"SELECT" "SELECT"
" id," " g.id,"
" name," " g.name,"
" value," " g.value,"
" modification_ts " " g.modification_ts "
"FROM dhcp4_global_parameter " "FROM dhcp4_global_parameter AS g "
"WHERE modification_ts > ? " "INNER JOIN dhcp4_global_parameter_server AS a "
"ORDER BY id" " 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. // Select subnet by id.
...@@ -2088,6 +2144,14 @@ TaggedStatementArray tagged_statements = { { ...@@ -2088,6 +2144,14 @@ TaggedStatementArray tagged_statements = { {
" modification_ts" " modification_ts"
") VALUES (?, ?, ?)" }, ") 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. // Insert a subnet.
{ MySqlConfigBackendDHCPv4Impl::INSERT_SUBNET4, { MySqlConfigBackendDHCPv4Impl::INSERT_SUBNET4,
"INSERT INTO dhcp4_subnet(" "INSERT INTO dhcp4_subnet("
...@@ -2173,11 +2237,17 @@ TaggedStatementArray tagged_statements = { { ...@@ -2173,11 +2237,17 @@ TaggedStatementArray tagged_statements = { {
// Update existing global parameter. // Update existing global parameter.
{ MySqlConfigBackendDHCPv4Impl::UPDATE_GLOBAL_PARAMETER4, { MySqlConfigBackendDHCPv4Impl::UPDATE_GLOBAL_PARAMETER4,
"UPDATE dhcp4_global_parameter SET" "UPDATE dhcp4_global_parameter AS g "
" name = ?," "INNER JOIN dhcp4_global_parameter_server AS a"
" value = ?," " ON g.id = a.parameter_id "
" modification_ts = ? " "INNER JOIN dhcp4_server AS s"
"WHERE name = ?" }, " ON a.server_id = s.id "
"SET"
" g.name = ?,"
" g.value = ?,"
" g.modification_ts = ? "
"WHERE s.tag = ? AND g.name = ?"
},
// Update existing subnet. // Update existing subnet.
{ MySqlConfigBackendDHCPv4Impl::UPDATE_SUBNET4, { MySqlConfigBackendDHCPv4Impl::UPDATE_SUBNET4,
...@@ -2514,10 +2584,14 @@ MySqlConfigBackendDHCPv4::getGlobalParameter4(const ServerSelector& server_selec ...@@ -2514,10 +2584,14 @@ MySqlConfigBackendDHCPv4::getGlobalParameter4(const ServerSelector& server_selec
StampedValueCollection StampedValueCollection
MySqlConfigBackendDHCPv4::getAllGlobalParameters4(const ServerSelector& /* server_selector */) const { MySqlConfigBackendDHCPv4::getAllGlobalParameters4(const ServerSelector& /* server_selector */) const {
MySqlBindingCollection in_bindings;
StampedValueCollection parameters; 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); return (parameters);
} }
...@@ -2525,12 +2599,18 @@ StampedValueCollection ...@@ -2525,12 +2599,18 @@ StampedValueCollection
MySqlConfigBackendDHCPv4:: MySqlConfigBackendDHCPv4::
getModifiedGlobalParameters4(const db::ServerSelector& /* server_selector */, getModifiedGlobalParameters4(const db::ServerSelector& /* server_selector */,
const boost::posix_time::ptime& modification_time) const { const boost::posix_time::ptime& modification_time) const {
MySqlBindingCollection in_bindings = {
MySqlBinding::createTimestamp(modification_time)
};
StampedValueCollection parameters; 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); return (parameters);
} }
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <mysql.h> #include <mysql.h>
#include <mysqld_error.h> #include <mysqld_error.h>
#include <cstdint> #include <cstdint>
#include <sstream>
#include <utility> #include <utility>
using namespace isc::cb; using namespace isc::cb;
...@@ -67,6 +68,40 @@ MySqlConfigBackendImpl::~MySqlConfigBackendImpl() { ...@@ -67,6 +68,40 @@ MySqlConfigBackendImpl::~MySqlConfigBackendImpl() {
} }
} }
std::set<std::string>
MySqlConfigBackendImpl::getServerTags(const ServerSelector& server_selector) const {
std::set<std::string> 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 uint64_t
MySqlConfigBackendImpl::deleteFromTable(const int index) { MySqlConfigBackendImpl::deleteFromTable(const int index) {
MySqlBindingCollection in_bindings; MySqlBindingCollection in_bindings;
......
...@@ -8,12 +8,14 @@ ...@@ -8,12 +8,14 @@
#define MYSQL_CONFIG_BACKEND_IMPL_H #define MYSQL_CONFIG_BACKEND_IMPL_H
#include <database/database_connection.h> #include <database/database_connection.h>
#include <database/server_selector.h>
#include <dhcp/option.h> #include <dhcp/option.h>
#include <dhcp/option_definition.h> #include <dhcp/option_definition.h>
#include <dhcpsrv/cfg_option.h> #include <dhcpsrv/cfg_option.h>
#include <dhcpsrv/network.h> #include <dhcpsrv/network.h>
#include <mysql/mysql_binding.h> #include <mysql/mysql_binding.h>
#include <mysql/mysql_connection.h> #include <mysql/mysql_connection.h>
#include <set>
#include <string> #include <string>
namespace isc { namespace isc {
...@@ -35,6 +37,18 @@ public: ...@@ -35,6 +37,18 @@ public:
/// @brief Destructor. /// @brief Destructor.
~MySqlConfigBackendImpl(); ~MySqlConfigBackendImpl();
/// @brief Returns server tags associated with the particular selector.
///
/// @param server_selector Server selector.
/// @return Set of server tags.
std::set<std::string> 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. /// @brief Sends query to delete rows from a table.
/// ///
/// @param index Index of the statement to be executed. /// @param index Index of the statement to be executed.
......
...@@ -306,6 +306,8 @@ public: ...@@ -306,6 +306,8 @@ public:
// deleted. // deleted.
TEST_F(MySqlConfigBackendDHCPv4Test, createUpdateDeleteGlobalParameter4) { TEST_F(MySqlConfigBackendDHCPv4Test, createUpdateDeleteGlobalParameter4) {
StampedValuePtr server_tag = StampedValue::create("server-tag", "whale"); StampedValuePtr server_tag = StampedValue::create("server-tag", "whale");
StampedValuePtr original_server_tag = server_tag;
// Explicitly set modification time to make sure that the time // Explicitly set modification time to make sure that the time
// returned from the database is correct. // returned from the database is correct.
server_tag->setModificationTime(timestamps_["yesterday"]); server_tag->setModificationTime(timestamps_["yesterday"]);
...@@ -321,6 +323,25 @@ TEST_F(MySqlConfigBackendDHCPv4Test, createUpdateDeleteGlobalParameter4) { ...@@ -321,6 +323,25 @@ TEST_F(MySqlConfigBackendDHCPv4Test, createUpdateDeleteGlobalParameter4) {
EXPECT_TRUE(returned_server_tag->getModificationTime() == EXPECT_TRUE(returned_server_tag->getModificationTime() ==
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 // Check that the parameter is udpated when it already exists in
// the database. // the database.
server_tag = StampedValue::create("server-tag", "fish"); server_tag = StampedValue::create("server-tag", "fish");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment