Browse Source

Add _cat/plugins endpoint

If we want to have a full picture of versions running in a cluster, we need to add a `_cat/plugins` endpoint.

Response could look like:

```sh
% curl es2:9200/_cat/plugins?v
node component                        version   type url                                   desc
es1  mapper-attachments               1.7.0       j                                        Adds the attachment type allowing to parse difference attachment formats
es1  lang-javascript                  1.4.0       j                                        JavaScript plugin allowing to add javascript scripting support
es1  analysis-smartcn                 1.9.0       j                                        Smart Chinese analysis support
es1  marvel                           1.1.0      j/s http://localhost:9200/_plugins/marvel Elasticsearch Management & Monitoring
es1  kopf                             0.5.3       s  http://localhost:9200/_plugins/kopf   kopf - simple web administration tool for ElasticSearch
es2  mapper-attachments               2.0.0.RC1   j                                        Adds the attachment type allowing to parse difference attachment formats
es2  lang-javascript                  2.0.0.RC1   j                                        JavaScript plugin allowing to add javascript scripting support
es2  analysis-smartcn                 2.0.0.RC1   j                                        Smart Chinese analysis support
```

Closes #4824.
David Pilato 11 years ago
parent
commit
f54e9246c1

+ 3 - 0
docs/reference/cat.asciidoc

@@ -115,3 +115,6 @@ include::cat/recovery.asciidoc[]
 include::cat/thread_pool.asciidoc[]
 
 include::cat/shards.asciidoc[]
+
+include::cat/plugins.asciidoc[]
+

+ 20 - 0
docs/reference/cat/plugins.asciidoc

@@ -0,0 +1,20 @@
+[[cat-plugins]]
+== Plugins
+
+The `plugins` command provides a view per node of running plugins. This information *spans nodes*.
+
+[source,shell]
+------------------------------------------------------------------------------
+% curl 'localhost:9200/_cat/plugins?v'
+name    component       version        type isolation url
+Abraxas cloud-azure     2.1.0-SNAPSHOT j    x
+Abraxas lang-groovy     2.0.0          j    x
+Abraxas lang-javascript 2.0.0-SNAPSHOT j    x
+Abraxas marvel          NA             j/s  x         /_plugin/marvel/
+Abraxas lang-python     2.0.0-SNAPSHOT j    x
+Abraxas inquisitor      NA             s              /_plugin/inquisitor/
+Abraxas kopf            0.5.2          s              /_plugin/kopf/
+Abraxas segmentspy      NA             s              /_plugin/segmentspy/
+-------------------------------------------------------------------------------
+
+We can tell quickly how many plugins per node we have and which versions.

+ 35 - 0
rest-api-spec/api/cat.plugins.json

@@ -0,0 +1,35 @@
+{
+  "cat.plugins": {
+    "documentation": "http://www.elasticsearch.org/guide/en/elasticsearch/reference/master/cat-plugins.html",
+    "methods": ["GET"],
+    "url": {
+      "path": "/_cat/plugins",
+      "paths": ["/_cat/plugins"],
+      "params": {
+        "local": {
+          "type" : "boolean",
+          "description" : "Return local information, do not retrieve the state from master node (default: false)"
+        },
+        "master_timeout": {
+          "type" : "time",
+          "description" : "Explicit operation timeout for connection to master node"
+        },
+        "h": {
+            "type": "list",
+            "description" : "Comma-separated list of column names to display"
+        },
+        "help": {
+          "type": "boolean",
+          "description": "Return help information",
+          "default": false
+        },
+        "v": {
+          "type": "boolean",
+          "description": "Verbose mode. Display column headers",
+          "default": false
+        }
+      }
+    },
+    "body": null
+  }
+}

+ 1 - 0
src/main/java/org/elasticsearch/rest/action/RestActionModule.java

@@ -224,6 +224,7 @@ public class RestActionModule extends AbstractModule {
         catActionMultibinder.addBinding().to(org.elasticsearch.rest.action.cat.RestPendingClusterTasksAction.class).asEagerSingleton();
         catActionMultibinder.addBinding().to(RestAliasAction.class).asEagerSingleton();
         catActionMultibinder.addBinding().to(RestThreadPoolAction.class).asEagerSingleton();
+        catActionMultibinder.addBinding().to(RestPluginsAction.class).asEagerSingleton();
         // no abstract cat action
         bind(RestCatAction.class).asEagerSingleton();
     }

+ 132 - 0
src/main/java/org/elasticsearch/rest/action/cat/RestPluginsAction.java

@@ -0,0 +1,132 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch 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.
+ */
+
+package org.elasticsearch.rest.action.cat;
+
+import org.elasticsearch.action.admin.cluster.node.info.NodeInfo;
+import org.elasticsearch.action.admin.cluster.node.info.NodesInfoRequest;
+import org.elasticsearch.action.admin.cluster.node.info.NodesInfoResponse;
+import org.elasticsearch.action.admin.cluster.node.info.PluginInfo;
+import org.elasticsearch.action.admin.cluster.state.ClusterStateRequest;
+import org.elasticsearch.action.admin.cluster.state.ClusterStateResponse;
+import org.elasticsearch.client.Client;
+import org.elasticsearch.cluster.node.DiscoveryNode;
+import org.elasticsearch.cluster.node.DiscoveryNodes;
+import org.elasticsearch.common.Table;
+import org.elasticsearch.common.inject.Inject;
+import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.rest.AbstractRestResponseActionListener;
+import org.elasticsearch.rest.RestChannel;
+import org.elasticsearch.rest.RestController;
+import org.elasticsearch.rest.RestRequest;
+import org.elasticsearch.rest.action.support.RestTable;
+
+import static org.elasticsearch.rest.RestRequest.Method.GET;
+
+public class RestPluginsAction extends AbstractCatAction {
+
+    @Inject
+    public RestPluginsAction(Settings settings, Client client, RestController controller) {
+        super(settings, client);
+        controller.registerHandler(GET, "/_cat/plugins", this);
+    }
+
+    @Override
+    void documentation(StringBuilder sb) {
+        sb.append("/_cat/plugins\n");
+    }
+
+    @Override
+    public void doRequest(final RestRequest request, final RestChannel channel) {
+        final ClusterStateRequest clusterStateRequest = new ClusterStateRequest();
+        clusterStateRequest.clear().nodes(true);
+        clusterStateRequest.local(request.paramAsBoolean("local", clusterStateRequest.local()));
+        clusterStateRequest.masterNodeTimeout(request.paramAsTime("master_timeout", clusterStateRequest.masterNodeTimeout()));
+
+        client.admin().cluster().state(clusterStateRequest, new AbstractRestResponseActionListener<ClusterStateResponse>(request, channel, logger) {
+            @Override
+            public void onResponse(final ClusterStateResponse clusterStateResponse) {
+                NodesInfoRequest nodesInfoRequest = new NodesInfoRequest();
+                nodesInfoRequest.clear().plugins(true);
+                client.admin().cluster().nodesInfo(nodesInfoRequest, new AbstractRestResponseActionListener<NodesInfoResponse>(request, channel, logger) {
+                    @Override
+                    public void onResponse(final NodesInfoResponse nodesInfoResponse) {
+                        try {
+                            channel.sendResponse(RestTable.buildResponse(buildTable(request, clusterStateResponse, nodesInfoResponse), request, channel));
+                        } catch (Throwable e) {
+                            onFailure(e);
+                        }
+                    }
+                });
+            }
+        });
+    }
+
+    @Override
+    Table getTableWithHeader(final RestRequest request) {
+        Table table = new Table();
+        table.startHeaders();
+        table.addCell("name", "alias:n;desc:node name");
+        table.addCell("component", "alias:c;desc:component");
+        table.addCell("version", "alias:v;desc:component version");
+        table.addCell("type", "alias:t;desc:type (j for JVM, s for Site)");
+        table.addCell("isolation", "alias:i;desc:isolation");
+        table.addCell("url", "alias:u;desc:url for site plugins");
+        table.addCell("description", "alias:d;default:false;desc:plugin details");
+        table.endHeaders();
+        return table;
+    }
+
+    private Table buildTable(RestRequest req, ClusterStateResponse state, NodesInfoResponse nodesInfo) {
+        DiscoveryNodes nodes = state.getState().nodes();
+        Table table = getTableWithHeader(req);
+
+        for (DiscoveryNode node : nodes) {
+            NodeInfo info = nodesInfo.getNodesMap().get(node.id());
+
+            for (PluginInfo pluginInfo : info.getPlugins().getInfos()) {
+                table.startRow();
+                table.addCell(node.name());
+                table.addCell(pluginInfo.getName());
+                table.addCell(pluginInfo.getVersion());
+                String type;
+                if (pluginInfo.isSite()) {
+                    if (pluginInfo.isJvm()) {
+                        type = "j/s";
+                    } else {
+                        type = "s";
+                    }
+                } else {
+                    if (pluginInfo.isJvm()) {
+                        type = "j";
+                    } else {
+                        type = "";
+                    }
+                }
+                table.addCell(type);
+                table.addCell(pluginInfo.isIsolation() ? "x" : "");
+                table.addCell(pluginInfo.getUrl());
+                table.addCell(pluginInfo.getDescription());
+                table.endRow();
+            }
+        }
+
+        return table;
+    }
+}