Merge pull request #12534 from metadave/feature/cat_nodeattrs

Add _cat/nodeattrs API
This commit is contained in:
Dave Parfitt 2015-07-29 17:01:22 -04:00
commit 2d2f21e760
6 changed files with 269 additions and 0 deletions

View File

@ -250,6 +250,7 @@ public class RestActionModule extends AbstractModule {
catActionMultibinder.addBinding().to(RestThreadPoolAction.class).asEagerSingleton();
catActionMultibinder.addBinding().to(RestPluginsAction.class).asEagerSingleton();
catActionMultibinder.addBinding().to(RestFielddataAction.class).asEagerSingleton();
catActionMultibinder.addBinding().to(RestNodeAttrsAction.class).asEagerSingleton();
// no abstract cat action
bind(RestCatAction.class).asEagerSingleton();
}

View File

@ -0,0 +1,131 @@
/*
* 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 com.google.common.collect.ImmutableMap;
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.stats.NodesStatsRequest;
import org.elasticsearch.action.admin.cluster.node.stats.NodesStatsResponse;
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.Strings;
import org.elasticsearch.common.Table;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.rest.*;
import org.elasticsearch.rest.action.support.RestActionListener;
import org.elasticsearch.rest.action.support.RestResponseListener;
import org.elasticsearch.rest.action.support.RestTable;
import static org.elasticsearch.rest.RestRequest.Method.GET;
public class RestNodeAttrsAction extends AbstractCatAction {
@Inject
public RestNodeAttrsAction(Settings settings, RestController controller, Client client) {
super(settings, controller, client);
controller.registerHandler(GET, "/_cat/nodeattrs", this);
}
@Override
void documentation(StringBuilder sb) {
sb.append("/_cat/nodeattrs\n");
}
@Override
public void doRequest(final RestRequest request, final RestChannel channel, final Client client) {
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 RestActionListener<ClusterStateResponse>(channel) {
@Override
public void processResponse(final ClusterStateResponse clusterStateResponse) {
NodesInfoRequest nodesInfoRequest = new NodesInfoRequest();
nodesInfoRequest.clear().jvm(false).os(false).process(true);
client.admin().cluster().nodesInfo(nodesInfoRequest, new RestActionListener<NodesInfoResponse>(channel) {
@Override
public void processResponse(final NodesInfoResponse nodesInfoResponse) {
NodesStatsRequest nodesStatsRequest = new NodesStatsRequest();
nodesStatsRequest.clear().jvm(false).os(false).fs(false).indices(false).process(false);
client.admin().cluster().nodesStats(nodesStatsRequest, new RestResponseListener<NodesStatsResponse>(channel) {
@Override
public RestResponse buildResponse(NodesStatsResponse nodesStatsResponse) throws Exception {
return RestTable.buildResponse(buildTable(request, clusterStateResponse, nodesInfoResponse, nodesStatsResponse), channel);
}
});
}
});
}
});
}
@Override
Table getTableWithHeader(final RestRequest request) {
Table table = new Table();
table.startHeaders();
table.addCell("node", "default:true;alias:name;desc:node name");
table.addCell("id", "default:false;alias:id,nodeId;desc:unique node id");
table.addCell("pid", "default:false;alias:p;desc:process id");
table.addCell("host", "alias:h;desc:host name");
table.addCell("ip", "alias:i;desc:ip address");
table.addCell("port", "default:false;alias:po;desc:bound transport port");
table.addCell("attr", "default:true;alias:attr.name;desc:attribute description");
table.addCell("value","default:true;alias:attr.value;desc:attribute value");
table.endHeaders();
return table;
}
private Table buildTable(RestRequest req, ClusterStateResponse state, NodesInfoResponse nodesInfo, NodesStatsResponse nodesStats) {
boolean fullId = req.paramAsBoolean("full_id", false);
DiscoveryNodes nodes = state.getState().nodes();
Table table = getTableWithHeader(req);
for (DiscoveryNode node : nodes) {
NodeInfo info = nodesInfo.getNodesMap().get(node.id());
ImmutableMap<String, String> attrs = node.getAttributes();
for(String att : attrs.keySet()) {
table.startRow();
table.addCell(node.name());
table.addCell(fullId ? node.id() : Strings.substring(node.getId(), 0, 4));
table.addCell(info == null ? null : info.getProcess().getId());
table.addCell(node.getHostName());
table.addCell(node.getHostAddress());
if (node.address() instanceof InetSocketTransportAddress) {
table.addCell(((InetSocketTransportAddress) node.address()).address().getPort());
} else {
table.addCell("-");
}
table.addCell(att);
table.addCell(attrs.containsKey(att) ? attrs.get(att) : null);
table.endRow();
}
}
return table;
}
}

View File

@ -112,6 +112,8 @@ include::cat/indices.asciidoc[]
include::cat/master.asciidoc[]
include::cat/nodeattrs.asciidoc[]
include::cat/nodes.asciidoc[]
include::cat/pending_tasks.asciidoc[]

View File

@ -0,0 +1,71 @@
[[cat-nodeattrs]]
== cat nodeattrs
The `nodeattrs` command shows custom node attributes.
["source","sh",subs="attributes,callouts"]
--------------------------------------------------
% curl 192.168.56.10:9200/_cat/nodeattrs
node host ip attr value
Black Bolt epsilon 192.168.1.8 rack rack314
Black Bolt epsilon 192.168.1.8 azone us-east-1
--------------------------------------------------
The first few columns give you basic info per node.
["source","sh",subs="attributes,callouts"]
--------------------------------------------------
node host ip
Black Bolt epsilon 192.168.1.8
Black Bolt epsilon 192.168.1.8
--------------------------------------------------
The attr and value columns can give you a picture of custom node attributes.
[source,sh]
--------------------------------------------------
attr value
rack rack314
azone us-east-1
--------------------------------------------------
[float]
=== Columns
Below is an exhaustive list of the existing headers that can be
passed to `nodes?h=` to retrieve the relevant details in ordered
columns. If no headers are specified, then those marked to Appear
by Default will appear. If any header is specified, then the defaults
are not used.
Aliases can be used in place of the full header name for brevity.
Columns appear in the order that they are listed below unless a
different order is specified (e.g., `h=attr,value` versus `h=value,attr`).
When specifying headers, the headers are not placed in the output
by default. To have the headers appear in the output, use verbose
mode (`v`). The header name will match the supplied value (e.g.,
`pid` versus `p`). For example:
["source","sh",subs="attributes,callouts"]
--------------------------------------------------
% curl 192.168.56.10:9200/_cat/nodeattrs?v&h=name,pid,attr,value
name pid attr value
Black Bolt 28000 rack rack314
Black Bolt 28000 azone us-east-1
--------------------------------------------------
[cols="<,<,<,<,<",options="header",subs="normal"]
|=======================================================================
|Header |Alias |Appear by Default |Description |Example
|`node`|`name`|Yes|Name of the node|Black Bolt
|`id` |`nodeId` |No |Unique node ID |k0zy
|`pid` |`p` |No |Process ID |13061
|`host` |`h` |Yes |Host name |n1
|`ip` |`i` |Yes |IP address |127.0.1.1
|`port` |`po` |No |Bound transport port |9300
|`attr` | `attr.name` | Yes | Attribute name | rack
|`value` | `attr.value` | Yes | Attribute value | rack123
|=======================================================================

View File

@ -0,0 +1,37 @@
{
"cat.nodeattrs": {
"documentation": "http://www.elastic.co/guide/en/elasticsearch/reference/master/cat-nodeattrs.html",
"methods": ["GET"],
"url": {
"path": "/_cat/nodeattrs",
"paths": ["/_cat/nodeattrs"],
"parts": {
},
"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": true
}
}
},
"body": null
}
}

View File

@ -0,0 +1,27 @@
---
"Test cat nodes attrs output":
- do:
cat.nodeattrs:
v: false
- match:
$body: |
/((\S+)\s+(\S+)\s+(\d{1,3}\.){3}\d{1,3}\s+(\S+)\s+(\S+)\s*)+/
- do:
cat.nodeattrs:
v: true
- match:
$body: |
/((\S+)\s+(\S+)\s+(\d{1,3}\.){3}\d{1,3}\s+(\S+)\s+(\S+)\s*)+/
- do:
cat.nodeattrs:
h: attr,value
v: true
- match:
$body: |
/((\S+)\s+(\S+)\s*)+/