From 2e9d27ec3d36a3062a5aa8c948e6851847eeef83 Mon Sep 17 00:00:00 2001
From: "lionel.liu@vesoft.com" <lionel.liu@vesoft.com>
Date: Wed, 9 Dec 2020 11:24:38 +0800
Subject: [PATCH] let "show hosts" can show git info sha of graph/meta/storage
 (#437)

* init upload

* remove debug code

* add parser test

* address commens from Laura

* address cpw's comments

* address cpw's comments

Co-authored-by: cpw <13495049+CPWstatic@users.noreply.github.com>
---
 src/executor/admin/ShowHostsExecutor.cpp | 122 +++++++++++++----------
 src/parser/AdminSentences.h              |  12 +++
 src/parser/parser.yy                     |  15 ++-
 src/parser/test/ParserTest.cpp           |  18 ++++
 src/planner/Admin.h                      |  13 ++-
 src/service/QueryEngine.cpp              |  10 +-
 src/validator/AdminValidator.cpp         |   3 +-
 7 files changed, 133 insertions(+), 60 deletions(-)

diff --git a/src/executor/admin/ShowHostsExecutor.cpp b/src/executor/admin/ShowHostsExecutor.cpp
index 61e4ae43..9bfead20 100644
--- a/src/executor/admin/ShowHostsExecutor.cpp
+++ b/src/executor/admin/ShowHostsExecutor.cpp
@@ -5,8 +5,8 @@
  */
 
 #include "executor/admin/ShowHostsExecutor.h"
-#include "planner/Admin.h"
 #include "context/QueryContext.h"
+#include "planner/Admin.h"
 #include "util/ScopedTimer.h"
 
 namespace nebula {
@@ -18,64 +18,86 @@ folly::Future<Status> ShowHostsExecutor::execute() {
 }
 
 folly::Future<Status> ShowHostsExecutor::showHosts() {
-    static constexpr char kNoPartition[]        = "No valid partition";
+    static constexpr char kNoPartition[] = "No valid partition";
     static constexpr char kPartitionDelimeter[] = ", ";
+
+    auto *shNode = asNode<ShowHosts>(node());
+    auto makeTranditionalResult = [&](const std::vector<meta::cpp2::HostItem> &hostVec) -> DataSet {
+        DataSet v({"Host",
+                   "Port",
+                   "Status",
+                   "Leader count",
+                   "Leader distribution",
+                   "Partition distribution"});
+        for (const auto &host : hostVec) {
+            nebula::Row r({host.get_hostAddr().host,
+                           host.get_hostAddr().port,
+                           meta::cpp2::_HostStatus_VALUES_TO_NAMES.at(host.get_status())});
+            int64_t leaderCount = 0;
+            for (const auto &spaceEntry : host.get_leader_parts()) {
+                leaderCount += spaceEntry.second.size();
+            }
+            std::stringstream leaders;
+            std::stringstream parts;
+            std::size_t i = 0;
+            for (const auto &l : host.get_leader_parts()) {
+                leaders << l.first << ":" << l.second.size();
+                if (i < host.get_leader_parts().size() - 1) {
+                    leaders << kPartitionDelimeter;
+                }
+                ++i;
+            }
+            if (host.get_leader_parts().empty()) {
+                leaders << kNoPartition;
+            }
+            i = 0;
+            for (const auto &p : host.get_all_parts()) {
+                parts << p.first << ":" << p.second.size();
+                if (i < host.get_all_parts().size() - 1) {
+                    parts << kPartitionDelimeter;
+                }
+                ++i;
+            }
+            if (host.get_all_parts().empty()) {
+                parts << kNoPartition;
+            }
+            r.emplace_back(leaderCount);
+            r.emplace_back(leaders.str());
+            r.emplace_back(parts.str());
+            v.emplace_back(std::move(r));
+        }   // row loop
+        return v;
+    };
+
+    auto makeGitInfoResult = [&](const std::vector<meta::cpp2::HostItem> &hostVec) -> DataSet {
+        DataSet v({"Host", "Port", "Status", "Role", "Git Info Sha"});
+        for (const auto &host : hostVec) {
+            nebula::Row r({host.get_hostAddr().host,
+                           host.get_hostAddr().port,
+                           meta::cpp2::_HostStatus_VALUES_TO_NAMES.at(host.get_status()),
+                           meta::cpp2::_HostRole_VALUES_TO_NAMES.at(host.get_role()),
+                           host.get_git_info_sha()});
+            v.emplace_back(std::move(r));
+        }   // row loop
+        return v;
+    };
+
     return qctx()
         ->getMetaClient()
-        ->listHosts()
+        ->listHosts(shNode->getType())
         .via(runner())
-        .then([this](auto &&resp) {
+        .then([=, type = shNode->getType()](auto &&resp) {
             if (!resp.ok()) {
                 LOG(ERROR) << resp.status();
                 return resp.status();
             }
             auto value = std::move(resp).value();
-            DataSet v({"Host",
-                       "Port",
-                       "Status",
-                       "Leader count",
-                       "Leader distribution",
-                       "Partition distribution"});
-            for (const auto &host : value) {
-                nebula::Row r({host.get_hostAddr().host,
-                               host.get_hostAddr().port,
-                               meta::cpp2::_HostStatus_VALUES_TO_NAMES.at(host.get_status())});
-                int64_t leaderCount = 0;
-                for (const auto& spaceEntry : host.get_leader_parts()) {
-                    leaderCount += spaceEntry.second.size();
-                }
-                std::stringstream leaders;
-                std::stringstream parts;
-                std::size_t i = 0;
-                for (const auto &l : host.get_leader_parts()) {
-                    leaders << l.first << ":" << l.second.size();
-                    if (i < host.get_leader_parts().size() - 1) {
-                        leaders << kPartitionDelimeter;
-                    }
-                    ++i;
-                }
-                if (host.get_leader_parts().empty()) {
-                    leaders << kNoPartition;
-                }
-                i = 0;
-                for (const auto &p : host.get_all_parts()) {
-                    parts << p.first << ":" << p.second.size();
-                    if (i < host.get_all_parts().size() - 1) {
-                        parts << kPartitionDelimeter;
-                    }
-                    ++i;
-                }
-                if (host.get_all_parts().empty()) {
-                    parts << kNoPartition;
-                }
-                r.emplace_back(leaderCount);
-                r.emplace_back(leaders.str());
-                r.emplace_back(parts.str());
-                v.emplace_back(std::move(r));
-            }  // row loop
-            return finish(std::move(v));
+            if (type == meta::cpp2::ListHostType::ALLOC) {
+                return finish(makeTranditionalResult(value));
+            }
+            return finish(makeGitInfoResult(value));
         });
 }
 
-}  // namespace graph
-}  // namespace nebula
+}   // namespace graph
+}   // namespace nebula
diff --git a/src/parser/AdminSentences.h b/src/parser/AdminSentences.h
index 6bd545f6..4686df0a 100644
--- a/src/parser/AdminSentences.h
+++ b/src/parser/AdminSentences.h
@@ -20,7 +20,19 @@ public:
     ShowHostsSentence() {
         kind_ = Kind::kShowHosts;
     }
+
+    explicit ShowHostsSentence(meta::cpp2::ListHostType type) : type_(type) {
+        kind_ = Kind::kShowHosts;
+    }
+
     std::string toString() const override;
+
+    meta::cpp2::ListHostType getType() const {
+        return type_;
+    }
+
+private:
+    meta::cpp2::ListHostType type_;
 };
 
 class ShowSpacesSentence : public Sentence {
diff --git a/src/parser/parser.yy b/src/parser/parser.yy
index e2cae50d..f8e103ba 100644
--- a/src/parser/parser.yy
+++ b/src/parser/parser.yy
@@ -97,6 +97,7 @@ static constexpr size_t MAX_ABS_INTEGER = 9223372036854775808ULL;
     nebula::OrderFactor                    *order_factor;
     nebula::OrderFactors                   *order_factors;
     nebula::meta::cpp2::ConfigModule        config_module;
+    nebula::meta::cpp2::ListHostType       list_host_type;
     nebula::ConfigRowItem                  *config_row_item;
     nebula::EdgeKey                        *edge_key;
     nebula::EdgeKeys                       *edge_keys;
@@ -132,7 +133,7 @@ static constexpr size_t MAX_ABS_INTEGER = 9223372036854775808ULL;
 
 /* destructors */
 %destructor {} <sentences>
-%destructor {} <boolval> <intval> <doubleval> <type> <config_module> <integer_list>
+%destructor {} <boolval> <intval> <doubleval> <type> <config_module> <integer_list> <list_host_type>
 %destructor { delete $$; } <*>
 
 /* keywords */
@@ -242,6 +243,7 @@ static constexpr size_t MAX_ABS_INTEGER = 9223372036854775808ULL;
 %type <order_factor> order_factor
 %type <order_factors> order_factors
 %type <config_module> config_module_enum
+%type <list_host_type> list_host_type
 %type <config_row_item> show_config_item get_config_item set_config_item
 %type <edge_key> edge_key
 %type <edge_keys> edge_keys
@@ -2523,7 +2525,10 @@ job_concurrency
 
 show_sentence
     : KW_SHOW KW_HOSTS {
-        $$ = new ShowHostsSentence();
+        $$ = new ShowHostsSentence(meta::cpp2::ListHostType::ALLOC);
+    }
+    | KW_SHOW KW_HOSTS list_host_type {
+        $$ = new ShowHostsSentence($3);
     }
     | KW_SHOW KW_SPACES {
         $$ = new ShowSpacesSentence();
@@ -2604,6 +2609,12 @@ show_sentence
     }
     ;
 
+list_host_type
+    : KW_GRAPH      { $$ = meta::cpp2::ListHostType::GRAPH; }
+    | KW_META       { $$ = meta::cpp2::ListHostType::META; }
+    | KW_STORAGE    { $$ = meta::cpp2::ListHostType::STORAGE; }
+    ;
+
 config_module_enum
     : KW_GRAPH      { $$ = meta::cpp2::ConfigModule::GRAPH; }
     | KW_META       { $$ = meta::cpp2::ConfigModule::META; }
diff --git a/src/parser/test/ParserTest.cpp b/src/parser/test/ParserTest.cpp
index d3251913..5cc918c5 100644
--- a/src/parser/test/ParserTest.cpp
+++ b/src/parser/test/ParserTest.cpp
@@ -1370,6 +1370,24 @@ TEST(Parser, AdminOperation) {
         auto result = parser.parse(query);
         ASSERT_TRUE(result.ok()) << result.status();
     }
+    {
+        GQLParser parser;
+        std::string query = "SHOW HOSTS graph";
+        auto result = parser.parse(query);
+        ASSERT_TRUE(result.ok()) << result.status();
+    }
+    {
+        GQLParser parser;
+        std::string query = "SHOW HOSTS meta";
+        auto result = parser.parse(query);
+        ASSERT_TRUE(result.ok()) << result.status();
+    }
+    {
+        GQLParser parser;
+        std::string query = "SHOW HOSTS storage";
+        auto result = parser.parse(query);
+        ASSERT_TRUE(result.ok()) << result.status();
+    }
     {
         GQLParser parser;
         std::string query = "SHOW SPACES";
diff --git a/src/planner/Admin.h b/src/planner/Admin.h
index 6ec6396a..36bdfcd9 100644
--- a/src/planner/Admin.h
+++ b/src/planner/Admin.h
@@ -60,13 +60,18 @@ private:
 class ShowHosts final : public SingleDependencyNode {
     // TODO(shylock) meta/storage/graph enumerate
 public:
-    static ShowHosts* make(QueryContext* qctx, PlanNode* dep) {
-        return qctx->objPool()->add(new ShowHosts(qctx, dep));
+    static ShowHosts* make(QueryContext* qctx, PlanNode* dep, meta::cpp2::ListHostType type) {
+        return qctx->objPool()->add(new ShowHosts(qctx, dep, type));
+    }
+
+    meta::cpp2::ListHostType getType() const {
+        return type_;
     }
 
 private:
-    ShowHosts(QueryContext* qctx, PlanNode* dep)
-        : SingleDependencyNode(qctx, Kind::kShowHosts, dep) {}
+    ShowHosts(QueryContext* qctx, PlanNode* dep, meta::cpp2::ListHostType type)
+        : SingleDependencyNode(qctx, Kind::kShowHosts, dep), type_(type) {}
+    meta::cpp2::ListHostType type_;
 };
 
 class CreateSpace final : public SingleInputNode {
diff --git a/src/service/QueryEngine.cpp b/src/service/QueryEngine.cpp
index 33120379..a99b8ef9 100644
--- a/src/service/QueryEngine.cpp
+++ b/src/service/QueryEngine.cpp
@@ -11,6 +11,7 @@
 #include "optimizer/OptRule.h"
 #include "planner/PlannersRegister.h"
 #include "service/QueryInstance.h"
+#include "service/GraphFlags.h"
 
 DECLARE_bool(local_config);
 DECLARE_bool(enable_optimizer);
@@ -28,9 +29,12 @@ Status QueryEngine::init(std::shared_ptr<folly::IOThreadPoolExecutor> ioExecutor
     meta::MetaClientOptions options;
     options.serviceName_ = "graph";
     options.skipConfig_ = FLAGS_local_config;
-    metaClient_ = std::make_unique<meta::MetaClient>(ioExecutor,
-                                                     std::move(addrs.value()),
-                                                     options);
+    options.role_ = meta::cpp2::HostRole::GRAPH;
+    std::string localIP = network::NetworkUtils::getIPv4FromDevice(FLAGS_listen_netdev).value();
+    options.localHost_ = HostAddr{localIP, FLAGS_port};
+    options.gitInfoSHA_ = NEBULA_STRINGIFY(GIT_INFO_SHA);
+    metaClient_ =
+        std::make_unique<meta::MetaClient>(ioExecutor, std::move(addrs.value()), options);
     // load data try 3 time
     bool loadDataOk = metaClient_->waitForMetadReady(3);
     if (!loadDataOk) {
diff --git a/src/validator/AdminValidator.cpp b/src/validator/AdminValidator.cpp
index 25ca7e5e..58dcc73c 100644
--- a/src/validator/AdminValidator.cpp
+++ b/src/validator/AdminValidator.cpp
@@ -268,7 +268,8 @@ Status ShowHostsValidator::validateImpl() {
 }
 
 Status ShowHostsValidator::toPlan() {
-    auto *showHosts = ShowHosts::make(qctx_, nullptr);
+    auto sentence = static_cast<ShowHostsSentence *>(sentence_);
+    auto *showHosts = ShowHosts::make(qctx_, nullptr, sentence->getType());
     root_ = showHosts;
     tail_ = root_;
     return Status::OK();
-- 
GitLab