]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#716,!412] Added support for unassigned networks addition/deletion.
authorMarcin Siodelski <marcin@isc.org>
Mon, 8 Jul 2019 16:23:14 +0000 (18:23 +0200)
committerMarcin Siodelski <marcin@isc.org>
Tue, 9 Jul 2019 18:37:29 +0000 (14:37 -0400)
src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.cc
src/hooks/dhcp/mysql_cb/mysql_cb_dhcp6.cc
src/hooks/dhcp/mysql_cb/mysql_cb_impl.h
src/hooks/dhcp/mysql_cb/mysql_query_macros_dhcp.h
src/hooks/dhcp/mysql_cb/tests/mysql_cb_dhcp4_unittest.cc
src/hooks/dhcp/mysql_cb/tests/mysql_cb_dhcp6_unittest.cc

index 1d2d932e7baa963dd7f90368b4762312d05fda7b..48f015fd1e44216d875a0592e34a7ead2ef2d381 100644 (file)
@@ -67,8 +67,12 @@ public:
         GET_SHARED_NETWORK_SUBNETS4,
         GET_POOL4_RANGE,
         GET_SHARED_NETWORK4_NAME_NO_TAG,
+        GET_SHARED_NETWORK4_NAME_ANY,
+        GET_SHARED_NETWORK4_NAME_UNASSIGNED,
         GET_ALL_SHARED_NETWORKS4,
+        GET_ALL_SHARED_NETWORKS4_UNASSIGNED,
         GET_MODIFIED_SHARED_NETWORKS4,
+        GET_MODIFIED_SHARED_NETWORKS4_UNASSIGNED,
         GET_OPTION_DEF4_CODE_SPACE,
         GET_ALL_OPTION_DEFS4,
         GET_MODIFIED_OPTION_DEFS4,
@@ -111,7 +115,7 @@ public:
         DELETE_ALL_SUBNETS4_SHARED_NETWORK_NAME,
         DELETE_POOLS4_SUBNET_ID,
         DELETE_SHARED_NETWORK4_NAME_WITH_TAG,
-        DELETE_SHARED_NETWORK4_NAME_NO_TAG,
+        DELETE_SHARED_NETWORK4_NAME_ANY,
         DELETE_ALL_SHARED_NETWORKS4,
         DELETE_SHARED_NETWORK4_SERVER,
         DELETE_OPTION_DEF4_CODE_NAME,
@@ -1238,22 +1242,25 @@ public:
     SharedNetwork4Ptr getSharedNetwork4(const ServerSelector& server_selector,
                                         const std::string& name) {
 
-        if (server_selector.amUnassigned()) {
-            isc_throw(NotImplemented, "managing configuration for no particular server"
-                      " (unassigned) is unsupported at the moment");
-
-        } else if (server_selector.hasMultipleTags()) {
+        if (server_selector.hasMultipleTags()) {
             isc_throw(InvalidOperation, "expected one server tag to be specified"
                       " while fetching a shared network. Got: "
                       << getServerTagsAsText(server_selector));
         }
 
         MySqlBindingCollection in_bindings = { MySqlBinding::createString(name) };
+
         auto index = GET_SHARED_NETWORK4_NAME_NO_TAG;
 
+        if (server_selector.amUnassigned()) {
+            index = GET_SHARED_NETWORK4_NAME_UNASSIGNED;
+
+        } else if (server_selector.amAny()) {
+            index = GET_SHARED_NETWORK4_NAME_ANY;
+        }
+
         SharedNetwork4Collection shared_networks;
-        getSharedNetworks4(GET_SHARED_NETWORK4_NAME_NO_TAG, server_selector, in_bindings,
-                           shared_networks);
+        getSharedNetworks4(index, server_selector, in_bindings, shared_networks);
 
         return (shared_networks.empty() ? SharedNetwork4Ptr() : *shared_networks.begin());
     }
@@ -1265,9 +1272,10 @@ public:
     /// structure where shared networks should be inserted.
     void getAllSharedNetworks4(const ServerSelector& server_selector,
                                SharedNetwork4Collection& shared_networks) {
+        auto index = (server_selector.amUnassigned() ? GET_ALL_SHARED_NETWORKS4_UNASSIGNED :
+                      GET_ALL_SHARED_NETWORKS4);
         MySqlBindingCollection in_bindings;
-        getSharedNetworks4(GET_ALL_SHARED_NETWORKS4, server_selector, in_bindings,
-                           shared_networks);
+        getSharedNetworks4(index, server_selector, in_bindings, shared_networks);
     }
 
     /// @brief Sends query to retrieve modified shared networks.
@@ -1283,8 +1291,9 @@ public:
             MySqlBinding::createTimestamp(modification_ts)
         };
 
-        getSharedNetworks4(GET_MODIFIED_SHARED_NETWORKS4, server_selector, in_bindings,
-                           shared_networks);
+        auto index = (server_selector.amUnassigned() ? GET_MODIFIED_SHARED_NETWORKS4_UNASSIGNED :
+                      GET_MODIFIED_SHARED_NETWORKS4);
+        getSharedNetworks4(index, server_selector, in_bindings, shared_networks);
     }
 
     /// @brief Sends query to insert or update shared network.
@@ -2024,21 +2033,41 @@ TaggedStatementArray tagged_statements = { {
       "ORDER BY p.id, x.option_id"
     },
 
-    // Select shared network by name without filtering by server tag.
+    // Select shared network by name.
     { MySqlConfigBackendDHCPv4Impl::GET_SHARED_NETWORK4_NAME_NO_TAG,
       MYSQL_GET_SHARED_NETWORK4_NO_TAG(WHERE n.name = ?)
     },
 
+    // Select shared network by name without specifying server tags.
+    { MySqlConfigBackendDHCPv4Impl::GET_SHARED_NETWORK4_NAME_ANY,
+      MYSQL_GET_SHARED_NETWORK4_ANY(WHERE n.name = ?)
+    },
+
+    // Select unassigned shared network by name.
+    { MySqlConfigBackendDHCPv4Impl::GET_SHARED_NETWORK4_NAME_UNASSIGNED,
+      MYSQL_GET_SHARED_NETWORK4_UNASSIGNED(AND n.name = ?)
+    },
+
     // Select all shared networks.
     { MySqlConfigBackendDHCPv4Impl::GET_ALL_SHARED_NETWORKS4,
       MYSQL_GET_SHARED_NETWORK4_NO_TAG()
     },
 
+    // Select all unassigned shared networks.
+    { MySqlConfigBackendDHCPv4Impl::GET_ALL_SHARED_NETWORKS4_UNASSIGNED,
+      MYSQL_GET_SHARED_NETWORK4_UNASSIGNED()
+    },
+
     // Select modified shared networks.
     { MySqlConfigBackendDHCPv4Impl::GET_MODIFIED_SHARED_NETWORKS4,
       MYSQL_GET_SHARED_NETWORK4_NO_TAG(WHERE n.modification_ts > ?)
     },
 
+    // Select modified and unassigned shared networks.
+    { MySqlConfigBackendDHCPv4Impl::GET_MODIFIED_SHARED_NETWORKS4_UNASSIGNED,
+      MYSQL_GET_SHARED_NETWORK4_UNASSIGNED(AND n.modification_ts > ?)
+    },
+
     // Retrieves option definition by code and space.
     { MySqlConfigBackendDHCPv4Impl::GET_OPTION_DEF4_CODE_SPACE,
       MYSQL_GET_OPTION_DEF(dhcp4, AND d.code = ? AND d.space = ?)
@@ -2346,8 +2375,8 @@ TaggedStatementArray tagged_statements = { {
     },
 
     // Delete shared network by name without specifying server tag.
-    { MySqlConfigBackendDHCPv4Impl::DELETE_SHARED_NETWORK4_NAME_NO_TAG,
-      MYSQL_DELETE_SHARED_NETWORK_NO_TAG(dhcp4, AND n.name = ?)
+    { MySqlConfigBackendDHCPv4Impl::DELETE_SHARED_NETWORK4_NAME_ANY,
+      MYSQL_DELETE_SHARED_NETWORK_ANY(dhcp4, WHERE n.name = ?)
     },
 
     // Delete all shared networks.
@@ -2800,8 +2829,9 @@ MySqlConfigBackendDHCPv4::deleteSharedNetwork4(const ServerSelector& server_sele
                                                const std::string& name) {
     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_SHARED_NETWORK4)
         .arg(name);
+
     int index = (server_selector.amAny() ?
-                 MySqlConfigBackendDHCPv4Impl::DELETE_SHARED_NETWORK4_NAME_NO_TAG :
+                 MySqlConfigBackendDHCPv4Impl::DELETE_SHARED_NETWORK4_NAME_ANY :
                  MySqlConfigBackendDHCPv4Impl::DELETE_SHARED_NETWORK4_NAME_WITH_TAG);
     uint64_t result = impl_->deleteTransactional(index, server_selector,
                                                  "deleting a shared network",
index f7412ad2526c9bf92101650ee0c706d442cf6604..d89c346589bd02201ed28bfd3d3e70e66fdf4838 100644 (file)
@@ -69,8 +69,12 @@ public:
         GET_POOL6_RANGE,
         GET_PD_POOL,
         GET_SHARED_NETWORK6_NAME_NO_TAG,
+        GET_SHARED_NETWORK6_NAME_ANY,
+        GET_SHARED_NETWORK6_NAME_UNASSIGNED,
         GET_ALL_SHARED_NETWORKS6,
+        GET_ALL_SHARED_NETWORKS6_UNASSIGNED,
         GET_MODIFIED_SHARED_NETWORKS6,
+        GET_MODIFIED_SHARED_NETWORKS6_UNASSIGNED,
         GET_OPTION_DEF6_CODE_SPACE,
         GET_ALL_OPTION_DEFS6,
         GET_MODIFIED_OPTION_DEFS6,
@@ -117,7 +121,7 @@ public:
         DELETE_POOLS6_SUBNET_ID,
         DELETE_PD_POOLS_SUBNET_ID,
         DELETE_SHARED_NETWORK6_NAME_WITH_TAG,
-        DELETE_SHARED_NETWORK6_NAME_NO_TAG,
+        DELETE_SHARED_NETWORK6_NAME_ANY,
         DELETE_ALL_SHARED_NETWORKS6,
         DELETE_SHARED_NETWORK6_SERVER,
         DELETE_OPTION_DEF6_CODE_NAME,
@@ -1440,19 +1444,23 @@ public:
     SharedNetwork6Ptr getSharedNetwork6(const ServerSelector& server_selector,
                                         const std::string& name) {
 
-        if (server_selector.amUnassigned()) {
-            isc_throw(NotImplemented, "managing configuration for no particular server"
-                      " (unassigned) is unsupported at the moment");
-
-        } else if (server_selector.hasMultipleTags()) {
+        if (server_selector.hasMultipleTags()) {
             isc_throw(InvalidOperation, "expected one server tag to be specified"
                       " while fetching a shared network. Got: "
                       << getServerTagsAsText(server_selector));
         }
 
         MySqlBindingCollection in_bindings = { MySqlBinding::createString(name) };
+
         auto index = GET_SHARED_NETWORK6_NAME_NO_TAG;
 
+        if (server_selector.amUnassigned()) {
+            index = GET_SHARED_NETWORK6_NAME_UNASSIGNED;
+
+        } else if (server_selector.amAny()) {
+            index = GET_SHARED_NETWORK6_NAME_ANY;
+        }
+
         SharedNetwork6Collection shared_networks;
         getSharedNetworks6(index, server_selector, in_bindings, shared_networks);
 
@@ -1466,9 +1474,10 @@ public:
     /// structure where shared networks should be inserted.
     void getAllSharedNetworks6(const ServerSelector& server_selector,
                                SharedNetwork6Collection& shared_networks) {
+        auto index = (server_selector.amUnassigned() ? GET_ALL_SHARED_NETWORKS6_UNASSIGNED :
+                      GET_ALL_SHARED_NETWORKS6);
         MySqlBindingCollection in_bindings;
-        getSharedNetworks6(GET_ALL_SHARED_NETWORKS6, server_selector, in_bindings,
-                           shared_networks);
+        getSharedNetworks6(index, server_selector, in_bindings, shared_networks);
     }
 
     /// @brief Sends query to retrieve modified shared networks.
@@ -1484,8 +1493,9 @@ public:
             MySqlBinding::createTimestamp(modification_ts)
         };
 
-        getSharedNetworks6(GET_MODIFIED_SHARED_NETWORKS6, server_selector, in_bindings,
-                           shared_networks);
+        auto index = (server_selector.amUnassigned() ? GET_MODIFIED_SHARED_NETWORKS6_UNASSIGNED :
+                      GET_MODIFIED_SHARED_NETWORKS6);
+        getSharedNetworks6(index, server_selector, in_bindings, shared_networks);
     }
 
     /// @brief Sends query to insert or update shared network.
@@ -2375,21 +2385,41 @@ TaggedStatementArray tagged_statements = { {
       "ORDER BY p.id, x.option_id"
     },
 
-    // Select shared network by name without filtering by server tag.
+    // Select shared network by name.
     { MySqlConfigBackendDHCPv6Impl::GET_SHARED_NETWORK6_NAME_NO_TAG,
       MYSQL_GET_SHARED_NETWORK6_NO_TAG(WHERE n.name = ?)
     },
 
+    // Select shared network by name without specifying server tags.
+    { MySqlConfigBackendDHCPv6Impl::GET_SHARED_NETWORK6_NAME_ANY,
+      MYSQL_GET_SHARED_NETWORK6_ANY(WHERE n.name = ?)
+    },
+
+    // Select unassigned shared network by name.
+    { MySqlConfigBackendDHCPv6Impl::GET_SHARED_NETWORK6_NAME_UNASSIGNED,
+      MYSQL_GET_SHARED_NETWORK6_UNASSIGNED(AND n.name = ?)
+    },
+
     // Select all shared networks.
     { MySqlConfigBackendDHCPv6Impl::GET_ALL_SHARED_NETWORKS6,
       MYSQL_GET_SHARED_NETWORK6_NO_TAG()
     },
 
+    // Select all unassigned shared networks.
+    { MySqlConfigBackendDHCPv6Impl::GET_ALL_SHARED_NETWORKS6_UNASSIGNED,
+      MYSQL_GET_SHARED_NETWORK6_UNASSIGNED()
+    },
+
     // Select modified shared networks.
     { MySqlConfigBackendDHCPv6Impl::GET_MODIFIED_SHARED_NETWORKS6,
       MYSQL_GET_SHARED_NETWORK6_NO_TAG(WHERE n.modification_ts > ?)
     },
 
+    // Select modified and unassigned shared networks.
+    { MySqlConfigBackendDHCPv6Impl::GET_MODIFIED_SHARED_NETWORKS6_UNASSIGNED,
+      MYSQL_GET_SHARED_NETWORK6_UNASSIGNED(AND n.modification_ts > ?)
+    },
+
     // Retrieves option definition by code and space.
     { MySqlConfigBackendDHCPv6Impl::GET_OPTION_DEF6_CODE_SPACE,
       MYSQL_GET_OPTION_DEF(dhcp6, AND d.code = ? AND d.space = ?)
@@ -2706,8 +2736,8 @@ TaggedStatementArray tagged_statements = { {
     },
 
     // Delete shared network by name without specifying server tag.
-    { MySqlConfigBackendDHCPv6Impl::DELETE_SHARED_NETWORK6_NAME_NO_TAG,
-      MYSQL_DELETE_SHARED_NETWORK_NO_TAG(dhcp6, AND n.name = ?)
+    { MySqlConfigBackendDHCPv6Impl::DELETE_SHARED_NETWORK6_NAME_ANY,
+      MYSQL_DELETE_SHARED_NETWORK_ANY(dhcp6, WHERE n.name = ?)
     },
 
     // Delete all shared networks.
@@ -3172,7 +3202,7 @@ MySqlConfigBackendDHCPv6::deleteSharedNetwork6(const ServerSelector& server_sele
     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_SHARED_NETWORK6)
         .arg(name);
     int index = (server_selector.amAny() ?
-                 MySqlConfigBackendDHCPv6Impl::DELETE_SHARED_NETWORK6_NAME_NO_TAG :
+                 MySqlConfigBackendDHCPv6Impl::DELETE_SHARED_NETWORK6_NAME_ANY :
                  MySqlConfigBackendDHCPv6Impl::DELETE_SHARED_NETWORK6_NAME_WITH_TAG);
     uint64_t result = impl_->deleteTransactional(index, server_selector,
                                                  "deleting a shared network",
index a8749582da38674f314b145cc4a297ead2953fe6..7e54c1c0635bfdd9a6661a8a3308f4386fd2082d 100644 (file)
@@ -707,6 +707,14 @@ public:
                     continue;
                 }
 
+            } else if (server_selector.amUnassigned()) {
+                // Returned element has server tags but we expect that the
+                // elements are unassigned.
+                if (!(*elem)->getServerTags().empty()) {
+                    elem = index.erase(elem);
+                    continue;
+                }
+
             } else {
                 // Server selector contains explicit server tags, so
                 // let's see if the returned elements includes any of
index a5e5e1158b9f26a4bb3a9d3e1208ce9b6556b8ae..f56d2dab72f9b43adccf262adfc5bd84f7aeee83 100644 (file)
@@ -211,7 +211,7 @@ namespace {
 #endif
 
 #ifndef MYSQL_GET_SHARED_NETWORK4
-#define MYSQL_GET_SHARED_NETWORK4_COMMON(...) \
+#define MYSQL_GET_SHARED_NETWORK4_COMMON(server_join, ...) \
     "SELECT" \
     "  n.id," \
     "  n.name," \
@@ -249,21 +249,39 @@ namespace {
     "  n.max_valid_lifetime," \
     "  s.tag " \
     "FROM dhcp4_shared_network AS n " \
-    "INNER JOIN dhcp4_shared_network_server AS a " \
-    "  ON n.id = a.shared_network_id " \
-    "INNER JOIN dhcp4_server AS s " \
-    "  ON (a.server_id = s.id) " \
+    server_join \
     "LEFT JOIN dhcp4_options AS o ON o.scope_id = 4 AND n.name = o.shared_network_name " \
     #__VA_ARGS__ \
     " ORDER BY n.id, s.id, o.option_id"
 
 #define MYSQL_GET_SHARED_NETWORK4_NO_TAG(...) \
-    MYSQL_GET_SHARED_NETWORK4_COMMON(__VA_ARGS__)
+    MYSQL_GET_SHARED_NETWORK4_COMMON( \
+    "INNER JOIN dhcp4_shared_network_server AS a " \
+    "  ON n.id = a.shared_network_id " \
+    "INNER JOIN dhcp4_server AS s " \
+    "  ON (a.server_id = s.id) ", \
+    __VA_ARGS__)
+
+#define MYSQL_GET_SHARED_NETWORK4_ANY(...) \
+    MYSQL_GET_SHARED_NETWORK4_COMMON( \
+    "LEFT JOIN dhcp4_shared_network_server AS a " \
+    "  ON n.id = a.shared_network_id " \
+    "LEFT JOIN dhcp4_server AS s " \
+    "  ON a.server_id = s.id ", \
+    __VA_ARGS__)
+
+#define MYSQL_GET_SHARED_NETWORK4_UNASSIGNED(...) \
+    MYSQL_GET_SHARED_NETWORK4_COMMON( \
+    "LEFT JOIN dhcp4_shared_network_server AS a " \
+    "  ON n.id = a.shared_network_id " \
+    "LEFT JOIN dhcp4_server AS s " \
+    "  ON a.server_id = s.id ", \
+    WHERE a.shared_network_id IS NULL __VA_ARGS__)
 
 #endif
 
 #ifndef MYSQL_GET_SHARED_NETWORK6
-#define MYSQL_GET_SHARED_NETWORK6_COMMON(...) \
+#define MYSQL_GET_SHARED_NETWORK6_COMMON(server_join, ...) \
     "SELECT" \
     "  n.id," \
     "  n.name," \
@@ -302,16 +320,34 @@ namespace {
     "  n.max_valid_lifetime," \
     "  s.tag " \
     "FROM dhcp6_shared_network AS n " \
-    "INNER JOIN dhcp6_shared_network_server AS a " \
-    "  ON n.id = a.shared_network_id " \
-    "INNER JOIN dhcp6_server AS s " \
-    "  ON (a.server_id = s.id) " \
+    server_join \
     "LEFT JOIN dhcp6_options AS o ON o.scope_id = 4 AND n.name = o.shared_network_name " \
     #__VA_ARGS__ \
     " ORDER BY n.id, s.id, o.option_id"
 
 #define MYSQL_GET_SHARED_NETWORK6_NO_TAG(...) \
-    MYSQL_GET_SHARED_NETWORK6_COMMON(__VA_ARGS__)
+    MYSQL_GET_SHARED_NETWORK6_COMMON( \
+    "INNER JOIN dhcp6_shared_network_server AS a " \
+    "  ON n.id = a.shared_network_id " \
+    "INNER JOIN dhcp6_server AS s " \
+    "  ON (a.server_id = s.id) ", \
+    __VA_ARGS__)
+
+#define MYSQL_GET_SHARED_NETWORK6_ANY(...) \
+    MYSQL_GET_SHARED_NETWORK6_COMMON( \
+    "LEFT JOIN dhcp6_shared_network_server AS a " \
+    "  ON n.id = a.shared_network_id " \
+    "LEFT JOIN dhcp6_server AS s " \
+    "  ON a.server_id = s.id ", \
+    __VA_ARGS__)
+
+#define MYSQL_GET_SHARED_NETWORK6_UNASSIGNED(...) \
+    MYSQL_GET_SHARED_NETWORK6_COMMON( \
+    "LEFT JOIN dhcp6_shared_network_server AS a " \
+    "  ON n.id = a.shared_network_id " \
+    "LEFT JOIN dhcp6_server AS s " \
+    "  ON a.server_id = s.id ", \
+    WHERE a.shared_network_id IS NULL __VA_ARGS__)
 
 #endif
 
@@ -665,9 +701,9 @@ namespace {
 #define MYSQL_DELETE_SHARED_NETWORK_WITH_TAG(table_prefix, ...) \
     MYSQL_DELETE_SHARED_NETWORK_COMMON(table_prefix, WHERE s.tag = ? __VA_ARGS__)
 
-#define MYSQL_DELETE_SHARED_NETWORK_NO_TAG(table_prefix, ...) \
-    MYSQL_DELETE_SHARED_NETWORK_COMMON(table_prefix, __VA_ARGS__)
-
+#define MYSQL_DELETE_SHARED_NETWORK_ANY(table_prefix, ...) \
+    "DELETE n FROM " #table_prefix "_shared_network AS n " \
+    #__VA_ARGS__
 
 #endif
 
index 5abd2c4982e8b765b1732992bb2b8601afe94920..336f7b74aee2439e3cb9dfe6201616347902a27b 100644 (file)
@@ -1460,12 +1460,6 @@ TEST_F(MySqlConfigBackendDHCPv4Test, getSharedNetwork4) {
     EXPECT_THROW(cbptr_->getSharedNetwork4(ServerSelector::MULTIPLE({ "server1", "server2" }),
                                            test_networks_[0]->getName()),
                  isc::InvalidOperation);
-    // We currently don't support fetching a shared network which is assigned
-    // to no servers.
-    EXPECT_THROW(cbptr_->getSharedNetwork4(ServerSelector::UNASSIGNED(),
-                                           test_networks_[0]->getName()),
-                 isc::NotImplemented);
-
 
     // Test that this shared network will be fetched for various server selectors.
     auto test_get_network = [this, &shared_network] (const std::string& test_case_name,
@@ -1962,6 +1956,84 @@ TEST_F(MySqlConfigBackendDHCPv4Test, deleteSharedNetwork4) {
     test_delete("one server", ServerSelector::ONE("server1"), shared_network3);
 }
 
+// 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.
+    auto shared_network = test_networks_[0];
+    EXPECT_NO_THROW(
+        cbptr_->createUpdateSharedNetwork4(ServerSelector::ONE("server1"), shared_network)
+    );
+
+    // Delete the server. The shared network should be preserved but is
+    // considered orhpaned, i.e. does not belong to any server.
+    uint64_t deleted_count = 0;
+    EXPECT_NO_THROW(deleted_count = cbptr_->deleteServer4(ServerTag("server1")));
+    EXPECT_EQ(1, deleted_count);
+
+    // Trying to fetch this shared network by server tag should return no result.
+    SharedNetwork4Ptr returned_network;
+    EXPECT_NO_THROW(returned_network = cbptr_->getSharedNetwork4(ServerSelector::ONE("server1"),
+                                                                 "level1"));
+    EXPECT_FALSE(returned_network);
+
+    // The same if we use other calls.
+    SharedNetwork4Collection returned_networks;
+    EXPECT_NO_THROW(
+        returned_networks = cbptr_->getAllSharedNetworks4(ServerSelector::ONE("server1"))
+    );
+    EXPECT_TRUE(returned_networks.empty());
+
+    EXPECT_NO_THROW(
+        returned_networks = cbptr_->getModifiedSharedNetworks4(ServerSelector::ONE("server1"),
+                                                               timestamps_["two days ago"])
+    );
+    EXPECT_TRUE(returned_networks.empty());
+
+    // We should get the shared network if we ask for unassigned.
+    EXPECT_NO_THROW(returned_network = cbptr_->getSharedNetwork4(ServerSelector::UNASSIGNED(),
+                                                                 "level1"));
+    ASSERT_TRUE(returned_network);
+
+    // 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());
+
+    // And all modified.
+    EXPECT_NO_THROW(
+        returned_networks = cbptr_->getModifiedSharedNetworks4(ServerSelector::UNASSIGNED(),
+                                                               timestamps_["two days ago"])
+    );
+    ASSERT_EQ(1, returned_networks.size());
+
+    // If we ask for any network with this name, it should be returned too.
+    EXPECT_NO_THROW(returned_network = cbptr_->getSharedNetwork4(ServerSelector::ANY(),
+                                                                 "level1"));
+    ASSERT_TRUE(returned_network);
+
+    // Deleting a shared network with the mismatched server tag should not affect
+    // our shared network.
+    EXPECT_NO_THROW(
+        deleted_count = cbptr_->deleteSharedNetwork4(ServerSelector::ONE("server1"),
+                                                     "level1")
+    );
+    EXPECT_EQ(0, deleted_count);
+
+    // Also, if we delete all shared networks for server1.
+    EXPECT_NO_THROW(
+        deleted_count = cbptr_->deleteAllSharedNetworks4(ServerSelector::ONE("server1"))
+    );
+    EXPECT_EQ(0, deleted_count);
+
+    // We can delete this shared network when we specify ANY and the matching name.
+    EXPECT_NO_THROW(
+        deleted_count = cbptr_->deleteSharedNetwork4(ServerSelector::ANY(), "level1")
+    );
+    EXPECT_EQ(1, deleted_count);
+}
+
 // Test that lifetimes in shared networks are handled as expected.
 TEST_F(MySqlConfigBackendDHCPv4Test, sharedNetworkLifetime) {
     // Insert new shared network with unspecified valid lifetime
index a9af75113be8a0120eac36bb8074ca797d5a0a90..0998b1f1b6b422f53b917cc829b8e505bf7af1ae 100644 (file)
@@ -1475,11 +1475,6 @@ TEST_F(MySqlConfigBackendDHCPv6Test, getSharedNetwork6) {
     EXPECT_THROW(cbptr_->getSharedNetwork6(ServerSelector::MULTIPLE({ "server1", "server2" }),
                                            test_networks_[0]->getName()),
                  isc::InvalidOperation);
-    // We currently don't support fetching a shared network which is assigned
-    // to no servers.
-    EXPECT_THROW(cbptr_->getSharedNetwork6(ServerSelector::UNASSIGNED(),
-                                           test_networks_[0]->getName()),
-                 isc::NotImplemented);
 
     // Test that this shared network will be fetched for various server selectors.
     auto test_get_network = [this, &shared_network] (const std::string& test_case_name,
@@ -1977,6 +1972,84 @@ TEST_F(MySqlConfigBackendDHCPv6Test, deleteSharedNetwork6) {
     test_delete("one server", ServerSelector::ONE("server1"), shared_network3);
 }
 
+// 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.
+    auto shared_network = test_networks_[0];
+    EXPECT_NO_THROW(
+        cbptr_->createUpdateSharedNetwork6(ServerSelector::ONE("server1"), shared_network)
+    );
+
+    // Delete the server. The shared network should be preserved but is
+    // considered orhpaned, i.e. does not belong to any server.
+    uint64_t deleted_count = 0;
+    EXPECT_NO_THROW(deleted_count = cbptr_->deleteServer6(ServerTag("server1")));
+    EXPECT_EQ(1, deleted_count);
+
+    // Trying to fetch this shared network by server tag should return no result.
+    SharedNetwork6Ptr returned_network;
+    EXPECT_NO_THROW(returned_network = cbptr_->getSharedNetwork6(ServerSelector::ONE("server1"),
+                                                                 "level1"));
+    EXPECT_FALSE(returned_network);
+
+    // The same if we use other calls.
+    SharedNetwork6Collection returned_networks;
+    EXPECT_NO_THROW(
+        returned_networks = cbptr_->getAllSharedNetworks6(ServerSelector::ONE("server1"))
+    );
+    EXPECT_TRUE(returned_networks.empty());
+
+    EXPECT_NO_THROW(
+        returned_networks = cbptr_->getModifiedSharedNetworks6(ServerSelector::ONE("server1"),
+                                                               timestamps_["two days ago"])
+    );
+    EXPECT_TRUE(returned_networks.empty());
+
+    // We should get the shared network if we ask for unassigned.
+    EXPECT_NO_THROW(returned_network = cbptr_->getSharedNetwork6(ServerSelector::UNASSIGNED(),
+                                                                 "level1"));
+    ASSERT_TRUE(returned_network);
+
+    // 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());
+
+    // And all modified.
+    EXPECT_NO_THROW(
+        returned_networks = cbptr_->getModifiedSharedNetworks6(ServerSelector::UNASSIGNED(),
+                                                               timestamps_["two days ago"])
+    );
+    ASSERT_EQ(1, returned_networks.size());
+
+    // If we ask for any network with this name, it should be returned too.
+    EXPECT_NO_THROW(returned_network = cbptr_->getSharedNetwork6(ServerSelector::ANY(),
+                                                                 "level1"));
+    ASSERT_TRUE(returned_network);
+
+    // Deleting a shared network with the mismatched server tag should not affect
+    // our shared network.
+    EXPECT_NO_THROW(
+        deleted_count = cbptr_->deleteSharedNetwork6(ServerSelector::ONE("server1"),
+                                                     "level1")
+    );
+    EXPECT_EQ(0, deleted_count);
+
+    // Also, if we delete all shared networks for server1.
+    EXPECT_NO_THROW(
+        deleted_count = cbptr_->deleteAllSharedNetworks6(ServerSelector::ONE("server1"))
+    );
+    EXPECT_EQ(0, deleted_count);
+
+    // We can delete this shared network when we specify ANY and the matching name.
+    EXPECT_NO_THROW(
+        deleted_count = cbptr_->deleteSharedNetwork6(ServerSelector::ANY(), "level1")
+    );
+    EXPECT_EQ(1, deleted_count);
+}
+
 // Test that lifetimes in shared networks are handled as expected.
 TEST_F(MySqlConfigBackendDHCPv6Test, sharedNetworkLifetime) {
     // Insert new shared network with unspecified valid lifetime