]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
rbd-mirror: add namespace support to service daemon 31642/head
authorMykola Golub <mgolub@suse.com>
Thu, 14 Nov 2019 16:13:22 +0000 (16:13 +0000)
committerMykola Golub <mgolub@suse.com>
Fri, 15 Nov 2019 09:28:07 +0000 (09:28 +0000)
Signed-off-by: Mykola Golub <mgolub@suse.com>
src/test/rbd_mirror/test_mock_InstanceReplayer.cc
src/test/rbd_mirror/test_mock_NamespaceReplayer.cc
src/test/rbd_mirror/test_mock_PoolReplayer.cc
src/tools/rbd_mirror/InstanceReplayer.cc
src/tools/rbd_mirror/NamespaceReplayer.cc
src/tools/rbd_mirror/PoolReplayer.cc
src/tools/rbd_mirror/ServiceDaemon.cc
src/tools/rbd_mirror/ServiceDaemon.h

index 0d1b620c53ff179de21f4f692cd312b8a4decc5e..743c709bdda20b7daca8199eac58bcd93288cd32 100644 (file)
@@ -50,8 +50,8 @@ struct Threads<librbd::MockTestImageCtx> {
 
 template<>
 struct ServiceDaemon<librbd::MockTestImageCtx> {
-  MOCK_METHOD3(add_or_update_attribute,
-               void(int64_t, const std::string&,
+  MOCK_METHOD4(add_or_update_namespace_attribute,
+               void(int64_t, const std::string&, const std::string&,
                     const service_daemon::AttributeValue&));
 };
 
@@ -299,7 +299,8 @@ TEST_F(TestMockInstanceReplayer, RemoveFinishedImage) {
   EXPECT_CALL(mock_image_replayer, is_blacklisted()).WillOnce(Return(false));
   EXPECT_CALL(mock_image_replayer, is_finished()).WillOnce(Return(true));
   EXPECT_CALL(mock_image_replayer, destroy());
-  EXPECT_CALL(mock_service_daemon,add_or_update_attribute(_, _, _)).Times(3);
+  EXPECT_CALL(mock_service_daemon,
+              add_or_update_namespace_attribute(_, _, _, _)).Times(3);
 
   ASSERT_TRUE(start_image_replayers_ctx != nullptr);
   start_image_replayers_ctx->complete(0);
index 6cde475a2f735a0fe7e51903c6903d75122796fa..162d2abef02059fe05a3ad301347ae6b93c9825a 100644 (file)
@@ -221,8 +221,8 @@ std::map<int64_t, PoolWatcher<librbd::MockTestImageCtx> *> PoolWatcher<librbd::M
 
 template<>
 struct ServiceDaemon<librbd::MockTestImageCtx> {
-  MOCK_METHOD3(add_or_update_attribute,
-               void(int64_t, const std::string&,
+  MOCK_METHOD4(add_or_update_namespace_attribute,
+               void(int64_t, const std::string&, const std::string&,
                     const service_daemon::AttributeValue&));
   MOCK_METHOD2(remove_attribute,
                void(int64_t, const std::string&));
@@ -386,20 +386,6 @@ public:
       .WillOnce(CompleteContext(m_mock_threads->work_queue, 0));
   }
 
-  void expect_service_daemon_add_or_update_attribute(
-      MockServiceDaemon &mock_service_daemon, const std::string& key,
-      const service_daemon::AttributeValue& value) {
-    EXPECT_CALL(mock_service_daemon, add_or_update_attribute(_, key, value));
-  }
-
-  void expect_service_daemon_add_or_update_instance_id_attribute(
-      MockInstanceWatcher &mock_instance_watcher,
-      MockServiceDaemon &mock_service_daemon) {
-    expect_instance_watcher_get_instance_id(mock_instance_watcher, "1234");
-    expect_service_daemon_add_or_update_attribute(
-        mock_service_daemon, "instance_id", {std::string("1234")});
-  }
-
   MockThreads *m_mock_threads;
 };
 
@@ -515,9 +501,6 @@ TEST_F(TestMockNamespaceReplayer, Init) {
   expect_instance_watcher_init(*mock_instance_watcher, 0);
 
   MockServiceDaemon mock_service_daemon;
-  expect_service_daemon_add_or_update_instance_id_attribute(
-      *mock_instance_watcher, mock_service_daemon);
-
   MockNamespaceReplayer namespace_replayer(
       {}, m_local_io_ctx, m_remote_io_ctx, "local mirror uuid",
       "remote mirror uuid", "siteA", m_mock_threads, nullptr, nullptr,
@@ -558,9 +541,6 @@ TEST_F(TestMockNamespaceReplayer, AcuqireLeader) {
   expect_instance_watcher_init(*mock_instance_watcher, 0);
 
   MockServiceDaemon mock_service_daemon;
-  expect_service_daemon_add_or_update_instance_id_attribute(
-      *mock_instance_watcher, mock_service_daemon);
-
   MockNamespaceReplayer namespace_replayer(
       {}, m_local_io_ctx, m_remote_io_ctx, "local mirror uuid",
       "remote mirror uuid", "siteA", m_mock_threads, nullptr, nullptr,
index 039ab7292e4c00d1eb0e723b6179cecd87c1fc8c..756d3906490f32b4c6d8f5ba1e7f064a62428c25 100644 (file)
@@ -202,6 +202,9 @@ LeaderWatcher<librbd::MockTestImageCtx>* LeaderWatcher<librbd::MockTestImageCtx>
 
 template<>
 struct ServiceDaemon<librbd::MockTestImageCtx> {
+  MOCK_METHOD2(add_namespace, void(int64_t, const std::string &));
+  MOCK_METHOD2(remove_namespace, void(int64_t, const std::string &));
+
   MOCK_METHOD3(add_or_update_attribute,
                void(int64_t, const std::string&,
                     const service_daemon::AttributeValue&));
@@ -436,6 +439,20 @@ public:
     EXPECT_CALL(mock_namespace_replayer, handle_instances_removed(_));
   }
 
+  void expect_service_daemon_add_namespace(
+      MockServiceDaemon &mock_service_daemon,
+      const std::string& namespace_name) {
+    EXPECT_CALL(mock_service_daemon,
+                add_namespace(m_local_io_ctx.get_id(), namespace_name));
+  }
+
+  void expect_service_daemon_remove_namespace(
+      MockServiceDaemon &mock_service_daemon,
+      const std::string& namespace_name) {
+    EXPECT_CALL(mock_service_daemon,
+                remove_namespace(m_local_io_ctx.get_id(), namespace_name));
+  }
+
   void expect_service_daemon_add_or_update_attribute(
       MockServiceDaemon &mock_service_daemon, const std::string& key,
       const service_daemon::AttributeValue& value) {
@@ -446,6 +463,12 @@ public:
       MockServiceDaemon &mock_service_daemon, const std::string& key) {
     EXPECT_CALL(mock_service_daemon, remove_attribute(_, key));
   }
+
+  void expect_service_daemon_add_or_update_instance_id_attribute(
+      MockServiceDaemon &mock_service_daemon, const std::string &instance_id) {
+    expect_service_daemon_add_or_update_attribute(
+        mock_service_daemon, "instance_id", {instance_id});
+  }
 };
 
 TEST_F(TestMockPoolReplayer, ConfigKeyOverride) {
@@ -485,6 +508,10 @@ TEST_F(TestMockPoolReplayer, ConfigKeyOverride) {
   expect_leader_watcher_init(*mock_leader_watcher, 0);
 
   MockServiceDaemon mock_service_daemon;
+  std::string instance_id = stringify(mock_local_io_ctx->get_instance_id());
+  expect_service_daemon_add_or_update_instance_id_attribute(
+    mock_service_daemon, instance_id);
+
   MockPoolReplayer pool_replayer(&mock_threads, &mock_service_daemon, nullptr,
                                  m_local_io_ctx.get_id(), peer_spec, {});
   pool_replayer.init("siteA");
@@ -537,6 +564,10 @@ TEST_F(TestMockPoolReplayer, AcquireReleaseLeader) {
   expect_leader_watcher_init(*mock_leader_watcher, 0);
 
   MockServiceDaemon mock_service_daemon;
+  std::string instance_id = stringify(mock_local_io_ctx->get_instance_id());
+  expect_service_daemon_add_or_update_instance_id_attribute(
+    mock_service_daemon, instance_id);
+
   MockPoolReplayer pool_replayer(&mock_threads, &mock_service_daemon, nullptr,
                                  m_local_io_ctx.get_id(), peer_spec, {});
   pool_replayer.init("siteA");
@@ -615,12 +646,17 @@ TEST_F(TestMockPoolReplayer, Namespaces) {
   expect_leader_watcher_init(*mock_leader_watcher, 0);
 
   MockServiceDaemon mock_service_daemon;
+  std::string instance_id = stringify(mock_local_io_ctx->get_instance_id());
+  expect_service_daemon_add_or_update_instance_id_attribute(
+    mock_service_daemon, instance_id);
+
   MockPoolReplayer pool_replayer(&mock_threads, &mock_service_daemon, nullptr,
                                  m_local_io_ctx.get_id(), peer_spec, {});
   pool_replayer.init("siteA");
 
   C_SaferCond on_ns1_init;
   expect_namespace_replayer_init(*mock_ns1_namespace_replayer, 0);
+  expect_service_daemon_add_namespace(mock_service_daemon, "ns1");
   expect_namespace_replayer_handle_update_leader(*mock_ns1_namespace_replayer,
                                                  "", &on_ns1_init);
 
@@ -639,6 +675,7 @@ TEST_F(TestMockPoolReplayer, Namespaces) {
   ASSERT_EQ(0, on_acquire.wait());
 
   expect_namespace_replayer_init(*mock_ns2_namespace_replayer, 0);
+  expect_service_daemon_add_namespace(mock_service_daemon, "ns2");
   C_SaferCond on_ns2_acquire;
   expect_namespace_replayer_handle_acquire_leader(
       *mock_ns2_namespace_replayer, 0, &on_ns2_acquire);
@@ -649,6 +686,7 @@ TEST_F(TestMockPoolReplayer, Namespaces) {
   ASSERT_EQ(0, on_ns2_acquire.wait());
 
   C_SaferCond on_ns2_shut_down;
+  expect_service_daemon_remove_namespace(mock_service_daemon, "ns2");
   expect_namespace_replayer_shut_down(*mock_ns2_namespace_replayer,
                                       &on_ns2_shut_down);
   mock_namespace.remove("ns2");
@@ -665,6 +703,7 @@ TEST_F(TestMockPoolReplayer, Namespaces) {
   mock_leader_watcher->listener->pre_release_handler(&on_release);
   ASSERT_EQ(0, on_release.wait());
 
+  expect_service_daemon_remove_namespace(mock_service_daemon, "ns1");
   expect_namespace_replayer_shut_down(*mock_ns1_namespace_replayer);
   expect_leader_watcher_shut_down(*mock_leader_watcher);
   expect_namespace_replayer_shut_down(*mock_default_namespace_replayer);
@@ -719,6 +758,10 @@ TEST_F(TestMockPoolReplayer, NamespacesError) {
   expect_leader_watcher_init(*mock_leader_watcher, 0);
 
   MockServiceDaemon mock_service_daemon;
+  std::string instance_id = stringify(mock_local_io_ctx->get_instance_id());
+  expect_service_daemon_add_or_update_instance_id_attribute(
+    mock_service_daemon, instance_id);
+
   MockPoolReplayer pool_replayer(&mock_threads, &mock_service_daemon, nullptr,
                                  m_local_io_ctx.get_id(), peer_spec, {});
   pool_replayer.init("siteA");
@@ -750,11 +793,12 @@ TEST_F(TestMockPoolReplayer, NamespacesError) {
 
   C_SaferCond on_ns2_init;
   expect_namespace_replayer_init(*mock_ns2_namespace_replayer, 0);
+  expect_service_daemon_add_namespace(mock_service_daemon, "ns2");
   expect_namespace_replayer_handle_update_leader(*mock_ns2_namespace_replayer,
                                                  "", &on_ns2_init);
   mock_namespace.add("ns2");
   ASSERT_EQ(0, on_ns2_init.wait());
-  
+
   expect_service_daemon_add_or_update_attribute(
       mock_service_daemon, SERVICE_DAEMON_LEADER_KEY, true);
   expect_namespace_replayer_handle_acquire_leader(
@@ -766,6 +810,7 @@ TEST_F(TestMockPoolReplayer, NamespacesError) {
       [&mock_namespace](int) {
         mock_namespace.remove("ns2");
       });
+  expect_service_daemon_remove_namespace(mock_service_daemon, "ns2");
   expect_namespace_replayer_shut_down(*mock_ns2_namespace_replayer, ctx);
   mock_namespace.add("ns2");
 
@@ -782,8 +827,10 @@ TEST_F(TestMockPoolReplayer, NamespacesError) {
         on_ns3_shut_down.complete(0);
       });
   expect_namespace_replayer_init(*mock_ns3_namespace_replayer, 0);
+  expect_service_daemon_add_namespace(mock_service_daemon, "ns3");
   expect_namespace_replayer_handle_acquire_leader(*mock_ns3_namespace_replayer,
                                                   -EINVAL);
+  expect_service_daemon_remove_namespace(mock_service_daemon, "ns3");
   expect_namespace_replayer_shut_down(*mock_ns3_namespace_replayer, ctx);
   mock_namespace.add("ns3");
   ASSERT_EQ(0, on_ns3_shut_down.wait());
index 9795f8073f1df38d39e2cc1e031909cee567c402..5e6fc66366d5b16b6634fb165bf383ae947c2453 100644 (file)
@@ -382,15 +382,15 @@ void InstanceReplayer<I>::start_image_replayers(int r) {
     start_image_replayer(current_it->second);
   }
 
-  // TODO: add namespace support to service daemon
-  if (m_local_io_ctx.get_namespace().empty()) {
-    m_service_daemon->add_or_update_attribute(
-      m_local_io_ctx.get_id(), SERVICE_DAEMON_ASSIGNED_COUNT_KEY, image_count);
-    m_service_daemon->add_or_update_attribute(
-      m_local_io_ctx.get_id(), SERVICE_DAEMON_WARNING_COUNT_KEY, warning_count);
-    m_service_daemon->add_or_update_attribute(
-      m_local_io_ctx.get_id(), SERVICE_DAEMON_ERROR_COUNT_KEY, error_count);
-  }
+  m_service_daemon->add_or_update_namespace_attribute(
+    m_local_io_ctx.get_id(), m_local_io_ctx.get_namespace(),
+    SERVICE_DAEMON_ASSIGNED_COUNT_KEY, image_count);
+  m_service_daemon->add_or_update_namespace_attribute(
+    m_local_io_ctx.get_id(), m_local_io_ctx.get_namespace(),
+    SERVICE_DAEMON_WARNING_COUNT_KEY, warning_count);
+  m_service_daemon->add_or_update_namespace_attribute(
+    m_local_io_ctx.get_id(), m_local_io_ctx.get_namespace(),
+    SERVICE_DAEMON_ERROR_COUNT_KEY, error_count);
 
   m_async_op_tracker.finish_op();
 }
index b22a547dc7623b7742901656afaff04fd8aef2b1..983682159dcea7039a9cf2f50b6fcf3699311bab 100644 (file)
@@ -29,7 +29,6 @@ using ::operator<<;
 
 namespace {
 
-const std::string SERVICE_DAEMON_INSTANCE_ID_KEY("instance_id");
 const std::string SERVICE_DAEMON_LOCAL_COUNT_KEY("image_local_count");
 const std::string SERVICE_DAEMON_REMOTE_COUNT_KEY("image_remote_count");
 
@@ -183,16 +182,14 @@ void NamespaceReplayer<I>::handle_update(const std::string &mirror_uuid,
            << "added_count=" << added_image_ids.size() << ", "
            << "removed_count=" << removed_image_ids.size() << dendl;
 
-  // TODO: add namespace support to service daemon
-  if (m_local_io_ctx.get_namespace().empty()) {
-    m_service_daemon->add_or_update_attribute(
-        m_local_io_ctx.get_id(), SERVICE_DAEMON_LOCAL_COUNT_KEY,
-        m_local_pool_watcher->get_image_count());
-    if (m_remote_pool_watcher) {
-      m_service_daemon->add_or_update_attribute(
-          m_local_io_ctx.get_id(), SERVICE_DAEMON_REMOTE_COUNT_KEY,
-          m_remote_pool_watcher->get_image_count());
-    }
+  m_service_daemon->add_or_update_namespace_attribute(
+    m_local_io_ctx.get_id(), m_local_io_ctx.get_namespace(),
+    SERVICE_DAEMON_LOCAL_COUNT_KEY, m_local_pool_watcher->get_image_count());
+  if (m_remote_pool_watcher) {
+    m_service_daemon->add_or_update_namespace_attribute(
+      m_local_io_ctx.get_id(), m_local_io_ctx.get_namespace(),
+      SERVICE_DAEMON_REMOTE_COUNT_KEY,
+      m_remote_pool_watcher->get_image_count());
   }
 
   std::set<std::string> added_global_image_ids;
@@ -397,13 +394,6 @@ void NamespaceReplayer<I>::handle_init_instance_watcher(int r) {
     return;
   }
 
-  // TODO: add namespace support to service daemon
-  if (m_local_io_ctx.get_namespace().empty()) {
-    m_service_daemon->add_or_update_attribute(
-        m_local_io_ctx.get_id(), SERVICE_DAEMON_INSTANCE_ID_KEY,
-        m_instance_watcher->get_instance_id());
-  }
-
   ceph_assert(m_on_finish != nullptr);
   m_threads->work_queue->queue(m_on_finish);
   m_on_finish = nullptr;
index 74bb06c48ce7918309c8ce7df010658fcb51e56e..75ddc5fd95671416b66e57f6fd2c913561c6b34d 100644 (file)
@@ -31,6 +31,7 @@ using ::operator<<;
 
 namespace {
 
+const std::string SERVICE_DAEMON_INSTANCE_ID_KEY("instance_id");
 const std::string SERVICE_DAEMON_LEADER_KEY("leader");
 
 const std::vector<std::string> UNIQUE_PEER_CONFIG_KEYS {
@@ -352,6 +353,10 @@ void PoolReplayer<I>::init(const std::string& site_name) {
     m_callout_id = service_daemon::CALLOUT_ID_NONE;
   }
 
+  m_service_daemon->add_or_update_attribute(
+    m_local_io_ctx.get_id(), SERVICE_DAEMON_INSTANCE_ID_KEY,
+    stringify(m_local_io_ctx.get_instance_id()));
+
   m_pool_replayer_thread.create("pool replayer");
 }
 
@@ -586,6 +591,7 @@ void PoolReplayer<I>::update_namespace_replayers() {
           delete namespace_replayer;
           ctx->complete(r);
         });
+      m_service_daemon->remove_namespace(m_local_pool_id, it->first);
       namespace_replayer->shut_down(on_shut_down);
       it = m_namespace_replayers.erase(it);
     } else {
@@ -611,6 +617,7 @@ void PoolReplayer<I>::update_namespace_replayers() {
           } else {
             std::lock_guard locker{m_lock};
             m_namespace_replayers[name] = namespace_replayer;
+            m_service_daemon->add_namespace(m_local_pool_id, name);
           }
           ctx->complete(r);
         });
@@ -716,6 +723,7 @@ void PoolReplayer<I>::namespace_replayer_acquire_leader(const std::string &name,
                 delete namespace_replayer;
                 on_finish->complete(r);
               });
+          m_service_daemon->remove_namespace(m_local_pool_id, name);
           namespace_replayer->shut_down(on_shut_down);
           return;
         }
index 19f69ea88de7f091518ccf4e389a8eab416e162a..f3cabcc873a41a74750bd6388451626ef17e97da 100644 (file)
@@ -108,6 +108,38 @@ void ServiceDaemon<I>::remove_pool(int64_t pool_id) {
   schedule_update_status();
 }
 
+template <typename I>
+void ServiceDaemon<I>::add_namespace(int64_t pool_id,
+                                     const std::string& namespace_name) {
+  dout(20) << "pool_id=" << pool_id << ", namespace=" << namespace_name
+           << dendl;
+
+  std::lock_guard locker{m_lock};
+  auto pool_it = m_pools.find(pool_id);
+  if (pool_it == m_pools.end()) {
+    return;
+  }
+  pool_it->second.ns_attributes[namespace_name];
+
+  // don't schedule update status as the namespace attributes are empty yet
+}
+
+template <typename I>
+void ServiceDaemon<I>::remove_namespace(int64_t pool_id,
+                                        const std::string& namespace_name) {
+  dout(20) << "pool_id=" << pool_id << ", namespace=" << namespace_name
+           << dendl;
+  {
+    std::lock_guard locker{m_lock};
+    auto pool_it = m_pools.find(pool_id);
+    if (pool_it == m_pools.end()) {
+      return;
+    }
+    pool_it->second.ns_attributes.erase(namespace_name);
+  }
+  schedule_update_status();
+}
+
 template <typename I>
 uint64_t ServiceDaemon<I>::add_or_update_callout(int64_t pool_id,
                                                  uint64_t callout_id,
@@ -172,6 +204,38 @@ void ServiceDaemon<I>::add_or_update_attribute(int64_t pool_id,
   schedule_update_status();
 }
 
+template <typename I>
+void ServiceDaemon<I>::add_or_update_namespace_attribute(
+    int64_t pool_id, const std::string& namespace_name, const std::string& key,
+    const AttributeValue& value) {
+  if (namespace_name.empty()) {
+    add_or_update_attribute(pool_id, key, value);
+    return;
+  }
+
+  dout(20) << "pool_id=" << pool_id << ", "
+           << "namespace=" << namespace_name << ", "
+           << "key=" << key << ", "
+           << "value=" << value << dendl;
+
+  {
+    std::lock_guard locker{m_lock};
+    auto pool_it = m_pools.find(pool_id);
+    if (pool_it == m_pools.end()) {
+      return;
+    }
+
+    auto ns_it = pool_it->second.ns_attributes.find(namespace_name);
+    if (ns_it == pool_it->second.ns_attributes.end()) {
+      return;
+    }
+
+    ns_it->second[key] = value;
+  }
+
+  schedule_update_status();
+}
+
 template <typename I>
 void ServiceDaemon<I>::remove_attribute(int64_t pool_id,
                                         const std::string& key) {
@@ -229,6 +293,19 @@ void ServiceDaemon<I>::update_status() {
         AttributeDumpVisitor attribute_dump_visitor(&f, attribute.first);
         boost::apply_visitor(attribute_dump_visitor, attribute.second);
       }
+
+      if (!pool_pair.second.ns_attributes.empty()) {
+        f.open_object_section("namespaces");
+        for (auto& [ns, attributes] : pool_pair.second.ns_attributes) {
+          f.open_object_section(ns.c_str());
+          for (auto& [key, value] : attributes) {
+            AttributeDumpVisitor attribute_dump_visitor(&f, key);
+            boost::apply_visitor(attribute_dump_visitor, value);
+          }
+          f.close_section(); // namespace
+        }
+        f.close_section(); // namespaces
+      }
       f.close_section(); // pool
     }
     f.close_section(); // pools
index 68599df8099e6b08297a8de27d0816df1eca7afc..8df1bda8f5c46ea5693b1df7150087d3d49b3737 100644 (file)
@@ -30,6 +30,9 @@ public:
   void add_pool(int64_t pool_id, const std::string& pool_name);
   void remove_pool(int64_t pool_id);
 
+  void add_namespace(int64_t pool_id, const std::string& namespace_name);
+  void remove_namespace(int64_t pool_id, const std::string& namespace_name);
+
   uint64_t add_or_update_callout(int64_t pool_id, uint64_t callout_id,
                                  service_daemon::CalloutLevel callout_level,
                                  const std::string& text);
@@ -37,6 +40,9 @@ public:
 
   void add_or_update_attribute(int64_t pool_id, const std::string& key,
                                const service_daemon::AttributeValue& value);
+  void add_or_update_namespace_attribute(
+      int64_t pool_id, const std::string& namespace_name,
+      const std::string& key, const service_daemon::AttributeValue& value);
   void remove_attribute(int64_t pool_id, const std::string& key);
 
 private:
@@ -52,11 +58,13 @@ private:
   };
   typedef std::map<uint64_t, Callout> Callouts;
   typedef std::map<std::string, service_daemon::AttributeValue> Attributes;
+  typedef std::map<std::string, Attributes> NamespaceAttributes;
 
   struct Pool {
     std::string name;
     Callouts callouts;
     Attributes attributes;
+    NamespaceAttributes ns_attributes;
 
     Pool(const std::string& name) : name(name) {
     }