Commit dc80c465 authored by Marcin Siodelski's avatar Marcin Siodelski

[#716,!412] Documented and tested server selection for shared networks.

Also fixed the code where it accepted unsupported selectors. Implemented
deleting the unassigned subnets.
parent cc8b6fc5
......@@ -117,6 +117,7 @@ public:
DELETE_SHARED_NETWORK4_NAME_WITH_TAG,
DELETE_SHARED_NETWORK4_NAME_ANY,
DELETE_ALL_SHARED_NETWORKS4,
DELETE_ALL_SHARED_NETWORKS4_UNASSIGNED,
DELETE_SHARED_NETWORK4_SERVER,
DELETE_OPTION_DEF4_CODE_NAME,
DELETE_ALL_OPTION_DEFS4,
......@@ -1271,6 +1272,11 @@ public:
/// structure where shared networks should be inserted.
void getAllSharedNetworks4(const ServerSelector& server_selector,
SharedNetwork4Collection& shared_networks) {
if (server_selector.amAny()) {
isc_throw(InvalidOperation, "fetching all shared networks for ANY "
"server is not supported");
}
auto index = (server_selector.amUnassigned() ? GET_ALL_SHARED_NETWORKS4_UNASSIGNED :
GET_ALL_SHARED_NETWORKS4);
MySqlBindingCollection in_bindings;
......@@ -1286,6 +1292,11 @@ public:
void getModifiedSharedNetworks4(const ServerSelector& server_selector,
const boost::posix_time::ptime& modification_ts,
SharedNetwork4Collection& shared_networks) {
if (server_selector.amAny()) {
isc_throw(InvalidOperation, "fetching modified shared networks for ANY "
"server is not supported");
}
MySqlBindingCollection in_bindings = {
MySqlBinding::createTimestamp(modification_ts)
};
......@@ -1302,9 +1313,13 @@ public:
void createUpdateSharedNetwork4(const ServerSelector& server_selector,
const SharedNetwork4Ptr& shared_network) {
if (server_selector.amUnassigned()) {
isc_throw(NotImplemented, "managing configuration for no particular server"
" (unassigned) is unsupported at the moment");
if (server_selector.amAny()) {
isc_throw(InvalidOperation, "creating or updating a shared network for ANY"
" server is not supported");
} else if (server_selector.amUnassigned()) {
isc_throw(NotImplemented, "creating or updating a shared network without"
" assigning it to a server or all servers is not supported");
}
// Create binding for host reservation mode.
......@@ -2390,6 +2405,11 @@ TaggedStatementArray tagged_statements = { {
MYSQL_DELETE_SHARED_NETWORK_WITH_TAG(dhcp4)
},
// Delete all unassigned shared networks.
{ MySqlConfigBackendDHCPv4Impl::DELETE_ALL_SHARED_NETWORKS4_UNASSIGNED,
MYSQL_DELETE_SHARED_NETWORK_UNASSIGNED(dhcp4)
},
// Delete associations of a shared network with server.
{ MySqlConfigBackendDHCPv4Impl::DELETE_SHARED_NETWORK4_SERVER,
MYSQL_DELETE_SHARED_NETWORK_SERVER(dhcp4)
......@@ -2828,6 +2848,15 @@ MySqlConfigBackendDHCPv4::deleteSharedNetworkSubnets4(const db::ServerSelector&
uint64_t
MySqlConfigBackendDHCPv4::deleteSharedNetwork4(const ServerSelector& server_selector,
const std::string& name) {
/// @todo Using UNASSIGNED selector is allowed by the CB API but we don't have
/// dedicated query for this at the moment. The user should use ANY to delete
/// the shared network by name.
if (server_selector.amUnassigned()) {
isc_throw(NotImplemented, "deleting an unassigned shared network requires "
"an explicit server tag or using ANY server. The UNASSIGNED server "
"selector is currently not supported");
}
LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_SHARED_NETWORK4)
.arg(name);
......@@ -2844,9 +2873,17 @@ MySqlConfigBackendDHCPv4::deleteSharedNetwork4(const ServerSelector& server_sele
uint64_t
MySqlConfigBackendDHCPv4::deleteAllSharedNetworks4(const ServerSelector& server_selector) {
if (server_selector.amAny()) {
isc_throw(InvalidOperation, "deleting all shared networks for ANY server is not"
" supported");
}
LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_ALL_SHARED_NETWORKS4);
uint64_t result = impl_->deleteTransactional(MySqlConfigBackendDHCPv4Impl::DELETE_ALL_SHARED_NETWORKS4,
server_selector, "deleting all shared networks",
int index = (server_selector.amUnassigned() ?
MySqlConfigBackendDHCPv4Impl::DELETE_ALL_SHARED_NETWORKS4_UNASSIGNED :
MySqlConfigBackendDHCPv4Impl::DELETE_ALL_SHARED_NETWORKS4);
uint64_t result = impl_->deleteTransactional(index, server_selector, "deleting all shared networks",
"deleted all shared networks", true);
LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_ALL_SHARED_NETWORKS4_RESULT)
.arg(result);
......
......@@ -22,6 +22,11 @@ class MySqlConfigBackendDHCPv4Impl;
///
/// All POSIX times specified in the methods belonging to this
/// class must be local times.
///
/// The server selection mechanisms used by this backend generally adhere
/// to the rules described for @c ConfigBackendDHCPv4, but support for
/// some of the selectors is not implemented. Whenever this is the case,
/// the methods throw @c isc::NotImplemented exception.
class MySqlConfigBackendDHCPv4 : public ConfigBackendDHCPv4 {
public:
......
......@@ -123,6 +123,7 @@ public:
DELETE_SHARED_NETWORK6_NAME_WITH_TAG,
DELETE_SHARED_NETWORK6_NAME_ANY,
DELETE_ALL_SHARED_NETWORKS6,
DELETE_ALL_SHARED_NETWORKS6_UNASSIGNED,
DELETE_SHARED_NETWORK6_SERVER,
DELETE_OPTION_DEF6_CODE_NAME,
DELETE_ALL_OPTION_DEFS6,
......@@ -1474,6 +1475,11 @@ public:
/// structure where shared networks should be inserted.
void getAllSharedNetworks6(const ServerSelector& server_selector,
SharedNetwork6Collection& shared_networks) {
if (server_selector.amAny()) {
isc_throw(InvalidOperation, "fetching all shared networks for ANY "
"server is not supported");
}
auto index = (server_selector.amUnassigned() ? GET_ALL_SHARED_NETWORKS6_UNASSIGNED :
GET_ALL_SHARED_NETWORKS6);
MySqlBindingCollection in_bindings;
......@@ -1489,6 +1495,11 @@ public:
void getModifiedSharedNetworks6(const ServerSelector& server_selector,
const boost::posix_time::ptime& modification_ts,
SharedNetwork6Collection& shared_networks) {
if (server_selector.amAny()) {
isc_throw(InvalidOperation, "fetching modified shared networks for ANY "
"server is not supported");
}
MySqlBindingCollection in_bindings = {
MySqlBinding::createTimestamp(modification_ts)
};
......@@ -1505,7 +1516,11 @@ public:
void createUpdateSharedNetwork6(const ServerSelector& server_selector,
const SharedNetwork6Ptr& shared_network) {
if (server_selector.amUnassigned()) {
if (server_selector.amAny()) {
isc_throw(InvalidOperation, "creating or updating a shared network for ANY"
" server is not supported");
} else if (server_selector.amUnassigned()) {
isc_throw(NotImplemented, "managing configuration for no particular server"
" (unassigned) is unsupported at the moment");
}
......@@ -2752,6 +2767,11 @@ TaggedStatementArray tagged_statements = { {
MYSQL_DELETE_SHARED_NETWORK_WITH_TAG(dhcp6)
},
// Delete all unassigned shared networks.
{ MySqlConfigBackendDHCPv6Impl::DELETE_ALL_SHARED_NETWORKS6_UNASSIGNED,
MYSQL_DELETE_SHARED_NETWORK_UNASSIGNED(dhcp6)
},
// Delete associations of a shared network with server.
{ MySqlConfigBackendDHCPv6Impl::DELETE_SHARED_NETWORK6_SERVER,
MYSQL_DELETE_SHARED_NETWORK_SERVER(dhcp6)
......@@ -3221,8 +3241,17 @@ MySqlConfigBackendDHCPv6::deleteSharedNetwork6(const ServerSelector& server_sele
uint64_t
MySqlConfigBackendDHCPv6::deleteAllSharedNetworks6(const ServerSelector& server_selector) {
if (server_selector.amAny()) {
isc_throw(InvalidOperation, "deleting all shared networks for ANY server is not"
" supported");
}
LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_ALL_SHARED_NETWORKS6);
uint64_t result = impl_->deleteTransactional(MySqlConfigBackendDHCPv6Impl::DELETE_ALL_SHARED_NETWORKS6,
int index = (server_selector.amUnassigned() ?
MySqlConfigBackendDHCPv6Impl::DELETE_ALL_SHARED_NETWORKS6_UNASSIGNED :
MySqlConfigBackendDHCPv6Impl::DELETE_ALL_SHARED_NETWORKS6);
uint64_t result = impl_->deleteTransactional(index,
server_selector, "deleting all shared networks",
"deleted all shared networks", true);
LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_ALL_SHARED_NETWORKS6_RESULT)
......
......@@ -22,6 +22,11 @@ class MySqlConfigBackendDHCPv6Impl;
///
/// All POSIX times specified in the methods belonging to this
/// class must be local times.
///
/// The server selection mechanisms used by this backend generally adhere
/// to the rules described for @c ConfigBackendDHCPv6, but support for
/// some of the selectors is not implemented. Whenever this is the case,
/// the methods throw @c isc::NotImplemented exception.
class MySqlConfigBackendDHCPv6 : public ConfigBackendDHCPv6 {
public:
......
......@@ -236,6 +236,12 @@ uint64_t
MySqlConfigBackendImpl::deleteFromTable(const int index,
const ServerSelector& server_selector,
const std::string& operation) {
// When deleting multiple objects we must not use ANY server.
if (server_selector.amAny()) {
isc_throw(InvalidOperation, "deleting multiple objects for ANY server is not"
" supported");
}
MySqlBindingCollection in_bindings;
return (deleteFromTable(index, server_selector, operation, in_bindings));
}
......
......@@ -261,13 +261,8 @@ public:
const std::string& operation,
db::MySqlBindingCollection& in_bindings) {
if (server_selector.amUnassigned()) {
isc_throw(NotImplemented, "managing configuration for no particular server"
" (unassigned) is unsupported at the moment");
}
// For ANY server, we use queries that lack server tag.
if (!server_selector.amAny()) {
if (!server_selector.amAny() && !server_selector.amUnassigned()) {
auto tag = getServerTag(server_selector, operation);
in_bindings.insert(in_bindings.begin(), db::MySqlBinding::createString(tag));
}
......@@ -307,6 +302,13 @@ public:
const db::ServerSelector& server_selector,
const std::string& operation,
KeyType key) {
// When deleting by some key, we must use ANY.
if (server_selector.amUnassigned()) {
isc_throw(NotImplemented, "deleting an unassigned object requires "
"an explicit server tag or using ANY server. The UNASSIGNED "
"server selector is currently not supported");
}
db::MySqlBindingCollection in_bindings;
if (db::MySqlBindingTraits<KeyType>::column_type == MYSQL_TYPE_STRING) {
......
......@@ -704,6 +704,12 @@ namespace {
"DELETE n FROM " #table_prefix "_shared_network AS n " \
#__VA_ARGS__
#define MYSQL_DELETE_SHARED_NETWORK_UNASSIGNED(table_prefix, ...) \
"DELETE n FROM " #table_prefix "_shared_network AS n " \
"LEFT JOIN " #table_prefix "_shared_network_server AS a" \
" ON n.id = a.shared_network_id " \
"WHERE a.shared_network_id IS NULL " #__VA_ARGS__
#endif
#ifndef MYSQL_DELETE_SHARED_NETWORK_SERVER
......
......@@ -1528,6 +1528,21 @@ TEST_F(MySqlConfigBackendDHCPv4Test, getSharedNetwork4) {
}
}
// Test that getSharedNetwork4 throws appropriate exceptions for various
// server selectors.
TEST_F(MySqlConfigBackendDHCPv4Test, getSharedNetwork4Selectors) {
// Supported selectors.
EXPECT_NO_THROW(cbptr_->getSharedNetwork4(ServerSelector::ANY(), "level1"));
EXPECT_NO_THROW(cbptr_->getSharedNetwork4(ServerSelector::UNASSIGNED(), "level1"));
EXPECT_NO_THROW(cbptr_->getSharedNetwork4(ServerSelector::ALL(), "level1"));
EXPECT_NO_THROW(cbptr_->getSharedNetwork4(ServerSelector::ONE("server1"), "level1"));
// Not supported selectors.
EXPECT_THROW(cbptr_->getSharedNetwork4(ServerSelector::MULTIPLE({ "server1", "server2" }),
"level1"),
isc::InvalidOperation);
}
// Test that shared network may be created and updated and the server tags
// are properly assigned to it.
TEST_F(MySqlConfigBackendDHCPv4Test, createUpdateSharedNetwork4) {
......@@ -1583,6 +1598,33 @@ TEST_F(MySqlConfigBackendDHCPv4Test, createUpdateSharedNetwork4) {
EXPECT_FALSE(network->hasServerTag(ServerTag()));
}
// Test that craeteUpdateSharedNetwork4 throws appropriate exceptions for various
// server selectors.
TEST_F(MySqlConfigBackendDHCPv4Test, createUpdateSharedNetwork4Selectors) {
ASSERT_NO_THROW(cbptr_->createUpdateServer4(test_servers_[0]));
ASSERT_NO_THROW(cbptr_->createUpdateServer4(test_servers_[2]));
// Supported selectors.
SharedNetwork4Ptr shared_network(new SharedNetwork4("all"));
EXPECT_NO_THROW(cbptr_->createUpdateSharedNetwork4(ServerSelector::ALL(),
shared_network));
shared_network.reset(new SharedNetwork4("one"));
EXPECT_NO_THROW(cbptr_->createUpdateSharedNetwork4(ServerSelector::ONE("server1"),
shared_network));
shared_network.reset(new SharedNetwork4("multiple"));
EXPECT_NO_THROW(cbptr_->createUpdateSharedNetwork4(ServerSelector::MULTIPLE({ "server1", "server2" }),
shared_network));
// Not supported server selectors.
EXPECT_THROW(cbptr_->createUpdateSharedNetwork4(ServerSelector::ANY(), shared_network),
isc::InvalidOperation);
// Not implemented server selectors.
EXPECT_THROW(cbptr_->createUpdateSharedNetwork4(ServerSelector::UNASSIGNED(),
shared_network),
isc::NotImplemented);
}
// Test that the information about unspecified optional parameters gets
// propagated to the database.
TEST_F(MySqlConfigBackendDHCPv4Test, getSharedNetwork4WithOptionalUnspecified) {
......@@ -1763,6 +1805,20 @@ TEST_F(MySqlConfigBackendDHCPv4Test, getAllSharedNetworks4) {
EXPECT_TRUE(subnet->getSharedNetworkName().empty());
}
// Test that getAllSharedNetworks4 throws appropriate exceptions for various
// server selectors.
TEST_F(MySqlConfigBackendDHCPv4Test, getAllSharedNetworks4Selectors) {
// Supported selectors.
EXPECT_NO_THROW(cbptr_->getAllSharedNetworks4(ServerSelector::UNASSIGNED()));
EXPECT_NO_THROW(cbptr_->getAllSharedNetworks4(ServerSelector::ALL()));
EXPECT_NO_THROW(cbptr_->getAllSharedNetworks4(ServerSelector::ONE("server1")));
EXPECT_NO_THROW(cbptr_->getAllSharedNetworks4(ServerSelector::MULTIPLE({ "server1", "server2" })));
// Not supported selectors.
EXPECT_THROW(cbptr_->getAllSharedNetworks4(ServerSelector::ANY()),
isc::InvalidOperation);
}
// Test that shared networks with different server associations are returned.
TEST_F(MySqlConfigBackendDHCPv4Test, getAllSharedNetworks4WithServerTags) {
auto shared_network1 = test_networks_[0];
......@@ -1872,6 +1928,25 @@ TEST_F(MySqlConfigBackendDHCPv4Test, getModifiedSharedNetworks4) {
ASSERT_TRUE(networks.empty());
}
// Test that getModifiedSharedNetworks4 throws appropriate exceptions for various
// server selectors.
TEST_F(MySqlConfigBackendDHCPv4Test, getModifiedSharedNetworks4Selectors) {
// Supported selectors.
EXPECT_NO_THROW(cbptr_->getModifiedSharedNetworks4(ServerSelector::UNASSIGNED(),
timestamps_["yesterday"]));
EXPECT_NO_THROW(cbptr_->getModifiedSharedNetworks4(ServerSelector::ALL(),
timestamps_["yesterday"]));
EXPECT_NO_THROW(cbptr_->getModifiedSharedNetworks4(ServerSelector::ONE("server1"),
timestamps_["yesterday"]));
EXPECT_NO_THROW(cbptr_->getModifiedSharedNetworks4(ServerSelector::MULTIPLE({ "server1", "server2" }),
timestamps_["yesterday"]));
// Not supported selectors.
EXPECT_THROW(cbptr_->getModifiedSharedNetworks4(ServerSelector::ANY(),
timestamps_["yesterday"]),
isc::InvalidOperation);
}
// Test that selected shared network can be deleted.
TEST_F(MySqlConfigBackendDHCPv4Test, deleteSharedNetwork4) {
// Create two servers in the database.
......@@ -1961,19 +2036,56 @@ TEST_F(MySqlConfigBackendDHCPv4Test, deleteSharedNetwork4) {
test_delete("one server", ServerSelector::ONE("server1"), shared_network3);
}
// Test that deleteSharedNetwork4 throws appropriate exceptions for various
// server selectors.
TEST_F(MySqlConfigBackendDHCPv4Test, deleteSharedNetwork4Selectors) {
// Supported selectors.
EXPECT_NO_THROW(cbptr_->deleteSharedNetwork4(ServerSelector::ANY(), "level1"));
EXPECT_NO_THROW(cbptr_->deleteSharedNetwork4(ServerSelector::ALL(), "level1"));
EXPECT_NO_THROW(cbptr_->deleteSharedNetwork4(ServerSelector::ONE("server1"), "level1"));
// Not supported selectors.
EXPECT_THROW(cbptr_->deleteSharedNetwork4(ServerSelector::MULTIPLE({ "server1", "server2" }),
"level1"),
isc::InvalidOperation);
// Not implemented selectors.
EXPECT_THROW(cbptr_->deleteSharedNetwork4(ServerSelector::UNASSIGNED(), "level1"),
isc::NotImplemented);
}
// Test that deleteAllSharedNetworks4 throws appropriate exceptions for various
// server selectors.
TEST_F(MySqlConfigBackendDHCPv4Test, deleteAllSharedNetworks4Selectors) {
// Supported selectors.
EXPECT_NO_THROW(cbptr_->deleteAllSharedNetworks4(ServerSelector::UNASSIGNED()));
EXPECT_NO_THROW(cbptr_->deleteAllSharedNetworks4(ServerSelector::ALL()));
EXPECT_NO_THROW(cbptr_->deleteAllSharedNetworks4(ServerSelector::ONE("server1")));
// Not supported selectors.
EXPECT_THROW(cbptr_->deleteAllSharedNetworks4(ServerSelector::ANY()),
isc::InvalidOperation);
EXPECT_THROW(cbptr_->deleteAllSharedNetworks4(ServerSelector::MULTIPLE({ "server1", "server2" })),
isc::InvalidOperation);
}
// Test that it is possible to retrieve and delete orphaned shared network.
TEST_F(MySqlConfigBackendDHCPv4Test, unassignedSharedNetwork) {
// Create the server.
EXPECT_NO_THROW(cbptr_->createUpdateServer4(test_servers_[0]));
// Create the shared network and associate it with the server1.
// Create the shared networks and associate them with the server1.
auto shared_network = test_networks_[0];
auto shared_network2 = test_networks_[2];
EXPECT_NO_THROW(
cbptr_->createUpdateSharedNetwork4(ServerSelector::ONE("server1"), shared_network)
);
EXPECT_NO_THROW(
cbptr_->createUpdateSharedNetwork4(ServerSelector::ONE("server1"), shared_network2)
);
// Delete the server. The shared network should be preserved but is
// considered orhpaned, i.e. does not belong to any server.
// Delete the server. The shared networks should be preserved but are
// considered orhpaned, i.e. do not belong to any server.
uint64_t deleted_count = 0;
EXPECT_NO_THROW(deleted_count = cbptr_->deleteServer4(ServerTag("server1")));
EXPECT_EQ(1, deleted_count);
......@@ -2004,16 +2116,16 @@ TEST_F(MySqlConfigBackendDHCPv4Test, unassignedSharedNetwork) {
// Also if we ask for all unassigned networks it should be returned.
EXPECT_NO_THROW(returned_networks = cbptr_->getAllSharedNetworks4(ServerSelector::UNASSIGNED()));
ASSERT_EQ(1, returned_networks.size());
ASSERT_EQ(2, returned_networks.size());
// And all modified.
EXPECT_NO_THROW(
returned_networks = cbptr_->getModifiedSharedNetworks4(ServerSelector::UNASSIGNED(),
timestamps_["two days ago"])
);
ASSERT_EQ(1, returned_networks.size());
ASSERT_EQ(2, returned_networks.size());
// If we ask for any network with this name, it should be returned too.
// If we ask for any network by name, it should be returned too.
EXPECT_NO_THROW(returned_network = cbptr_->getSharedNetwork4(ServerSelector::ANY(),
"level1"));
ASSERT_TRUE(returned_network);
......@@ -2037,6 +2149,12 @@ TEST_F(MySqlConfigBackendDHCPv4Test, unassignedSharedNetwork) {
deleted_count = cbptr_->deleteSharedNetwork4(ServerSelector::ANY(), "level1")
);
EXPECT_EQ(1, deleted_count);
// We can delete all second networks using UNASSIGNED selector.
EXPECT_NO_THROW(
deleted_count = cbptr_->deleteAllSharedNetworks4(ServerSelector::UNASSIGNED());
);
EXPECT_EQ(1, deleted_count);
}
// Test that lifetimes in shared networks are handled as expected.
......
......@@ -1543,6 +1543,21 @@ TEST_F(MySqlConfigBackendDHCPv6Test, getSharedNetwork6) {
}
}
// Test that getSharedNetwork6 throws appropriate exceptions for various
// server selectors.
TEST_F(MySqlConfigBackendDHCPv6Test, getSharedNetwork6Selectors) {
// Supported selectors.
EXPECT_NO_THROW(cbptr_->getSharedNetwork6(ServerSelector::ANY(), "level1"));
EXPECT_NO_THROW(cbptr_->getSharedNetwork6(ServerSelector::UNASSIGNED(), "level1"));
EXPECT_NO_THROW(cbptr_->getSharedNetwork6(ServerSelector::ALL(), "level1"));
EXPECT_NO_THROW(cbptr_->getSharedNetwork6(ServerSelector::ONE("server1"), "level1"));
// Not supported selectors.
EXPECT_THROW(cbptr_->getSharedNetwork6(ServerSelector::MULTIPLE({ "server1", "server2" }),
"level1"),
isc::InvalidOperation);
}
// Test that shared network may be created and updated and the server tags
// are properly assigned to it.
TEST_F(MySqlConfigBackendDHCPv6Test, createUpdateSharedNetwork6) {
......@@ -1598,6 +1613,33 @@ TEST_F(MySqlConfigBackendDHCPv6Test, createUpdateSharedNetwork6) {
EXPECT_FALSE(network->hasServerTag(ServerTag()));
}
// Test that craeteUpdateSharedNetwork6 throws appropriate exceptions for various
// server selectors.
TEST_F(MySqlConfigBackendDHCPv6Test, createUpdateSharedNetwork6Selectors) {
ASSERT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[0]));
ASSERT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[2]));
// Supported selectors.
SharedNetwork6Ptr shared_network(new SharedNetwork6("all"));
EXPECT_NO_THROW(cbptr_->createUpdateSharedNetwork6(ServerSelector::ALL(),
shared_network));
shared_network.reset(new SharedNetwork6("one"));
EXPECT_NO_THROW(cbptr_->createUpdateSharedNetwork6(ServerSelector::ONE("server1"),
shared_network));
shared_network.reset(new SharedNetwork6("multiple"));
EXPECT_NO_THROW(cbptr_->createUpdateSharedNetwork6(ServerSelector::MULTIPLE({ "server1", "server2" }),
shared_network));
// Not supported server selectors.
EXPECT_THROW(cbptr_->createUpdateSharedNetwork6(ServerSelector::ANY(), shared_network),
isc::InvalidOperation);
// Not implemented server selectors.
EXPECT_THROW(cbptr_->createUpdateSharedNetwork6(ServerSelector::UNASSIGNED(),
shared_network),
isc::NotImplemented);
}
// Test that the information about unspecified optional parameters gets
// propagated to the database.
TEST_F(MySqlConfigBackendDHCPv6Test, getSharedNetwork6WithOptionalUnspecified) {
......@@ -1779,6 +1821,20 @@ TEST_F(MySqlConfigBackendDHCPv6Test, getAllSharedNetworks6) {
EXPECT_TRUE(subnet->getSharedNetworkName().empty());
}
// Test that getAllSharedNetworks6 throws appropriate exceptions for various
// server selectors.
TEST_F(MySqlConfigBackendDHCPv6Test, getAllSharedNetworks6Selectors) {
// Supported selectors.
EXPECT_NO_THROW(cbptr_->getAllSharedNetworks6(ServerSelector::UNASSIGNED()));
EXPECT_NO_THROW(cbptr_->getAllSharedNetworks6(ServerSelector::ALL()));
EXPECT_NO_THROW(cbptr_->getAllSharedNetworks6(ServerSelector::ONE("server1")));
EXPECT_NO_THROW(cbptr_->getAllSharedNetworks6(ServerSelector::MULTIPLE({ "server1", "server2" })));
// Not supported selectors.
EXPECT_THROW(cbptr_->getAllSharedNetworks6(ServerSelector::ANY()),
isc::InvalidOperation);
}
// Test that shared networks with different server associations are returned.
TEST_F(MySqlConfigBackendDHCPv6Test, getAllSharedNetworks6WithServerTags) {
auto shared_network1 = test_networks_[0];
......@@ -1888,6 +1944,25 @@ TEST_F(MySqlConfigBackendDHCPv6Test, getModifiedSharedNetworks6) {
ASSERT_TRUE(networks.empty());
}
// Test that getModifiedSharedNetworks6 throws appropriate exceptions for various
// server selectors.
TEST_F(MySqlConfigBackendDHCPv6Test, getModifiedSharedNetworks6Selectors) {
// Supported selectors.
EXPECT_NO_THROW(cbptr_->getModifiedSharedNetworks6(ServerSelector::UNASSIGNED(),
timestamps_["yesterday"]));
EXPECT_NO_THROW(cbptr_->getModifiedSharedNetworks6(ServerSelector::ALL(),
timestamps_["yesterday"]));
EXPECT_NO_THROW(cbptr_->getModifiedSharedNetworks6(ServerSelector::ONE("server1"),
timestamps_["yesterday"]));
EXPECT_NO_THROW(cbptr_->getModifiedSharedNetworks6(ServerSelector::MULTIPLE({ "server1", "server2" }),
timestamps_["yesterday"]));
// Not supported selectors.
EXPECT_THROW(cbptr_->getModifiedSharedNetworks6(ServerSelector::ANY(),
timestamps_["yesterday"]),
isc::InvalidOperation);
}
// Test that selected shared network can be deleted.
TEST_F(MySqlConfigBackendDHCPv6Test, deleteSharedNetwork6) {
// Create two servers in the database.
......@@ -1977,19 +2052,56 @@ TEST_F(MySqlConfigBackendDHCPv6Test, deleteSharedNetwork6) {
test_delete("one server", ServerSelector::ONE("server1"), shared_network3);
}
// Test that deleteSharedNetwork6 throws appropriate exceptions for various
// server selectors.
TEST_F(MySqlConfigBackendDHCPv6Test, deleteSharedNetwork6Selectors) {
// Supported selectors.
EXPECT_NO_THROW(cbptr_->deleteSharedNetwork6(ServerSelector::ANY(), "level1"));
EXPECT_NO_THROW(cbptr_->deleteSharedNetwork6(ServerSelector::ALL(), "level1"));
EXPECT_NO_THROW(cbptr_->deleteSharedNetwork6(ServerSelector::ONE("server1"), "level1"));
// Not supported selectors.
EXPECT_THROW(cbptr_->deleteSharedNetwork6(ServerSelector::MULTIPLE({ "server1", "server2" }),
"level1"),
isc::InvalidOperation);
// Not implemented selectors.
EXPECT_THROW(cbptr_->deleteSharedNetwork6(ServerSelector::UNASSIGNED(), "level1"),
isc::NotImplemented);
}
// Test that deleteAllSharedNetworks6 throws appropriate exceptions for various
// server selectors.
TEST_F(MySqlConfigBackendDHCPv6Test, deleteAllSharedNetworks6Selectors) {
// Supported selectors.
EXPECT_NO_THROW(cbptr_->deleteAllSharedNetworks6(ServerSelector::UNASSIGNED()));
EXPECT_NO_THROW(cbptr_->deleteAllSharedNetworks6(ServerSelector::ALL()));
EXPECT_NO_THROW(cbptr_->deleteAllSharedNetworks6(ServerSelector::ONE("server1")));
// Not supported selectors.
EXPECT_THROW(cbptr_->deleteAllSharedNetworks6(ServerSelector::ANY()),
isc::InvalidOperation);
EXPECT_THROW(cbptr_->deleteAllSharedNetworks6(ServerSelector::MULTIPLE({ "server1", "server2" })),
isc::InvalidOperation);
}
// Test that it is possible to retrieve and delete orphaned shared network.
TEST_F(MySqlConfigBackendDHCPv6Test, unassignedSharedNetwork) {
// Create the server.
EXPECT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[0]));
// Create the shared network and associate it with the server1.
// Create the shared networks and associate them with the server1.
auto shared_network = test_networks_[0];
auto shared_network2 = test_networks_[2];
EXPECT_NO_THROW(
cbptr_->createUpdateSharedNetwork6(ServerSelector::ONE("server1"), shared_network)
);
EXPECT_NO_THROW(
cbptr_->createUpdateSharedNetwork6(ServerSelector::ONE("server1"), shared_network2)
);
// Delete the server. The shared network should be preserved but is
// considered orhpaned, i.e. does not belong to any server.
// Delete the server. The shared networks should be preserved but are
// considered orhpaned, i.e. do not belong to any server.
uint64_t deleted_count = 0;
EXPECT_NO_THROW(deleted_count = cbptr_->deleteServer6(ServerTag("server1")));
EXPECT_EQ(1, deleted_count);
......@@ -2020,16 +2132,16 @@ TEST_F(MySqlConfigBackendDHCPv6Test, unassignedSharedNetwork) {
// Also if we ask for all unassigned networks it should be returned.
EXPECT_NO_THROW(returned_networks = cbptr_->getAllSharedNetworks6(ServerSelector::UNASSIGNED()));
ASSERT_EQ(1, returned_networks.size());
ASSERT_EQ(2, returned_networks.size());
// And all modified.
EXPECT_NO_THROW(
returned_networks = cbptr_->getModifiedSharedNetworks6(ServerSelector::UNASSIGNED(),
timestamps_["two days ago"])
);
ASSERT_EQ(1, returned_networks.size());
ASSERT_EQ(2, returned_networks.size());
// If we ask for any network with this name, it should be returned too.
// If we ask for any network by name, it should be returned too.
EXPECT_NO_THROW(returned_network = cbptr_->getSharedNetwork6(ServerSelector::ANY(),
"level1"));
ASSERT_TRUE(returned_network);
......@@ -2053,6 +2165,12 @@ TEST_F(MySqlConfigBackendDHCPv6Test, unassignedSharedNetwork) {
deleted_count = cbptr_->deleteSharedNetwork6(ServerSelector::ANY(), "level1")
);
EXPECT_EQ(1, deleted_count);
// We can delete all second networks using UNASSIGNED selector.
EXPECT_NO_THROW(
deleted_count = cbptr_->deleteAllSharedNetworks6(ServerSelector::UNASSIGNED());
);
EXPECT_EQ(1, deleted_count);
}
// Test that lifetimes in shared networks are handled as expected.
......
......@@ -29,6 +29,59 @@ namespace dhcp {
///
/// All POSIX times specified in the methods belonging to this
/// class must be local times.
///
/// Below, we describe the general rules of using the server selectors
/// when creating, updating, fetching and deleting the configuration
/// elements from the backends. The detailed information can be found
/// in the descriptions of the individual methods. The backend
/// implementations must not be in conflict with the rules described
/// here but may sometimes lack some functionality and not support
/// some of the server selectors for some API calls. In such cases
/// the backend's documentation should be clear about these cases
/// and document the exceptions thrown when unsupported selector is
/// used for a given method.
///
/// The @c ServerSelector class defines 5 types of selectors:
/// - ANY: server tag/id is not a part of the database query, i.e. the
/// object in the database is identified by some unique property,
/// e.g. subnet identifier, shared network name etc.
///
/// - UNASSIGNED: query pertains to the objects in the database which
/// are associated with no particular server (including the logical
/// server "all"). Objects associated with any server are never
/// selected.
///
/// - ALL: query pertains only to the objects in the database which are
/// associated with the logical server "all". Those objects are shared
/// between all servers using the database. This server selector never
/// returns objects explicitly associated with the particular servers
/// defined by the user.
///
/// - ONE: query pertains to the objects used by one particular server.
/// The server uses both the objects explicitly associated with it and
/// and the objects associated with the logical server "all". Therefore
/// the result returned for this server selector combines configuration
/// elements associated with this server and with "all" servers. In case
/// if there are two instances of the configuration information, one
/// associated with "all" servers and one associated with the server,
/// the information associated with the server takes precedence.
/// When using this selector to delete objects from the database, the
/// deletion pertains only to the objects associated with the given
/// server tag. It doesn't delete the objects associated with "all"
/// servers.
///
/// - MULTIPLE: query pertains to the objects used by multiple servers
/// listed in the selector. It allows for querying for a list of
/// objects associated with multiple servers and/or logical server
/// "all".
///
/// There are limitations imposed on the API calls what server selectors
/// are allowed for them. Configuration Backend implementations must not
/// be in conflict with those limitations. In particular, the implementation
/// must not permit for server selectors which are not allowed here.
/// However, the backend implementation may be more restrictive and not
/// allow some of the server selectors for some API calls. This should,
/// however, be properly documented.
class ConfigBackendDHCPv4 : public cb::BaseConfigBackend {
public:
......@@ -80,6 +133,9 @@ public:
/// @brief Retrieves shared network by name.
///
/// Allowed server selectors: ANY, UNASSIGNED, ALL, ONE.
/// Not allowed server selector: MULTIPLE.
///
/// @param server_selector Server selector.