### Description

From the nodes stats API, we should extract the `thread_pool` stats into their own endpoint. This endpoint can then be non-node-centric, and present a global view of the number of completed, rejected, and failed operations for each of the threadpools in the system.
server/src/test/java/org/elasticsearch/action/admin/cluster/node/stats/NodeStatsTests.java
+ expectedChunks(nodeStats.getHttp()) 
            + expectedChunks(nodeStats.getIndices(), level) 
            + expectedChunks(nodeStats.getTransport()) 
            + expectedChunks(nodeStats.getIngestStats()) 
            + expectedChunks(nodeStats.getThreadPool());
    }
    private static int expectedChunks(ThreadPoolStats threadPool) {
        return threadPool == null ? 0 : 2 + threadPool.stats().stream().mapToInt(s -> {
            var chunks = 0;
            chunks += s.threads() == -1 ? 0 : 1;
            chunks += s.queue() == -1 ? 0 : 1;
            chunks += s.active() == -1 ? 0 : 1;
            chunks += s.rejected() == -1 ? 0 : 1;
            chunks += s.largest() == -1 ? 0 : 1;
            chunks += s.completed() == -1 ? 0 : 1;
            return 2 + chunks; 
        }).sum();
    }
    private static int expectedChunks(@Nullable IngestStats ingestStats) {
        return ingestStats == null
            ? 0
            : 2 + ingestStats.pipelineStats()
                .stream()
                .mapToInt(pipelineStats -> 2 + ingestStats.processorStats().getOrDefault(pipelineStats.pipelineId(), List.of()).size())
                .sum();
    }
    private static int expectedChunks(@Nullable HttpStats httpStats) {
        return httpStats == null ? 0 : 2 + httpStats.getClientStats().size();
    }
    private static int expectedChunks(@Nullable TransportStats transportStats) {