This is an automated email from the ASF dual-hosted git repository.

wzhou pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/impala.git


The following commit(s) were added to refs/heads/master by this push:
     new f67f5f181 IMPALA-12705: Add /catalog_ha_info page on Statestore to 
show catalog HA information
f67f5f181 is described below

commit f67f5f1815c60a4723887ea6fcdaa067b7fa4ca5
Author: ttttttz <[email protected]>
AuthorDate: Fri May 31 10:24:47 2024 +0800

    IMPALA-12705: Add /catalog_ha_info page on Statestore to show catalog HA 
information
    
    This patch adds /catalog_ha_info page on Statestore to show catalog HA
    information. The page contains the following information: Active Node,
    Standby Node, and Notified Subscribers table. In the Notified
    Subscribers table, include the following information items:
      -- Id,
      -- Address,
      -- Registration ID,
      -- Subscriber Type,
      -- Catalogd Version,
      -- Catalogd Address,
      -- Last Update Catalogd Time
    
    Change-Id: If85f6a827ae8180d13caac588b92af0511ac35e3
    Reviewed-on: http://gerrit.cloudera.org:8080/21418
    Reviewed-by: Impala Public Jenkins <[email protected]>
    Tested-by: Impala Public Jenkins <[email protected]>
---
 be/src/statestore/statestore-catalogd-mgr.cc |  17 ++++
 be/src/statestore/statestore-catalogd-mgr.h  |  12 ++-
 be/src/statestore/statestore.cc              | 136 +++++++++++++++++++++++++++
 be/src/statestore/statestore.h               |  24 +++++
 common/thrift/StatestoreService.thrift       |   3 +
 tests/custom_cluster/test_catalogd_ha.py     |  41 ++++++++
 www/catalog_ha_info.tmpl                     |  84 +++++++++++++++++
 7 files changed, 316 insertions(+), 1 deletion(-)

diff --git a/be/src/statestore/statestore-catalogd-mgr.cc 
b/be/src/statestore/statestore-catalogd-mgr.cc
index a381e1a6b..1bb8c81a0 100644
--- a/be/src/statestore/statestore-catalogd-mgr.cc
+++ b/be/src/statestore/statestore-catalogd-mgr.cc
@@ -59,6 +59,7 @@ bool StatestoreCatalogdMgr::RegisterCatalogd(bool 
is_reregistering,
     is_active_catalogd_assigned_ = true;
     COPY_CATALOGD_REGISTRATION_FROM_LOCAL_VARIABLES(active);
     ++active_catalogd_version_;
+    last_update_catalogd_time_ = UnixMillis();
     return true;
   }
 
@@ -73,6 +74,7 @@ bool StatestoreCatalogdMgr::RegisterCatalogd(bool 
is_reregistering,
         LOG(INFO) << active_catalogd_subscriber_id_
                   << " is re-registered with FLAGS_force_catalogd_active.";
         ++active_catalogd_version_;
+        last_update_catalogd_time_ = UnixMillis();
         return true;
       }
     } else {
@@ -86,6 +88,7 @@ bool StatestoreCatalogdMgr::RegisterCatalogd(bool 
is_reregistering,
                   << " is re-registered after HA preemption waiting period and 
"
                   << "is assigned as active catalogd.";
         ++active_catalogd_version_;
+        last_update_catalogd_time_ = UnixMillis();
         return true;
       }
     }
@@ -116,6 +119,7 @@ bool StatestoreCatalogdMgr::RegisterCatalogd(bool 
is_reregistering,
       COPY_CATALOGD_REGISTRATION_FROM_LOCAL_VARIABLES(active);
       LOG(INFO) << active_catalogd_subscriber_id_ << " is assigned as active 
catalogd.";
       ++active_catalogd_version_;
+      last_update_catalogd_time_ = UnixMillis();
       return true;
     }
     // Wait second catalogd to be registered.
@@ -138,6 +142,7 @@ bool StatestoreCatalogdMgr::RegisterCatalogd(bool 
is_reregistering,
                 << " is registered with FLAGS_force_catalogd_active and is 
assigned as "
                 << "active catalogd.";
       ++active_catalogd_version_;
+      last_update_catalogd_time_ = UnixMillis();
       return true;
     } else if (is_active_catalogd_assigned_) {
       // Existing one is already assigned as active catalogd.
@@ -159,6 +164,7 @@ bool StatestoreCatalogdMgr::RegisterCatalogd(bool 
is_reregistering,
       LOG(INFO) << active_catalogd_subscriber_id_
                 << " has higher priority and is assigned as active catalogd.";
       ++active_catalogd_version_;
+      last_update_catalogd_time_ = UnixMillis();
       return true;
     }
   }
@@ -182,6 +188,7 @@ bool StatestoreCatalogdMgr::CheckActiveCatalog() {
   LOG(INFO) << active_catalogd_subscriber_id_
             << " is assigned as active catalogd after preemption waiting 
period.";
   ++active_catalogd_version_;
+  last_update_catalogd_time_ = UnixMillis();
   return true;
 }
 
@@ -197,6 +204,7 @@ bool StatestoreCatalogdMgr::UnregisterCatalogd(
       COPY_CATALOGD_REGISTRATION_FROM_MEMBER_VARIABLES(active, standby);
       RESET_CATALOGD_REGISTRATION_MEMBER_VARIABLES(standby);
       LOG(INFO) << "Fail over active catalogd to " << 
active_catalogd_subscriber_id_;
+      last_update_catalogd_time_ = UnixMillis();
       ++active_catalogd_version_;
       return true;
     } else {
@@ -226,6 +234,11 @@ const TCatalogRegistration& 
StatestoreCatalogdMgr::GetActiveCatalogRegistration(
   return active_catalogd_registration_;
 }
 
+const TCatalogRegistration& 
StatestoreCatalogdMgr::GetStandbyCatalogRegistration() {
+  std::lock_guard<std::mutex> l(catalog_mgr_lock_);
+  return standby_catalogd_registration_;
+}
+
 const SubscriberId& StatestoreCatalogdMgr::GetActiveCatalogdSubscriberId() {
   std::lock_guard<std::mutex> l(catalog_mgr_lock_);
   return active_catalogd_subscriber_id_;
@@ -236,3 +249,7 @@ bool StatestoreCatalogdMgr::IsActiveCatalogd(const 
SubscriberId& subscriber_id)
   return active_catalogd_subscriber_id_ == subscriber_id;
 }
 
+int64_t StatestoreCatalogdMgr::GetLastUpdateCatalogTime() {
+  std::lock_guard<std::mutex> l(catalog_mgr_lock_);
+  return last_update_catalogd_time_;
+}
diff --git a/be/src/statestore/statestore-catalogd-mgr.h 
b/be/src/statestore/statestore-catalogd-mgr.h
index 2fb7140ce..00b203437 100644
--- a/be/src/statestore/statestore-catalogd-mgr.h
+++ b/be/src/statestore/statestore-catalogd-mgr.h
@@ -45,7 +45,8 @@ class StatestoreCatalogdMgr {
       is_active_catalogd_assigned_(false),
       num_registered_catalogd_(0),
       first_catalogd_register_time_(0),
-      active_catalogd_version_(0L) {}
+      active_catalogd_version_(0L),
+      last_update_catalogd_time_(0L) {}
 
   /// Register one catalogd.
   /// Return true if new active catalogd is designated during this 
registration.
@@ -73,12 +74,18 @@ class StatestoreCatalogdMgr {
   /// This function should be called after the active catalogd is designated.
   const SubscriberId& GetActiveCatalogdSubscriberId();
 
+  /// Return the protocol version of catalog service and address of standby 
catalogd.
+  const TCatalogRegistration& GetStandbyCatalogRegistration();
+
   /// Check if the subscriber with given subscriber_id is active catalogd.
   bool IsActiveCatalogd(const SubscriberId&subscriber_id);
 
   /// Return the mutex lock.
   std::mutex* GetLock() { return &catalog_mgr_lock_; }
 
+  /// Return the last time when the catalogd is updated.
+  int64_t GetLastUpdateCatalogTime();
+
  private:
   /// Protect all member variables.
   std::mutex catalog_mgr_lock_;
@@ -119,6 +126,9 @@ class StatestoreCatalogdMgr {
   /// Monotonically increasing version number. The value is increased when a 
new active
   /// catalogd is designated.
   int64_t active_catalogd_version_;
+
+  /// The time is updated when a new active catalogd is designated.
+  int64_t last_update_catalogd_time_;
 };
 
 } // namespace impala
diff --git a/be/src/statestore/statestore.cc b/be/src/statestore/statestore.cc
index 3114cc9f7..c150bb1aa 100644
--- a/be/src/statestore/statestore.cc
+++ b/be/src/statestore/statestore.cc
@@ -284,6 +284,7 @@ class StatestoreThriftIf : public StatestoreServiceIf {
     TCatalogRegistration catalogd_registration;
     if (params.__isset.catalogd_registration) {
       catalogd_registration = params.catalogd_registration;
+      catalogd_registration.__set_registration_time(UnixMillis());
     }
 
     RegistrationId registration_id;
@@ -306,6 +307,7 @@ class StatestoreThriftIf : public StatestoreServiceIf {
     if (is_active_statestored && has_active_catalogd) {
       response.__set_catalogd_registration(active_catalogd_registration);
       response.__set_catalogd_version(active_catalogd_version);
+      statestore_->UpdateSubscriberCatalogInfo(params.subscriber_id);
     }
   }
 
@@ -645,6 +647,13 @@ void 
Statestore::Subscriber::RefreshLastHeartbeatTimestamp() {
   last_heartbeat_ts_.Store(MonotonicMillis());
 }
 
+void Statestore::Subscriber::UpdateCatalogInfo(
+    int64_t catalogd_version, const TNetworkAddress& catalogd_address) {
+  catalogd_version_ = catalogd_version;
+  catalogd_address_ = catalogd_address;
+  last_update_catalogd_time_ = UnixMillis();
+}
+
 Statestore::Statestore(MetricGroup* metrics)
   : protocol_version_(StatestoreServiceVersion::V2),
     catalog_manager_(FLAGS_enable_catalogd_ha),
@@ -817,6 +826,13 @@ void Statestore::RegisterWebpages(Webserver* webserver, 
bool metrics_only) {
   webserver->RegisterUrlCallback("/subscribers", "statestore_subscribers.tmpl",
       subscribers_callback, true);
 
+  if (FLAGS_enable_catalogd_ha) {
+    Webserver::UrlCallback show_catalog_ha_callback =
+        bind<void>(&Statestore::CatalogHAInfoHandler, this, _1, _2);
+    webserver->RegisterUrlCallback(
+        "/catalog_ha_info", "catalog_ha_info.tmpl", show_catalog_ha_callback, 
true);
+  }
+
   RegisterLogLevelCallbacks(webserver, false);
 }
 
@@ -1580,6 +1596,7 @@ void Statestore::SendUpdateCatalogdNotification(int64_t* 
last_active_catalogd_ve
         // left in the receiver list so that RPC will be resent to it in next 
round.
         ++it;
       } else {
+        UpdateSubscriberCatalogInfo(it->get()->id());
         successful_update_catalogd_rpc_metric_->Increment(1);
         // Remove the subscriber from the receiver list so that Statestore 
will not resend
         // RPC to it in next round.
@@ -2155,3 +2172,122 @@ Status Statestore::SendHaHeartbeat() {
   }
   return status;
 }
+
+void Statestore::UpdateSubscriberCatalogInfo(const SubscriberId& 
subscriber_id) {
+  lock_guard<mutex> l(subscribers_lock_);
+  SubscriberMap::iterator it = subscribers_.find(subscriber_id);
+  if (it == subscribers_.end()) return;
+  std::shared_ptr<Subscriber> subscriber = it->second;
+  bool has_active_catalogd;
+  int64_t active_catalogd_version = 0;
+  TCatalogRegistration catalogd_registration =
+      catalog_manager_.GetActiveCatalogRegistration(
+          &has_active_catalogd, &active_catalogd_version);
+  if (has_active_catalogd) {
+    subscriber->UpdateCatalogInfo(active_catalogd_version, 
catalogd_registration.address);
+  }
+}
+
+void Statestore::CatalogHAInfoHandler(
+    const Webserver::WebRequest& req, Document* document) {
+  if (FLAGS_enable_statestored_ha && !is_active_) {
+    document->AddMember("is_active_statestored", false, 
document->GetAllocator());
+    return;
+  }
+  document->AddMember("is_active_statestored", true, document->GetAllocator());
+  // HA INFO
+  bool has_active_catalogd;
+  int64_t active_catalogd_version = 0;
+  TCatalogRegistration active_catalog_registration =
+      catalog_manager_.GetActiveCatalogRegistration(&has_active_catalogd,
+          &active_catalogd_version);
+
+  document->AddMember("has_active_catalogd", has_active_catalogd,
+      document->GetAllocator());
+  document->AddMember("active_catalogd_version", active_catalogd_version,
+      document->GetAllocator());
+  if (active_catalogd_version > 0) {
+    Value last_update_catalogd_time_(ToStringFromUnixMillis(
+        catalog_manager_.GetLastUpdateCatalogTime(),
+        TimePrecision::Millisecond).c_str(), document->GetAllocator());
+    document->AddMember("last_update_catalogd_time", 
last_update_catalogd_time_,
+        document->GetAllocator());
+  }
+
+  if (has_active_catalogd) {
+    // Active catalogd information.
+    document->AddMember("active_catalogd_enable_catalogd_ha",
+        active_catalog_registration.enable_catalogd_ha, 
document->GetAllocator());
+    Value active_catalogd_address(
+        TNetworkAddressToString(active_catalog_registration.address).c_str(),
+        document->GetAllocator());
+    document->AddMember("active_catalogd_address", active_catalogd_address,
+        document->GetAllocator());
+    document->AddMember("active_catalogd_force_catalogd_active",
+        active_catalog_registration.force_catalogd_active, 
document->GetAllocator());
+    Value active_catalogd_registration_time(ToStringFromUnixMillis(
+        active_catalog_registration.registration_time,
+        TimePrecision::Millisecond).c_str(), document->GetAllocator());
+    document->AddMember("active_catalogd_registration_time",
+        active_catalogd_registration_time, document->GetAllocator());
+  }
+
+  // Standby catalogd information.
+  TCatalogRegistration standby_catalog_registration =
+      catalog_manager_.GetStandbyCatalogRegistration();
+  if (standby_catalog_registration.__isset.registration_time) {
+    document->AddMember("standby_catalogd_enable_catalogd_ha",
+        standby_catalog_registration.enable_catalogd_ha, 
document->GetAllocator());
+    Value standby_catalogd_address(
+        TNetworkAddressToString(standby_catalog_registration.address).c_str(),
+        document->GetAllocator());
+    document->AddMember(
+        "standby_catalogd_address", standby_catalogd_address, 
document->GetAllocator());
+    document->AddMember("standby_catalogd_force_catalogd_active",
+        standby_catalog_registration.force_catalogd_active, 
document->GetAllocator());
+    Value standby_catalogd_registration_time(ToStringFromUnixMillis(
+        standby_catalog_registration.registration_time,
+        TimePrecision::Millisecond).c_str(), document->GetAllocator());
+    document->AddMember("standby_catalogd_registration_time",
+        standby_catalogd_registration_time, document->GetAllocator());
+  }
+
+  lock_guard<mutex> l(subscribers_lock_);
+  Value notified_subscribers(kArrayType);
+  for (const SubscriberMap::value_type& subscriber : subscribers_) {
+    // Only subscribers of type COORDINATOR, COORDINATOR_EXECUTOR, or CATALOGD
+    // need to be returned.
+    if (subscriber.second->IsSubscribedCatalogdChange()) {
+      Value sub_json(kObjectType);
+      Value subscriber_id(subscriber.second->id().c_str(), 
document->GetAllocator());
+      sub_json.AddMember("id", subscriber_id, document->GetAllocator());
+      Value address(TNetworkAddressToString(
+          subscriber.second->network_address()).c_str(), 
document->GetAllocator());
+      sub_json.AddMember("address", address, document->GetAllocator());
+      Value 
registration_id(PrintId(subscriber.second->registration_id()).c_str(),
+          document->GetAllocator());
+      sub_json.AddMember("registration_id", registration_id, 
document->GetAllocator());
+      Value subscriber_type(SubscriberTypeToString(
+          subscriber.second->subscriber_type()).c_str(), 
document->GetAllocator());
+      sub_json.AddMember("subscriber_type", subscriber_type, 
document->GetAllocator());
+      if (subscriber.second->catalogd_version() > 0) {
+        sub_json.AddMember("catalogd_version", 
subscriber.second->catalogd_version(),
+            document->GetAllocator());
+        Value catalogd_address(TNetworkAddressToString(
+            subscriber.second->catalogd_address()).c_str(), 
document->GetAllocator());
+        sub_json.AddMember("catalogd_address", catalogd_address,
+            document->GetAllocator());
+        Value last_subscriber_update_catalogd_time(ToStringFromUnixMillis(
+            subscriber.second->last_update_catalogd_time(),
+            TimePrecision::Millisecond).c_str(), document->GetAllocator());
+        sub_json.AddMember("last_subscriber_update_catalogd_time",
+            last_subscriber_update_catalogd_time, document->GetAllocator());
+      }
+
+      notified_subscribers.PushBack(sub_json, document->GetAllocator());
+    }
+  }
+  document->AddMember(
+      "notified_subscribers", notified_subscribers, document->GetAllocator());
+  return;
+}
diff --git a/be/src/statestore/statestore.h b/be/src/statestore/statestore.h
index 11b0fb6fe..949cac7fd 100644
--- a/be/src/statestore/statestore.h
+++ b/be/src/statestore/statestore.h
@@ -292,6 +292,9 @@ class Statestore : public CacheLineAligned {
     return TNetworkAddressToString(peer_statestore_ha_addr_);
   }
 
+  // Update the subscriber's catalog information.
+  void UpdateSubscriberCatalogInfo(const SubscriberId& subscriber_id);
+
  private:
   /// A TopicEntry is a single entry in a topic, and logically is a <string, 
byte string>
   /// pair.
@@ -508,6 +511,10 @@ class Statestore : public CacheLineAligned {
     const TNetworkAddress& network_address() const { return network_address_; }
     const SubscriberId& id() const { return subscriber_id_; }
     const RegistrationId& registration_id() const { return registration_id_; }
+    TStatestoreSubscriberType::type subscriber_type() const { return 
subscriber_type_; }
+    int64_t catalogd_version() const { return catalogd_version_; }
+    const TNetworkAddress& catalogd_address() const { return 
catalogd_address_; }
+    int64_t last_update_catalogd_time() const { return 
last_update_catalogd_time_; }
 
     /// Returns the time elapsed (in seconds) since the last heartbeat.
     double SecondsSinceHeartbeat() const {
@@ -571,6 +578,10 @@ class Statestore : public CacheLineAligned {
       return subscribe_catalogd_change_;
     }
 
+    /// The subscriber updates the catalog information.
+    void UpdateCatalogInfo(
+        int64_t catalogd_version, const TNetworkAddress& catalogd_address);
+
    private:
     /// Unique human-readable identifier for this subscriber, set by the 
subscriber itself
     /// on a Register call.
@@ -610,6 +621,15 @@ class Statestore : public CacheLineAligned {
     /// True once DeleteAllTransientEntries() has been called during subscriber
     /// unregisteration. Protected by 'transient_entry_lock_'
     bool unregistered_ = false;
+
+    // Version of catalogd.
+    int64_t catalogd_version_ = 0L;
+
+    // Address of catalogd.
+    TNetworkAddress catalogd_address_;
+
+    // The last time to update the catalogd.
+    int64_t last_update_catalogd_time_ = 0L;
   };
 
   /// Unique identifier for this statestore instance.
@@ -1009,6 +1029,10 @@ class Statestore : public CacheLineAligned {
 
   // Return true if this statestore instance is in recovery mode.
   bool IsInRecoveryMode();
+
+  /// Json callback for /catalog_ha_info.
+  void CatalogHAInfoHandler(const Webserver::WebRequest& req,
+      rapidjson::Document* document);
 };
 
 } // namespace impala
diff --git a/common/thrift/StatestoreService.thrift 
b/common/thrift/StatestoreService.thrift
index 69b73a26d..98d079b89 100644
--- a/common/thrift/StatestoreService.thrift
+++ b/common/thrift/StatestoreService.thrift
@@ -217,6 +217,9 @@ struct TCatalogRegistration {
 
   // True if the catalogd instance is started as active instance.
   4: optional bool force_catalogd_active;
+
+  // The registration time of the catalogd.
+  5: optional i64 registration_time;
 }
 
 struct TRegisterSubscriberRequest {
diff --git a/tests/custom_cluster/test_catalogd_ha.py 
b/tests/custom_cluster/test_catalogd_ha.py
index 244b8a58f..c2b5cdb0f 100644
--- a/tests/custom_cluster/test_catalogd_ha.py
+++ b/tests/custom_cluster/test_catalogd_ha.py
@@ -16,8 +16,10 @@
 # under the License.
 
 from __future__ import absolute_import, division, print_function
+import json
 import logging
 import re
+import requests
 
 from tests.common.custom_cluster_test_suite import CustomClusterTestSuite
 from tests.common.environ import build_flavor_timeout
@@ -35,6 +37,12 @@ class TestCatalogdHA(CustomClusterTestSuite):
   statestored and catalogds are started with starting flag 
FLAGS_enable_catalogd_ha
   as true. """
 
+  VARZ_URL = "http://localhost:{0}/varz";
+  CATALOG_HA_INFO_URL = "http://localhost:{0}/catalog_ha_info";
+  JSON_METRICS_URL = "http://localhost:{0}/jsonmetrics";
+
+  SS_TEST_PORT = ["25010"]
+
   def get_workload(self):
     return 'functional-query'
 
@@ -461,3 +469,36 @@ class TestCatalogdHA(CustomClusterTestSuite):
 
     self.execute_query_expect_success(
         self.client, "select %s.identity_tmp(10)" % unique_database)
+
+  def test_page_with_disable_ha(self):
+    self.__test_catalog_ha_info_page()
+
+  @CustomClusterTestSuite.with_args(start_args="--enable_catalogd_ha")
+  def test_page_with_enable_ha(self):
+    self.__test_catalog_ha_info_page()
+
+  def __test_catalog_ha_info_page(self):
+    for port in self.SS_TEST_PORT:
+      response = requests.get(self.VARZ_URL.format(port) + "?json")
+      assert response.status_code == requests.codes.ok
+      varz_json = json.loads(response.text)
+      ha_flags = [e for e in varz_json["flags"]
+              if e["name"] == "enable_catalogd_ha"]
+      assert len(ha_flags) == 1
+      assert ha_flags[0]["default"] == "false"
+
+      # High availability for the Catalog is enabled.
+      if ha_flags[0]["current"] == "true":
+        url = self.JSON_METRICS_URL.format(port) + "?json"
+        metrics = json.loads(requests.get(url).text)
+        if metrics["statestore.active-status"]:
+          url = self.CATALOG_HA_INFO_URL.format(port) + "?json"
+          catalog_ha_info = json.loads(requests.get(url).text)
+          assert catalog_ha_info["active_catalogd_address"]\
+                 == metrics["statestore.active-catalogd-address"]
+        else:
+          reponse = requests.get(self.CATALOG_HA_INFO_URL.format(port)).text
+          assert reponse.__contains__("The current statestored is inactive.")
+      else:
+        page = requests.get(self.CATALOG_HA_INFO_URL.format(port))
+        assert page.status_code == requests.codes.not_found
diff --git a/www/catalog_ha_info.tmpl b/www/catalog_ha_info.tmpl
new file mode 100644
index 000000000..e2376b3ec
--- /dev/null
+++ b/www/catalog_ha_info.tmpl
@@ -0,0 +1,84 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+{{> www/common-header.tmpl }}
+{{#is_active_statestored}}
+<h2>HA Info</h2>
+<pre>
+<b>has-active-catalogd:</b> {{has_active_catalogd}}
+<b>active-catalogd-version:</b> {{active_catalogd_version}}
+<b>active-catalogd-address:</b> {{active_catalogd_address}}
+<b>last-update-catalogd-time:</b> {{last_update_catalogd_time}}
+</pre>
+<h2>Active Catalogd Info</h2>
+<pre>
+<b>enable-catalogd-ha:</b> {{active_catalogd_enable_catalogd_ha}}
+<b>address:</b> {{active_catalogd_address}}
+<b>force-catalogd-active:</b> {{active_catalogd_force_catalogd_active}}
+<b>registration-time:</b> {{active_catalogd_registration_time}}
+</pre>
+<h2>Standby Catalogd Info</h2>
+<pre>
+<b>enable-catalogd-ha:</b> {{standby_catalogd_enable_catalogd_ha}}
+<b>address:</b> {{standby_catalogd_address}}
+<b>force-catalogd-active:</b> {{standby_catalogd_force_catalogd_active}}
+<b>registration-time:</b> {{standby_catalogd_registration_time}}
+</pre>
+<h2>Notified Subscribers ({{%notified_subscribers}} total)</h2>
+  <table id="notified-subscribers-tbl" class='table table-hover table-striped'>
+    <thead>
+      <tr>
+        <th>Id</th>
+        <th>Address</th>
+        <th>Registration ID</th>
+        <th>Subscriber Type</th>
+        <th>Catalogd Version</th>
+        <th>Catalogd Address</th>
+        <th>Last Update Catalogd Time</th>
+      </tr>
+    </thead>
+    <tbody>
+      {{#notified_subscribers}}
+      <tr>
+        <td>{{id}}</td>
+        <td>{{address}}</td>
+        <td>{{registration_id}}</td>
+        <td>{{subscriber_type}}</td>
+        <td>{{catalogd_version}}</td>
+        <td>{{catalogd_address}}</td>
+        <td>{{last_subscriber_update_catalogd_time}}</td>
+      </tr>
+      {{/notified_subscribers}}
+    </tbody>
+  </table>
+{{/is_active_statestored}}
+
+{{^is_active_statestored}}
+<h5>The current statestored is inactive. Please refer to the active
+statestored for the catalog's high availability information.</h5>
+{{/is_active_statestored}}
+<script>
+    $(document).ready(function() {
+        $('#notified-subscribers-tbl').DataTable({
+            "order": [[ 6, "asc" ]],
+            "pageLength": 100
+        });
+    });
+</script>
+
+{{> www/common-footer.tmpl }}

Reply via email to