Add _cat/nodeattrs API
This provides a _cat/nodeattrs API call, which presents custom node attributes in a denormalized table. Closes #8000
This commit is contained in:
parent
c6abf28273
commit
f209809716
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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[]
|
||||
|
|
|
@ -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
|
||||
|=======================================================================
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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*)+/
|
Loading…
Reference in New Issue