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(RestThreadPoolAction.class).asEagerSingleton();
|
||||||
catActionMultibinder.addBinding().to(RestPluginsAction.class).asEagerSingleton();
|
catActionMultibinder.addBinding().to(RestPluginsAction.class).asEagerSingleton();
|
||||||
catActionMultibinder.addBinding().to(RestFielddataAction.class).asEagerSingleton();
|
catActionMultibinder.addBinding().to(RestFielddataAction.class).asEagerSingleton();
|
||||||
|
catActionMultibinder.addBinding().to(RestNodeAttrsAction.class).asEagerSingleton();
|
||||||
// no abstract cat action
|
// no abstract cat action
|
||||||
bind(RestCatAction.class).asEagerSingleton();
|
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/master.asciidoc[]
|
||||||
|
|
||||||
|
include::cat/nodeattrs.asciidoc[]
|
||||||
|
|
||||||
include::cat/nodes.asciidoc[]
|
include::cat/nodes.asciidoc[]
|
||||||
|
|
||||||
include::cat/pending_tasks.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