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:
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) {
StampedValueCollection parameters;
auto tags = getServerTags(server_selector);
for (auto tag : tags) {
MySqlBindingCollection in_bindings = {
MySqlBinding::createString(tag),
MySqlBinding::createString(name)
};
StampedValueCollection parameters;
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<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.
......@@ -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;
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 {
StampedValueCollection parameters;
auto tags = impl_->getServerTags(server_selector);
for (auto tag : tags) {
MySqlBindingCollection in_bindings = {
MySqlBinding::createString(tag),
MySqlBinding::createTimestamp(modification_time)
};
StampedValueCollection parameters;
impl_->getGlobalParameters4(MySqlConfigBackendDHCPv4Impl::GET_MODIFIED_GLOBAL_PARAMETERS4,
in_bindings, parameters);
}
return (parameters);
}
......
......@@ -15,6 +15,7 @@
#include <mysql.h>
#include <mysqld_error.h>
#include <cstdint>
#include <sstream>
#include <utility>
using namespace isc::cb;
......@@ -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
MySqlConfigBackendImpl::deleteFromTable(const int index) {
MySqlBindingCollection in_bindings;
......
......@@ -8,12 +8,14 @@
#define MYSQL_CONFIG_BACKEND_IMPL_H
#include <database/database_connection.h>
#include <database/server_selector.h>
#include <dhcp/option.h>
#include <dhcp/option_definition.h>
#include <dhcpsrv/cfg_option.h>
#include <dhcpsrv/network.h>
#include <mysql/mysql_binding.h>
#include <mysql/mysql_connection.h>
#include <set>
#include <string>
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<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.
///
/// @param index Index of the statement to be executed.
......
......@@ -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");
......
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