From: Marcin Siodelski Date: Tue, 9 Jul 2019 14:40:33 +0000 (+0200) Subject: [#716,!412] Documented and tested server selection for shared networks. X-Git-Tag: Kea-1.6.0-beta2~83 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=dc80c4657650eb229bbb9f4825f1648819f8051a;p=thirdparty%2Fkea.git [#716,!412] Documented and tested server selection for shared networks. Also fixed the code where it accepted unsupported selectors. Implemented deleting the unassigned subnets. --- diff --git a/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.cc b/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.cc index 21320a45f3..18fa0c924c 100644 --- a/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.cc +++ b/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.cc @@ -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); diff --git a/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.h b/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.h index e0f9e05baf..6cc79b3dc1 100644 --- a/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.h +++ b/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.h @@ -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: diff --git a/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp6.cc b/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp6.cc index 9dfb2f47e5..c686572ed5 100644 --- a/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp6.cc +++ b/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp6.cc @@ -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) diff --git a/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp6.h b/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp6.h index ac126d735d..d0f612ae57 100644 --- a/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp6.h +++ b/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp6.h @@ -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: diff --git a/src/hooks/dhcp/mysql_cb/mysql_cb_impl.cc b/src/hooks/dhcp/mysql_cb/mysql_cb_impl.cc index ea7f66e1f9..1453223220 100644 --- a/src/hooks/dhcp/mysql_cb/mysql_cb_impl.cc +++ b/src/hooks/dhcp/mysql_cb/mysql_cb_impl.cc @@ -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)); } diff --git a/src/hooks/dhcp/mysql_cb/mysql_cb_impl.h b/src/hooks/dhcp/mysql_cb/mysql_cb_impl.h index 7e54c1c063..31edee4ee2 100644 --- a/src/hooks/dhcp/mysql_cb/mysql_cb_impl.h +++ b/src/hooks/dhcp/mysql_cb/mysql_cb_impl.h @@ -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::column_type == MYSQL_TYPE_STRING) { diff --git a/src/hooks/dhcp/mysql_cb/mysql_query_macros_dhcp.h b/src/hooks/dhcp/mysql_cb/mysql_query_macros_dhcp.h index 8e1b0eeecb..d37860eedc 100644 --- a/src/hooks/dhcp/mysql_cb/mysql_query_macros_dhcp.h +++ b/src/hooks/dhcp/mysql_cb/mysql_query_macros_dhcp.h @@ -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 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 020d8f59c9..f1ab1bf323 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 @@ -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. diff --git a/src/hooks/dhcp/mysql_cb/tests/mysql_cb_dhcp6_unittest.cc b/src/hooks/dhcp/mysql_cb/tests/mysql_cb_dhcp6_unittest.cc index 19fbe316b3..c7b31656ef 100644 --- a/src/hooks/dhcp/mysql_cb/tests/mysql_cb_dhcp6_unittest.cc +++ b/src/hooks/dhcp/mysql_cb/tests/mysql_cb_dhcp6_unittest.cc @@ -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. diff --git a/src/lib/dhcpsrv/config_backend_dhcp4.h b/src/lib/dhcpsrv/config_backend_dhcp4.h index c155398868..45527a584f 100644 --- a/src/lib/dhcpsrv/config_backend_dhcp4.h +++ b/src/lib/dhcpsrv/config_backend_dhcp4.h @@ -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. /// @param name Name of the shared network to be retrieved. /// @return Pointer to the shared network or NULL if not found. @@ -89,6 +145,9 @@ public: /// @brief Retrieves all shared networks. /// + /// Allowed server selectors: UNASSIGNED, ALL, ONE, MULTIPLE. + /// Not allowed server selector: ANY. + /// /// @param server_selector Server selector. /// @return Collection of shared network or empty collection if /// no shared network found. @@ -97,6 +156,9 @@ public: /// @brief Retrieves shared networks modified after specified time. /// + /// Allowed server selectors: UNASSIGNED, ALL, ONE, MULTIPLE. + /// Not allowed server selector: ANY. + /// /// @param server_selector Server selector. /// @param modification_time Lower bound shared network modification time. /// @return Collection of shared network or empty collection if @@ -256,6 +318,9 @@ public: /// @brief Creates or updates a shared network. /// + /// Allowed server selectors: UNASSIGNED, ALL, ONE, MULTIPLE. + /// Not allowed server selector: ANY. + /// /// @param server_selector Server selector. /// @param shared_network Shared network to be added or updated. virtual void @@ -363,15 +428,21 @@ public: /// @brief Deletes shared network by name. /// + /// Allowed server selectors: ANY, UNASSIGNED, ALL, ONE. + /// Not allowed server selectors: MULTIPLE. + /// /// @param server_selector Server selector. /// @param name Name of the shared network to be deleted. - /// @return Number of deleted shared networks.. + /// @return Number of deleted shared networks. virtual uint64_t deleteSharedNetwork4(const db::ServerSelector& server_selector, const std::string& name) = 0; /// @brief Deletes all shared networks. /// + /// Allowed server selectors: UNASSIGNED, ALL, ONE. + /// Not allowed server selectors: ANY, MULTIPLE. + /// /// @param server_selector Server selector. /// @return Number of deleted shared networks. virtual uint64_t diff --git a/src/lib/dhcpsrv/config_backend_dhcp6.h b/src/lib/dhcpsrv/config_backend_dhcp6.h index 3a0e3c411a..fd25b6a867 100644 --- a/src/lib/dhcpsrv/config_backend_dhcp6.h +++ b/src/lib/dhcpsrv/config_backend_dhcp6.h @@ -30,6 +30,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 ConfigBackendDHCPv6 : public cb::BaseConfigBackend { public: @@ -72,6 +125,9 @@ public: /// @brief Retrieves subnets modified after specified time. /// + /// Allowed server selectors: UNASSIGNED, ALL, ONE, MULTIPLE. + /// Not allowed server selector: ANY. + /// /// @param server_selector Server selector. /// @param modification_time Lower bound subnet modification time. /// @return Collection of subnets or empty collection if no subnet found. @@ -81,6 +137,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. /// @param name Name of the shared network to be retrieved. /// @return Pointer to the shared network or NULL if not found. @@ -90,6 +149,9 @@ public: /// @brief Retrieves all shared networks. /// + /// Allowed server selectors: UNASSIGNED, ALL, ONE, MULTIPLE. + /// Not allowed server selector: ANY. + /// /// @param server_selector Server selector. /// @return Collection of shared network or empty collection if /// no shared network found. @@ -257,6 +319,9 @@ public: /// @brief Creates or updates a shared network. /// + /// Allowed server selectors: UNASSIGNED, ALL, ONE, MULTIPLE. + /// Not allowed server selector: ANY. + /// /// @param server_selector Server selector. /// @param shared_network Shared network to be added or updated. virtual void @@ -378,6 +443,9 @@ public: /// @brief Deletes shared network by name. /// + /// Allowed server selectors: ANY, UNASSIGNED, ALL, ONE. + /// Not allowed server selectors: MULTIPLE. + /// /// @param server_selector Server selector. /// @param name Name of the shared network to be deleted. /// @return Number of deleted shared networks.. @@ -387,6 +455,9 @@ public: /// @brief Deletes all shared networks. /// + /// Allowed server selectors: UNASSIGNED, ALL, ONE. + /// Not allowed server selectors: ANY, MULTIPLE. + /// /// @param server_selector Server selector. /// @return Number of deleted shared networks. virtual uint64_t