Commit 90a950d1 authored by Marcin Siodelski's avatar Marcin Siodelski
Browse files

[#642,!373] Extended StampedElement to hold multiple server tags.

parent 4b491c08
......@@ -5,7 +5,8 @@ AM_CPPFLAGS += $(BOOST_INCLUDES)
AM_CXXFLAGS = $(KEA_CXXFLAGS)
lib_LTLIBRARIES = libkea-cc.la
libkea_cc_la_SOURCES = data.cc data.h
libkea_cc_la_SOURCES = base_stamped_element.cc base_stamped_element.h
libkea_cc_la_SOURCES += data.cc data.h
libkea_cc_la_SOURCES += element_value.h
libkea_cc_la_SOURCES += cfg_to_element.h dhcp_config_error.h
libkea_cc_la_SOURCES += command_interpreter.cc command_interpreter.h
......@@ -26,6 +27,7 @@ libkea_cc_la_LDFLAGS = -no-undefined -version-info 8:0:0
# Specify the headers for copying into the installation directory tree.
libkea_cc_includedir = $(pkgincludedir)/cc
libkea_cc_include_HEADERS = \
base_stamped_element.h \
cfg_to_element.h \
command_interpreter.h \
data.h \
......
// Copyright (C) 2019 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
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <cc/base_stamped_element.h>
namespace isc {
namespace data {
BaseStampedElement::BaseStampedElement()
/// @todo Change it to microsec_clock once we transition to subsecond
/// precision.
: id_(0), timestamp_(boost::posix_time::second_clock::local_time()) {
}
void
BaseStampedElement::updateModificationTime() {
/// @todo Change it to microsec_clock once we transition to subsecond
/// precision.
setModificationTime(boost::posix_time::second_clock::local_time());
}
} // end of namespace isc::data
} // end of namespace isc
// Copyright (C) 2019 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
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef BASE_STAMPED_ELEMENT_H
#define BASE_STAMPED_ELEMENT_H
#include <cc/data.h>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <cstdint>
namespace isc {
namespace data {
/// @brief This class represents configuration element which is
/// associated with database identifier and the modification
/// timestamp.
///
/// The @c StampedElement class derives from this class to extend
/// it with the capability to associate the configuration elements
/// with server tags. The @c db::Server class derives from it to
/// store a single server tag identifying a server it describes.
///
/// @note This class is not derived from @c Element and should not
/// be confused with the classes being derived from @c Element class.
/// Those classes are used to represent JSON structures, whereas this
/// class represents data fetched from the database.
class BaseStampedElement {
public:
/// @brief Constructor.
///
/// Sets timestamp to the current time.
BaseStampedElement();
/// @brief Sets element's database identifier.
///
/// @param id New id.
void setId(const uint64_t id) {
id_ = id;
}
/// @brief Returns element's database identifier.
uint64_t getId() const {
return (id_);
}
/// @brief Sets timestamp to the explicitly provided value.
///
/// @param timestamp New timestamp value.
void setModificationTime(const boost::posix_time::ptime& timestamp) {
timestamp_ = timestamp;
}
/// @brief Sets timestmp to the current time.
void updateModificationTime();
/// @brief Returns timestamp.
boost::posix_time::ptime getModificationTime() const {
return (timestamp_);
}
protected:
/// @brief Database identifier of the configuration element.
///
/// The default value of 0 indicates that the identifier is
/// not set.
uint64_t id_;
/// @brief Holds timestamp value.
boost::posix_time::ptime timestamp_;
};
} // end of namespace isc::data
} // end of namespace isc
#endif
......@@ -10,33 +10,35 @@ namespace isc {
namespace data {
StampedElement::StampedElement()
/// @todo Change it to microsec_clock once we transition to subsecond
/// precision.
: id_(0), timestamp_(boost::posix_time::second_clock::local_time()),
server_tag_() {
: BaseStampedElement(), server_tags_() {
}
void
StampedElement::updateModificationTime() {
/// @todo Change it to microsec_clock once we transition to subsecond
/// precision.
setModificationTime(boost::posix_time::second_clock::local_time());
}
std::string
StampedElement:: getServerTag() const {
return (server_tag_.get());
bool
StampedElement::hasServerTag(const ServerTag& server_tag) const {
for (auto tag : server_tags_) {
if (tag.get() == server_tag.get()) {
return (true);
}
}
return (false);
}
bool
StampedElement::allServers() const {
return (server_tag_.amAll());
StampedElement::hasAllServerTag() const {
return (hasServerTag(ServerTag(ServerTag::ALL)));
}
ElementPtr
StampedElement::getMetadata() const {
ElementPtr metadata = Element::createMap();
metadata->set("server-tag", Element::create(getServerTag()));
ElementPtr tags = Element::createList();
for (auto server_tag : server_tags_) {
tags->add(Element::create(server_tag.get()));
}
metadata->set("server-tags", tags);
return (metadata);
}
......
......@@ -7,19 +7,16 @@
#ifndef STAMPED_ELEMENT_H
#define STAMPED_ELEMENT_H
#include <cc/data.h>
#include <cc/base_stamped_element.h>
#include <cc/server_tag.h>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/scoped_ptr.hpp>
#include <cstdint>
#include <string>
#include <vector>
namespace isc {
namespace data {
/// @brief This class represents configuration element which is
/// associated with database identifier and the modification
/// timestamp.
/// associated with database identifiee, modification timestamp
/// and servers.
///
/// Classes storing Kea configuration should derive from this object
/// to track ids and modification times of the configuration objects.
......@@ -33,8 +30,8 @@ namespace data {
/// Those classes are used to represent JSON structures, whereas this
/// class represents data fetched from the database.
///
/// @todo Find a better name for @c StamepedElement.
class StampedElement {
/// @todo Find a better name for @c StampedElement.
class StampedElement : public BaseStampedElement {
public:
/// @brief Constructor.
......@@ -42,51 +39,31 @@ public:
/// Sets timestamp to the current time.
StampedElement();
/// @brief Sets element's database identifier.
///
/// @param id New id.
void setId(const uint64_t id) {
id_ = id;
}
/// @brief Returns element's database identifier.
uint64_t getId() const {
return (id_);
}
/// @brief Sets timestamp to the explicitly provided value.
///
/// @param timestamp New timestamp value.
void setModificationTime(const boost::posix_time::ptime& timestamp) {
timestamp_ = timestamp;
}
/// @brief Sets timestmp to the current time.
void updateModificationTime();
/// @brief Returns timestamp.
boost::posix_time::ptime getModificationTime() const {
return (timestamp_);
}
/// @brief Sets new server tag.
/// @brief Adds new server tag.
///
/// @param server_tag new server tag.
/// @throw BadValue if the server tag length exceeds 256 characters.
void setServerTag(const std::string& server_tag) {
server_tag_ = ServerTag(server_tag);
server_tags_.push_back(ServerTag(server_tag));
}
/// @brief Returns server tag.
/// @brief Returns server tags.
///
/// @return Server tag as string.
std::string getServerTag() const;
std::vector<ServerTag> getServerTags() const {
return (server_tags_);
}
/// @brief Checks if the element has the given server tag.
///
/// @param server_tag Server tag to be found.
/// @return true if the server tag was found, false otherwise.
bool hasServerTag(const ServerTag& server_tag) const;
/// @brief Checks if the stamped element is for all servers.
/// @brief Checks if the element has 'all' server tag.
///
/// @return true if the stamped element is associated with all servers,
/// false otherwise.
bool allServers() const;
/// @return true if the server tag was found, false otherwise.
bool hasAllServerTag() const;
/// @brief Returns an object representing metadata to be returned
/// with objects from the configuration backend.
......@@ -96,17 +73,8 @@ public:
private:
/// @brief Database identifier of the configuration element.
///
/// The default value of 0 indicates that the identifier is
/// not set.
uint64_t id_;
/// @brief Holds timestamp value.
boost::posix_time::ptime timestamp_;
/// @brief Holds server tag.
ServerTag server_tag_;
/// @brief Holds server tags.
std::vector<ServerTag> server_tags_;
};
} // end of namespace isc::data
......
......@@ -221,9 +221,9 @@ typedef boost::multi_index_container<
boost::multi_index::ordered_non_unique<
boost::multi_index::tag<StampedValueModificationTimeIndexTag>,
boost::multi_index::const_mem_fun<
StampedElement,
BaseStampedElement,
boost::posix_time::ptime,
&StampedElement::getModificationTime
&BaseStampedElement::getModificationTime
>
>
>
......
......@@ -23,8 +23,8 @@ TEST(StampedElementTest, create) {
// Default identifier is 0.
EXPECT_EQ(0, element.getId());
// Default server tag is 'all'.
EXPECT_EQ(ServerTag::ALL, element.getServerTag());
// By default there is no server tag.
EXPECT_TRUE(element.getServerTags().empty());
// Checking that the delta between now and the timestamp is within
// 5s range should be sufficient.
......@@ -70,11 +70,25 @@ TEST(StampedElementTest, update) {
EXPECT_LT(delta.seconds(), 5);
}
// Tests that server tag can be overriden by a new value.
TEST(StampedElementTest, setServerTag) {
// Tests that one or more server tag can be specified.
TEST(StampedElementTest, setServerTags) {
StampedElement element;
element.setServerTag("foo");
EXPECT_EQ("foo", element.getServerTag());
EXPECT_EQ(1, element.getServerTags().size());
EXPECT_EQ("foo", element.getServerTags()[0].get());
element.setServerTag("bar");
EXPECT_EQ(2, element.getServerTags().size());
EXPECT_EQ("foo", element.getServerTags()[0].get());
EXPECT_EQ("bar", element.getServerTags()[1].get());
EXPECT_TRUE(element.hasServerTag(ServerTag("foo")));
EXPECT_TRUE(element.hasServerTag(ServerTag("bar")));
EXPECT_FALSE(element.hasServerTag(ServerTag("xyz")));
EXPECT_FALSE(element.hasAllServerTag());
element.setServerTag(ServerTag::ALL);
EXPECT_TRUE(element.hasAllServerTag());
}
// Test that metadata can be created from the StampedElement.
......@@ -85,7 +99,12 @@ TEST(StampedElementTest, getMetadata) {
ASSERT_TRUE(metadata);
ASSERT_EQ(Element::map, metadata->getType());
auto server_tag_element = metadata->get("server-tag");
auto server_tags_element = metadata->get("server-tags");
ASSERT_TRUE(server_tags_element);
EXPECT_EQ(Element::list, server_tags_element->getType());
EXPECT_EQ(1, server_tags_element->size());
auto server_tag_element = server_tags_element->get(0);
ASSERT_TRUE(server_tag_element);
EXPECT_EQ(Element::string, server_tag_element->getType());
EXPECT_EQ("world", server_tag_element->stringValue());
......
......@@ -15,14 +15,12 @@ namespace isc {
namespace db {
Server::Server(const ServerTag& tag, const std::string& description)
: StampedElement(), description_(description) {
: BaseStampedElement(), server_tag_(tag), description_(description) {
if (description_.length() > 65536) {
isc_throw(BadValue, "server description must not be longer than"
" 65536 characters");
}
setServerTag(tag.get());
}
ServerPtr
......
......@@ -7,7 +7,8 @@
#ifndef DB_SERVER_H
#define DB_SERVER_H
#include <cc/stamped_element.h>
#include <cc/base_stamped_element.h>
#include <cc/server_tag.h>
#include <boost/shared_ptr.hpp>
#include <string>
......@@ -27,7 +28,7 @@ typedef boost::shared_ptr<Server> ServerPtr;
/// provided by the administrator and the metadata.
///
/// This class extends the base class with the server description field.
class Server : public data::StampedElement {
class Server : public data::BaseStampedElement {
public:
/// @brief Constructor.
......@@ -48,6 +49,18 @@ public:
static ServerPtr create(const data::ServerTag& tag,
const std::string& description = "");
/// @brief Returns server tag.
data::ServerTag getServerTag() const {
return (server_tag_);
}
/// @brief Returns server tag as text.
///
/// @return Server tag as text.
std::string getServerTagAsText() const {
return (server_tag_.get());
}
/// @brief Returns the description of the server.
///
/// @return Description of the server or an empty string if no
......@@ -58,6 +71,9 @@ public:
private:
/// @brief Server tag.
data::ServerTag server_tag_;
/// @brief Description of the server.
std::string description_;
};
......
......@@ -28,8 +28,8 @@ typedef boost::multi_index_container<
boost::multi_index::indexed_by<
boost::multi_index::ordered_unique<
boost::multi_index::tag<ServerTagIndexTag>,
boost::multi_index::const_mem_fun<data::StampedElement, std::string,
&Server::getServerTag>
boost::multi_index::const_mem_fun<Server, std::string,
&Server::getServerTagAsText>
>
>
> ServerCollection;
......
......@@ -24,7 +24,7 @@ TEST(ServerTest, constructor) {
server = Server::create(ServerTag("xyz"), "my first server")
);
ASSERT_TRUE(server);
EXPECT_EQ("xyz", server->getServerTag());
EXPECT_EQ("xyz", server->getServerTagAsText());
EXPECT_EQ("my first server", server->getDescription());
}
......@@ -47,17 +47,17 @@ TEST(ServerFetcherTest, getByTag) {
auto alpha = ServerFetcher::get(servers, ServerTag("alpha"));
ASSERT_TRUE(alpha);
EXPECT_EQ("alpha", alpha->getServerTag());
EXPECT_EQ("alpha", alpha->getServerTagAsText());
EXPECT_EQ("alpha description", alpha->getDescription());
auto beta = ServerFetcher::get(servers, ServerTag("beta"));
ASSERT_TRUE(beta);
EXPECT_EQ("beta", beta->getServerTag());
EXPECT_EQ("beta", beta->getServerTagAsText());
EXPECT_EQ("beta description", beta->getDescription());
auto gamma = ServerFetcher::get(servers, ServerTag("gamma"));
ASSERT_TRUE(gamma);
EXPECT_EQ("gamma", gamma->getServerTag());
EXPECT_EQ("gamma", gamma->getServerTagAsText());
EXPECT_EQ("gamma description", gamma->getDescription());
// Null pointer should be returned when a given server does not exist.
......
......@@ -891,9 +891,9 @@ typedef boost::multi_index_container<
// 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
// This value is returned by the BaseStampedElement::getModificationTime
boost::multi_index::const_mem_fun<
data::StampedElement,
data::BaseStampedElement,
boost::posix_time::ptime,
&data::StampedElement::getModificationTime
>
......@@ -902,8 +902,8 @@ typedef boost::multi_index_container<
// Use StampedElement::getId as a key.
boost::multi_index::hashed_non_unique<
boost::multi_index::tag<OptionIdIndexTag>,
boost::multi_index::const_mem_fun<data::StampedElement, uint64_t,
&data::StampedElement::getId>
boost::multi_index::const_mem_fun<data::BaseStampedElement, uint64_t,
&data::BaseStampedElement::getId>
>
>
> OptionDefContainer;
......
......@@ -233,21 +233,21 @@ typedef boost::multi_index_container<
>
>,
// Start definition of index #3.
// Use StampedElement::getModificationTime as a key.
// Use BaseStampedElement::getModificationTime as a key.
boost::multi_index::ordered_non_unique<
boost::multi_index::const_mem_fun<
data::StampedElement,
data::BaseStampedElement,
boost::posix_time::ptime,
&data::StampedElement::getModificationTime
&data::BaseStampedElement::getModificationTime
>
>,
// Start definition of index #4.
// Use StampedElement::getId as a key.
// Use BaseStampedElement::getId as a key.
boost::multi_index::hashed_non_unique<
boost::multi_index::tag<OptionIdIndexTag>,
boost::multi_index::const_mem_fun<data::StampedElement, uint64_t,
&data::StampedElement::getId>
boost::multi_index::const_mem_fun<data::BaseStampedElement, uint64_t,
&data::BaseStampedElement::getId>
>
>
> OptionContainer;
......
......@@ -232,8 +232,8 @@ typedef boost::multi_index_container<
// Second index allows for access by shared network id.
boost::multi_index::hashed_non_unique<
boost::multi_index::tag<SharedNetworkIdIndexTag>,
boost::multi_index::const_mem_fun<data::StampedElement, uint64_t,
&data::StampedElement::getId>
boost::multi_index::const_mem_fun<data::BaseStampedElement, uint64_t,
&data::BaseStampedElement::getId>
>,
// Third index allows for access by shared network's name.
boost::multi_index::ordered_unique<
......@@ -251,9 +251,9 @@ typedef boost::multi_index_container<
// Fifth index allows for searching using subnet modification time.
boost::multi_index::ordered_non_unique<
boost::multi_index::tag<SharedNetworkModificationTimeIndexTag>,
boost::multi_index::const_mem_fun<data::StampedElement,
boost::multi_index::const_mem_fun<data::BaseStampedElement,
boost::posix_time::ptime,
&data::StampedElement::getModificationTime>
&data::BaseStampedElement::getModificationTime>
>
>
> SharedNetwork4Collection;
......@@ -436,8 +436,8 @@ typedef boost::multi_index_container<
// Second index allows for access by shared network id.
boost::multi_index::hashed_non_unique<
boost::multi_index::tag<SharedNetworkIdIndexTag>,
boost::multi_index::const_mem_fun<data::StampedElement, uint64_t,
&data::StampedElement::getId>
boost::multi_index::const_mem_fun<data::BaseStampedElement, uint64_t,
&data::BaseStampedElement::getId>
>,
// Third index allows for access by shared network's name.
boost::multi_index::ordered_unique<
......@@ -448,9 +448,9 @@ typedef boost::multi_index_container<
// Fourth index allows for searching using subnet modification time.
boost::multi_index::ordered_non_unique<
boost::multi_index::tag<SharedNetworkModificationTimeIndexTag>,
boost::multi_index::const_mem_fun<data::StampedElement,
boost::multi_index::const_mem_fun<data::BaseStampedElement,
boost::posix_time::ptime,
&data::StampedElement::getModificationTime>
&data::BaseStampedElement::getModificationTime>
>
>
> SharedNetwork6Collection;
......
......@@ -796,9 +796,9 @@ typedef boost::multi_index_container<
// Fifth index allows for searching using subnet modification time.
boost::multi_index::ordered_non_unique<
boost::multi_index::tag<SubnetModificationTimeIndexTag>,
boost::multi_index::const_mem_fun<data::StampedElement,
boost::multi_index::const_mem_fun<data::BaseStampedElement,
boost::posix_time::ptime,
&data::StampedElement::getModificationTime>
&data::BaseStampedElement::getModificationTime>
>
>
> Subnet4Collection;
......@@ -848,9 +848,9 @@ typedef boost::multi_index_container<
// Fourth index allows for searching using subnet modification time.
boost::multi_index::ordered_non_unique<
boost::multi_index::tag<SubnetModificationTimeIndexTag>,
boost::multi_index::const_mem_fun<data::StampedElement,
boost::multi_index::const_mem_fun<data::BaseStampedElement,
boost::posix_time::ptime,
&data::StampedElement::getModificationTime>
&data::BaseStampedElement::getModificationTime>
>
>
> Subnet6Collection;
......
......@@ -367,7 +367,7 @@ TestConfigBackendDHCPv4::createUpdateGlobalParameter4(const db::ServerSelector&
void
TestConfigBackendDHCPv4::createUpdateServer4(const db::ServerPtr& server) {
auto& index = servers_.get<ServerTagIndexTag>();
auto server_it = index.find(server->getServerTag());
auto server_it = index.find(server->getServerTagAsText());
if (server_it != index.end()) {
index.replace(server_it, server);
......
......@@ -386,7 +386,7 @@ TestConfigBackendDHCPv6::createUpdateGlobalParameter6(const db::ServerSelector&
void
TestConfigBackendDHCPv6::createUpdateServer6(const db::ServerPtr& server) {
auto& index = servers_.get<ServerTagIndexTag>();
auto server_it = index.find(server->getServerTag());
auto server_it = index.find(server->getServerTagAsText());
if (server_it != index.end()) {