Elasticsearchのプラグインを作成する(2)

Elasticsearchのプラグインを作成する第２弾。
前回はcatプラグインをベースに単純に文字列を表示するものでしたが、今回はもう少しやる事を増やして、Elasticsearchの内部の情報を表示させるようにしようと思います。

コードは[こちら](https://github.com/nakaearth/elasticsearch-sample-plugin)になります。

では簡単に説明を

# 環境
前回と変わらずで

- Java8
- Maven3
- Elasticsearch6.5.4

# 実装
pluginで最初に呼ばれるクラスは変わりありません。

```ExamplePlugin.java
  1 package org.elasticsearch.plugin.example;
  2
  3 import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
  4 import org.elasticsearch.cluster.node.DiscoveryNodes;
  5 import org.elasticsearch.common.settings.ClusterSettings;
  6 import org.elasticsearch.common.settings.IndexScopedSettings;
  7 import org.elasticsearch.common.settings.Settings;
  8 import org.elasticsearch.common.settings.SettingsFilter;
  9 import org.elasticsearch.plugins.ActionPlugin;
 10 import org.elasticsearch.plugins.Plugin;
 11 import org.elasticsearch.rest.RestController;
 12 import org.elasticsearch.rest.RestHandler;
 13
 14 import java.util.List;
 15 import java.util.function.Supplier;
 16
 17 import static java.util.Collections.singletonList;
 18
 19 public class ExamplePlugin extends Plugin implements ActionPlugin {
 20     @Override
 21     public List<RestHandler> getRestHandlers(final Settings settings,
 22                                              final RestController restController,
 23                                              final ClusterSettings clusterSettings,
 24                                              final IndexScopedSettings indexScopedSettings,
 25                                              final SettingsFilter settingsFilter,
 26                                              final IndexNameExpressionResolver indexNameExpressionResolver,
 27                                              final Supplier<DiscoveryNodes> nodesInCluster) {
 28
 29         return singletonList(new ExampleDogAction(settings, restController));
 30     }
 31 }
```

実際に処理を行なっているのはこの<code>ExampleDogActionクラス</code>です。

```
  1 package org.elasticsearch.plugin.example;
  2
  3 import org.elasticsearch.action.admin.cluster.node.info.NodeInfo;
  4 import org.elasticsearch.action.admin.cluster.node.info.NodesInfoRequest;
  5 import org.elasticsearch.action.admin.cluster.node.info.NodesInfoResponse;
  6 import org.elasticsearch.action.admin.cluster.state.ClusterStateRequest;
  7 import org.elasticsearch.action.admin.cluster.state.ClusterStateResponse;
  8 import org.elasticsearch.client.node.NodeClient;
  9 import org.elasticsearch.cluster.node.DiscoveryNode;
 10 import org.elasticsearch.cluster.node.DiscoveryNodes;
 11 import org.elasticsearch.client.node.NodeClient;
 12 import org.elasticsearch.common.inject.Inject;
 13 import org.elasticsearch.common.Table;
 14 import org.elasticsearch.common.settings.Settings;
 15 import org.elasticsearch.plugins.PluginInfo;
 16 import org.elasticsearch.http.HttpInfo;
 17 import org.elasticsearch.monitor.os.OsInfo;
 18 import org.elasticsearch.rest.BaseRestHandler;
 19 import org.elasticsearch.rest.BytesRestResponse;
 20 import org.elasticsearch.rest.RestController;
 21 import org.elasticsearch.rest.RestRequest;
 22 import org.elasticsearch.rest.RestStatus;
 23 import org.elasticsearch.rest.RestResponse;
 24 import org.elasticsearch.rest.action.RestActionListener;
 25 import org.elasticsearch.rest.action.RestResponseListener;
 26 import org.elasticsearch.rest.action.cat.RestTable;
 27
 28 import static org.elasticsearch.rest.RestRequest.Method.GET;
 29 import static org.elasticsearch.rest.RestRequest.Method.POST;
 30
 31 import java.io.IOException;
 32 import java.util.List;
 33
 34 /**
 35  * Example of adding a cat action with a plugin.
 36  */
 37 public class ExampleDogAction extends BaseRestHandler {
 38     @Inject
 39     ExampleDogAction(final Settings settings, final RestController controller) {
 40         super(settings);
 41         controller.registerHandler(GET, "/_dog", this);
 42     }
 43
 44     @Override
 45     public String getName() {
 46         return "rest_handler_dog_example";
 47     }
 48
 49         @Override
 50     public RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException {
 51         // Clusterの情報を引っ張り出す
 52         final ClusterStateRequest clusterStateRequest = new ClusterStateRequest();
 53         clusterStateRequest.clear().nodes(true);
 54         clusterStateRequest.local(request.paramAsBoolean("local", clusterStateRequest.local()));
 55         clusterStateRequest.masterNodeTimeout(request.paramAsTime("master_timeout", clusterStateRequest.masterNodeTimeout()));
 56
 57         return channel -> client.admin().cluster().state(clusterStateRequest, new RestActionListener<ClusterStateResponse>(channel) {
 58             @Override
 59             public void processResponse(final ClusterStateResponse clusterStateResponse) throws Exception {
 60                 NodesInfoRequest nodesInfoRequest = new NodesInfoRequest();
 61                 nodesInfoRequest.clear().plugins(true);
 62                 client.admin().cluster().nodesInfo(nodesInfoRequest, new RestResponseListener<NodesInfoResponse>(channel) {
 63                     @Override
 64                     public RestResponse buildResponse(final NodesInfoResponse nodesInfoResponse) throws Exception {
 65                         return RestTable.buildResponse(buildTable(request, clusterStateResponse, nodesInfoResponse), channel);
 66                     }
 67                 });
 68             }
 69         });
 70     }
 71
 72     protected Table getTableWithHeader(final RestRequest request) {
 73         Table table = new Table();
 74         table.startHeaders();
 75         table.addCell("id", "default:false;desc:unique node id");
 76         table.addCell("name", "alias:n;desc:node name");
 77         table.addCell("hostName", "alias:n;desc:node host name");
 78         table.addCell("component", "alias:c;desc:component");
 79         table.addCell("version", "alias:v;desc:component version");
 80         table.addCell("description", "alias:d;default:false;desc:plugin details");
 81         table.endHeaders();
 82         return table;
 83     }
 84
 85
 86     private Table buildTable(RestRequest req, ClusterStateResponse state, NodesInfoResponse nodesInfo) {
 87         DiscoveryNodes nodes = state.getState().nodes();
 88         Table table = getTableWithHeader(req);
 89
 90         for (DiscoveryNode node : nodes) {
 91             NodeInfo info = nodesInfo.getNodesMap().get(node.getId());
 92
 93             for (PluginInfo pluginInfo : info.getPlugins().getPluginInfos()) {
 94                 table.startRow();
 95                 table.addCell(node.getId());
 96                 table.addCell(node.getName());
 97                 table.addCell(node.getHostName());
 98                 table.addCell(pluginInfo.getName());
 99                 table.addCell(pluginInfo.getVersion());
100                 table.addCell(pluginInfo.getDescription());
101                 table.endRow();
102             }
103         }
104
105         return table;
106     }
107 }
```

86行目あたりをみてください。この<code>buildTable</code>メソッドの中でNodeの情報を取得し、インストールされているpluginの情報も表示するように書いてます。