Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resurrect hot_threads routes #73855

Merged
merged 6 commits into from
Jun 8, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
{
"nodes.hotthreads":{
"documentation":{
"url":"https://www.elastic.co/guide/en/elasticsearch/reference/master/cluster-nodes-hot-threads.html",
"description":"Returns information about hot threads on each node in the cluster."
},
"stability":"stable",
"visibility":"public",
"headers":{
"accept": [ "text/plain"]
},
"url":{
"paths":[
{
"path":"/_cluster/nodes/hotthreads",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would it more correct to re-introduce this path (and the like) as deprecated in the spec for 7.x and add the allowed warning (for any tests that call this API) ?

This would allow you to avoid introducing the spec only for compatibility.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like that idea! Just to make sure I'm following -- that'd be a PR pointed at 7.x (no version that hits master) that adds these as deprecated endpoints to the rest-api-spec, and then in this PR we wouldn't need a new test or any specs, because this would all execute automatically by way of the yamlRestCompatTest tests.

Is there any downside to adding these as deprecated in 7.x? I'm thinking, for example, that perhaps the autogenerated client code might actually start using them (if so, that'd be strictly worse, and we probably wouldn't want to go this way).

@pgomulka what do you think?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i like that idea too!
if a test client will use it, maybe we can ignore the warning in 7.x for this? Like we do for types removal in 7.x

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that'd be a PR pointed at 7.x (no version that hits master) that adds these as deprecated endpoints to the rest-api-spec,

yes, that is what i meant. I think it works well in this case (and any other one off cases) since it probably should have been that way from the start and should have minimal pollution in 7.x.

However, I don't think this should be a rule of thumb for all missing paths. For example, for the _xpack/ prefix i can see the argument for not polluting 7.x since there are so many, somewhat inconsistent (depending on when it was added), and has a lot of associated tests that would need to allow warnings.

"methods":[
"GET"
]
},
{
"path":"/_cluster/nodes/hot_threads",
"methods":[
"GET"
]
},
{
"path":"/_clusters/nodes/{node_id}/hotthreads",
"methods":[
"GET"
],
"parts":{
"node_id":{
"type":"list",
"description":"A comma-separated list of node IDs or names to limit the returned information; leave empty to get information from all nodes"
}
}
},
{
"path":"/_clusters/nodes/{node_id}/hot_threads",
"methods":[
"GET"
],
"parts":{
"node_id":{
"type":"list",
"description":"A comma-separated list of node IDs or names to limit the returned information; leave empty to get information from all nodes"
}
}
},
{
"path":"/_nodes/hotthreads",
"methods":[
"GET"
]
},
{
"path":"/_nodes/{node_id}/hotthreads",
"methods":[
"GET"
],
"parts":{
"node_id":{
"type":"list",
"description":"A comma-separated list of node IDs or names to limit the returned information; leave empty to get information from all nodes"
}
}
}
]
},
"params":{
"interval":{
"type":"time",
"description":"The interval for the second sampling of threads"
},
"snapshots":{
"type":"number",
"description":"Number of samples of thread stacktrace (default: 10)"
},
"threads":{
"type":"number",
"description":"Specify the number of threads to provide information for (default: 3)"
},
"ignore_idle_threads":{
"type":"boolean",
"description":"Don't show threads that are in known-idle places, such as waiting on a socket select or pulling from an empty task queue (default: true)"
},
"type":{
"type":"enum",
"options":[
"cpu",
"wait",
"block"
],
"description":"The type to sample (default: cpu)"
},
"timeout":{
"type":"time",
"description":"Explicit operation timeout"
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
setup:
- skip:
version: "9.0.0 - "
reason: "compatible from 8.x to 7.x"
features:
- "headers"
- "warnings_regex"

---
"Get hot threads":

- do:
headers:
Content-Type: "application/vnd.elasticsearch+json;compatible-with=7"
Accept: "application/vnd.elasticsearch+json;compatible-with=7"
nodes.hotthreads: {}
warnings_regex:
- ".*hot_?threads.* is a deprecated endpoint.*"
- match:
$body: /:::/
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This match is not my most favorite code ever. I wanted to verify that the response actually resembles a hot_threads response, but the regex match has to be on the first line and there's not all that much for us to match on there:

::: {runTask-0}{rNO3-C-BStGLmQ_xUdIecA}{PiMCJKfOSnuRkp0Uk1E7ig}{127.0.0.1}{127.0.0.1:9300}{cdfhilmrstw}{ml.machine_memory=68719476736, xpack.installed=true, testattr=test, ml.max_open_jobs=512, ml.max_jvm_size=536870912}
   Hot threads at 2021-06-07T15:44:46.079Z, interval=500ms, busiestThreads=3, ignoreIdleThreads=true:

Copy link
Contributor Author

@joegallo joegallo Jun 7, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Anyway, there is a ::: so I'm matching on that. A reasonable alternative would be to cut the match entirely and just run with "any non-error response is good enough".

Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import org.elasticsearch.action.admin.cluster.node.hotthreads.NodesHotThreadsResponse;
import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.RestApiVersion;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.rest.BaseRestHandler;
import org.elasticsearch.rest.BytesRestResponse;
Expand All @@ -23,16 +24,59 @@

import java.io.IOException;
import java.util.List;
import java.util.Locale;

import static org.elasticsearch.rest.RestRequest.Method.GET;

public class RestNodesHotThreadsAction extends BaseRestHandler {

private static final String formatDeprecatedMessageWithoutNodeID = "[%s] is a deprecated endpoint. " +
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just a thought. we could just use one message for all. We have a used endpoint as a key, API_GET_/_nodes/{nodeid}/hot_threads
not as readable as here, but might save some effort
but it looks good now too!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I basically did a revert + edit of the commit that removed the apis, so it was cheap to do it as is (and keeps the code mostly in line with the way it is on 7.x).

"Please use [/_nodes/hot_threads] instead.";
private static final String formatDeprecatedMessageWithNodeID = "[%s] is a deprecated endpoint. " +
"Please use [/_nodes/{nodeId}/hot_threads] instead.";
private static final String DEPRECATED_MESSAGE_CLUSTER_NODES_HOT_THREADS = String.format(Locale.ROOT,
formatDeprecatedMessageWithoutNodeID,
"/_cluster/nodes/hot_threads"
);
private static final String DEPRECATED_MESSAGE_CLUSTER_NODES_NODEID_HOT_THREADS = String.format(Locale.ROOT,
formatDeprecatedMessageWithNodeID,
"/_cluster/nodes/{nodeId}/hot_threads"
);
private static final String DEPRECATED_MESSAGE_CLUSTER_NODES_HOTTHREADS = String.format(Locale.ROOT,
formatDeprecatedMessageWithoutNodeID,
"/_cluster/nodes/hotthreads"
);
private static final String DEPRECATED_MESSAGE_CLUSTER_NODES_NODEID_HOTTHREADS = String.format(Locale.ROOT,
formatDeprecatedMessageWithNodeID,
"/_cluster/nodes/{nodeId}/hotthreads"
);
private static final String DEPRECATED_MESSAGE_NODES_HOTTHREADS = String.format(Locale.ROOT,
formatDeprecatedMessageWithoutNodeID,
"/_nodes/hotthreads"
);
private static final String DEPRECATED_MESSAGE_NODES_NODEID_HOTTHREADS = String.format(Locale.ROOT,
formatDeprecatedMessageWithNodeID,
"/_nodes/{nodeId}/hotthreads"
);

@Override
public List<Route> routes() {
return List.of(
new Route(GET, "/_nodes/hot_threads"),
new Route(GET, "/_nodes/{nodeId}/hot_threads")
new Route(GET, "/_nodes/{nodeId}/hot_threads"),

Route.builder(GET, "/_cluster/nodes/hot_threads")
.deprecated(DEPRECATED_MESSAGE_CLUSTER_NODES_HOT_THREADS, RestApiVersion.V_7).build(),
Route.builder(GET, "/_cluster/nodes/{nodeId}/hot_threads")
.deprecated(DEPRECATED_MESSAGE_CLUSTER_NODES_NODEID_HOT_THREADS, RestApiVersion.V_7).build(),
Route.builder(GET, "/_cluster/nodes/hotthreads")
.deprecated(DEPRECATED_MESSAGE_CLUSTER_NODES_HOTTHREADS, RestApiVersion.V_7).build(),
Route.builder(GET, "/_cluster/nodes/{nodeId}/hotthreads")
.deprecated(DEPRECATED_MESSAGE_CLUSTER_NODES_NODEID_HOTTHREADS, RestApiVersion.V_7).build(),
Route.builder(GET, "/_nodes/hotthreads")
.deprecated(DEPRECATED_MESSAGE_NODES_HOTTHREADS, RestApiVersion.V_7).build(),
Route.builder(GET, "/_nodes/{nodeId}/hotthreads")
.deprecated(DEPRECATED_MESSAGE_NODES_NODEID_HOTTHREADS, RestApiVersion.V_7).build()
);
}

Expand Down