From c73c35c8af2b703b5fe4aff30c278ebd558a36d4 Mon Sep 17 00:00:00 2001
From: Tianli Feng <ftianli@amazon.com>
Date: Tue, 8 Mar 2022 16:36:18 -0800
Subject: [PATCH] Add cluster_manager_node into cluster state metric

Signed-off-by: Tianli Feng <ftianli@amazon.com>
---
 .../rest-api-spec/api/cluster.reroute.json        |  1 +
 .../rest-api-spec/api/cluster.state.json          |  1 +
 .../test/cluster.reroute/10_basic.yml             | 15 +++++++++++++++
 .../cluster.reroute/20_response_filtering.yml     | 13 +++++++++++++
 .../rest-api-spec/test/cluster.state/10_basic.yml | 15 +++++++++++++++
 .../test/cluster.state/20_filtering.yml           | 13 +++++++++++++
 .../java/org/opensearch/cluster/ClusterState.java |  6 ++++++
 .../admin/cluster/RestClusterStateAction.java     |  6 +++++-
 .../org/opensearch/cluster/ClusterStateTests.java |  4 ++++
 9 files changed, 73 insertions(+), 1 deletion(-)

diff --git a/rest-api-spec/src/main/resources/rest-api-spec/api/cluster.reroute.json b/rest-api-spec/src/main/resources/rest-api-spec/api/cluster.reroute.json
index b0e8054fc9e53..bcf2704110664 100644
--- a/rest-api-spec/src/main/resources/rest-api-spec/api/cluster.reroute.json
+++ b/rest-api-spec/src/main/resources/rest-api-spec/api/cluster.reroute.json
@@ -37,6 +37,7 @@
           "nodes",
           "routing_table",
           "master_node",
+          "cluster_manager_node",
           "version"
         ],
         "description":"Limit the information returned to the specified metrics. Defaults to all but metadata"
diff --git a/rest-api-spec/src/main/resources/rest-api-spec/api/cluster.state.json b/rest-api-spec/src/main/resources/rest-api-spec/api/cluster.state.json
index 017705082d189..c17e5b073e361 100644
--- a/rest-api-spec/src/main/resources/rest-api-spec/api/cluster.state.json
+++ b/rest-api-spec/src/main/resources/rest-api-spec/api/cluster.state.json
@@ -55,6 +55,7 @@
                 "routing_table",
                 "routing_nodes",
                 "master_node",
+                "cluster_manager_node",
                 "version"
               ],
               "description":"Limit the information returned to the specified metrics"
diff --git a/rest-api-spec/src/main/resources/rest-api-spec/test/cluster.reroute/10_basic.yml b/rest-api-spec/src/main/resources/rest-api-spec/test/cluster.reroute/10_basic.yml
index 771f647a952c7..1b45e19c24acf 100644
--- a/rest-api-spec/src/main/resources/rest-api-spec/test/cluster.reroute/10_basic.yml
+++ b/rest-api-spec/src/main/resources/rest-api-spec/test/cluster.reroute/10_basic.yml
@@ -2,3 +2,18 @@
 "Basic sanity check":
   - do:
       cluster.reroute: {}
+
+---
+"Cluster reroute returns cluster_manager_node":
+  - skip:
+      version: " - 1.4.99"
+      reason: "The metric cluster_manager_node is added to cluster state in version 2.0.0"
+
+  - do:
+      cluster.reroute: {}
+
+  - set:
+      state.cluster_manager_node: node_id
+
+  - match: {state.master_node: $node_id}
+  - match: {state.cluster_manager_node: $node_id}
diff --git a/rest-api-spec/src/main/resources/rest-api-spec/test/cluster.reroute/20_response_filtering.yml b/rest-api-spec/src/main/resources/rest-api-spec/test/cluster.reroute/20_response_filtering.yml
index 437b78e6119a7..c05d1db51142e 100644
--- a/rest-api-spec/src/main/resources/rest-api-spec/test/cluster.reroute/20_response_filtering.yml
+++ b/rest-api-spec/src/main/resources/rest-api-spec/test/cluster.reroute/20_response_filtering.yml
@@ -3,6 +3,7 @@
   - do:
       cluster.reroute: {}
   - is_false: state.metadata
+
 ---
 "return metadata if requested":
   - do:
@@ -12,3 +13,15 @@
   - is_true: state.metadata
   - is_false: state.nodes
 
+---
+"Filter the cluster reroute by cluster_manager_node only should work":
+  - skip:
+      version: " - 1.4.99"
+      reason: "The metric cluster_manager_node is added to cluster state in version 2.0.0"
+
+  - do:
+      cluster.reroute:
+        metric: [ cluster_manager_node ]
+
+  - is_true: state.cluster_manager_node
+  - is_false: state.master_node
diff --git a/rest-api-spec/src/main/resources/rest-api-spec/test/cluster.state/10_basic.yml b/rest-api-spec/src/main/resources/rest-api-spec/test/cluster.state/10_basic.yml
index b443e322f80f6..fa973454cfba5 100644
--- a/rest-api-spec/src/main/resources/rest-api-spec/test/cluster.state/10_basic.yml
+++ b/rest-api-spec/src/main/resources/rest-api-spec/test/cluster.state/10_basic.yml
@@ -17,3 +17,18 @@
 
   - is_true: cluster_uuid
   - is_true: master_node
+    
+---
+"Get cluster state returns cluster_manager_node":
+  - skip:
+      version: " - 1.4.99"
+      reason: "The metric cluster_manager_node is added to cluster state in version 2.0.0"
+      
+  - do:
+      cluster.state: {}
+      
+  - set:
+      cluster_manager_node: node_id
+      
+  - match: {master_node: $node_id}
+  - match: {cluster_manager_node: $node_id}
diff --git a/rest-api-spec/src/main/resources/rest-api-spec/test/cluster.state/20_filtering.yml b/rest-api-spec/src/main/resources/rest-api-spec/test/cluster.state/20_filtering.yml
index 88da42ee876be..5c0dd2bc04c23 100644
--- a/rest-api-spec/src/main/resources/rest-api-spec/test/cluster.state/20_filtering.yml
+++ b/rest-api-spec/src/main/resources/rest-api-spec/test/cluster.state/20_filtering.yml
@@ -180,3 +180,16 @@ setup:
 
   - match: { cluster_uuid: $cluster_uuid }
   - is_true: routing_table
+
+---
+"Filter the cluster state by cluster_manager_node only should work":
+  - skip:
+      version: " - 1.4.99"
+      reason: "The metric cluster_manager_node is added to cluster state in version 2.0.0"
+
+  - do:
+      cluster.state:
+        metric: [ cluster_manager_node ]
+
+  - is_true: cluster_manager_node
+  - is_false: master_node
diff --git a/server/src/main/java/org/opensearch/cluster/ClusterState.java b/server/src/main/java/org/opensearch/cluster/ClusterState.java
index 6e17be690dd9d..246889115fdbd 100644
--- a/server/src/main/java/org/opensearch/cluster/ClusterState.java
+++ b/server/src/main/java/org/opensearch/cluster/ClusterState.java
@@ -403,6 +403,7 @@ public boolean supersedes(ClusterState other) {
     public enum Metric {
         VERSION("version"),
         MASTER_NODE("master_node"),
+        CLUSTER_MANAGER_NODE("cluster_manager_node"),
         BLOCKS("blocks"),
         NODES("nodes"),
         METADATA("metadata"),
@@ -467,6 +468,11 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
             builder.field("master_node", nodes().getMasterNodeId());
         }
 
+        // Value of the field is identical with the above, and aims to replace the above field.
+        if (metrics.contains(Metric.CLUSTER_MANAGER_NODE)) {
+            builder.field("cluster_manager_node", nodes().getMasterNodeId());
+        }
+
         if (metrics.contains(Metric.BLOCKS)) {
             builder.startObject("blocks");
 
diff --git a/server/src/main/java/org/opensearch/rest/action/admin/cluster/RestClusterStateAction.java b/server/src/main/java/org/opensearch/rest/action/admin/cluster/RestClusterStateAction.java
index 5056e29d47dce..892bcd4f342e9 100644
--- a/server/src/main/java/org/opensearch/rest/action/admin/cluster/RestClusterStateAction.java
+++ b/server/src/main/java/org/opensearch/rest/action/admin/cluster/RestClusterStateAction.java
@@ -112,7 +112,11 @@ public RestChannelConsumer prepareRequest(final RestRequest request, final NodeC
         if (request.hasParam("metric")) {
             EnumSet<ClusterState.Metric> metrics = ClusterState.Metric.parseString(request.param("metric"), true);
             // do not ask for what we do not need.
-            clusterStateRequest.nodes(metrics.contains(ClusterState.Metric.NODES) || metrics.contains(ClusterState.Metric.MASTER_NODE));
+            clusterStateRequest.nodes(
+                metrics.contains(ClusterState.Metric.NODES)
+                    || metrics.contains(ClusterState.Metric.MASTER_NODE)
+                    || metrics.contains(ClusterState.Metric.CLUSTER_MANAGER_NODE)
+            );
             /*
              * there is no distinction in Java api between routing_table and routing_nodes, it's the same info set over the wire, one single
              * flag to ask for it
diff --git a/server/src/test/java/org/opensearch/cluster/ClusterStateTests.java b/server/src/test/java/org/opensearch/cluster/ClusterStateTests.java
index 03db6b22bc8bd..b343467e5e96e 100644
--- a/server/src/test/java/org/opensearch/cluster/ClusterStateTests.java
+++ b/server/src/test/java/org/opensearch/cluster/ClusterStateTests.java
@@ -147,6 +147,7 @@ public void testToXContent() throws IOException {
                 + "  \"version\" : 0,\n"
                 + "  \"state_uuid\" : \"stateUUID\",\n"
                 + "  \"master_node\" : \"masterNodeId\",\n"
+                + "  \"cluster_manager_node\" : \"masterNodeId\",\n"
                 + "  \"blocks\" : {\n"
                 + "    \"global\" : {\n"
                 + "      \"1\" : {\n"
@@ -354,6 +355,7 @@ public void testToXContent_FlatSettingTrue_ReduceMappingFalse() throws IOExcepti
                 + "  \"version\" : 0,\n"
                 + "  \"state_uuid\" : \"stateUUID\",\n"
                 + "  \"master_node\" : \"masterNodeId\",\n"
+                + "  \"cluster_manager_node\" : \"masterNodeId\",\n"
                 + "  \"blocks\" : {\n"
                 + "    \"global\" : {\n"
                 + "      \"1\" : {\n"
@@ -554,6 +556,7 @@ public void testToXContent_FlatSettingFalse_ReduceMappingTrue() throws IOExcepti
                 + "  \"version\" : 0,\n"
                 + "  \"state_uuid\" : \"stateUUID\",\n"
                 + "  \"master_node\" : \"masterNodeId\",\n"
+                + "  \"cluster_manager_node\" : \"masterNodeId\",\n"
                 + "  \"blocks\" : {\n"
                 + "    \"global\" : {\n"
                 + "      \"1\" : {\n"
@@ -780,6 +783,7 @@ public void testToXContentSameTypeName() throws IOException {
                 + "  \"version\" : 0,\n"
                 + "  \"state_uuid\" : \"stateUUID\",\n"
                 + "  \"master_node\" : null,\n"
+                + "  \"cluster_manager_node\" : null,\n"
                 + "  \"blocks\" : { },\n"
                 + "  \"nodes\" : { },\n"
                 + "  \"metadata\" : {\n"