Skip to content

Commit d9ad67b

Browse files
committed
Add stats endpoint to GeoIpDownloader (elastic#70282)
This change adds _geoip/stats endpoint that can be used to collect basic data about geoip downloader (successful, failed and skipped downloads, current db count and total time spent downloading). It also fixes missing/wrong origins for clients that will break if used with security. Relates to elastic#68920
1 parent f66fe70 commit d9ad67b

File tree

21 files changed

+1146
-45
lines changed

21 files changed

+1146
-45
lines changed

client/rest-high-level/build.gradle

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ dependencies {
4747
testImplementation(project(':x-pack:plugin:core')) {
4848
exclude group: 'org.elasticsearch', module: 'elasticsearch-rest-high-level-client'
4949
}
50+
testImplementation(project(':modules:ingest-geoip')) {
51+
exclude group: 'com.fasterxml.jackson.core', module: 'jackson-annotations'
52+
}
5053
testImplementation(project(':x-pack:plugin:eql'))
5154
}
5255

@@ -81,6 +84,8 @@ tasks.named("check").configure {
8184
testClusters.all {
8285
testDistribution = 'DEFAULT'
8386
systemProperty 'es.scripting.update.ctx_in_params', 'false'
87+
systemProperty 'es.geoip_v2_feature_flag_enabled', 'true'
88+
setting 'geoip.downloader.enabled', 'false'
8489
setting 'reindex.remote.whitelist', '[ "[::1]:*", "127.0.0.1:*" ]'
8590
setting 'xpack.license.self_generated.type', 'trial'
8691
setting 'xpack.security.enabled', 'true'
Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0 and the Server Side Public License, v 1; you may not use this file except
5+
* in compliance with, at your election, the Elastic License 2.0 or the Server
6+
* Side Public License, v 1.
7+
*/
8+
9+
package org.elasticsearch.client;
10+
11+
import org.elasticsearch.common.ParseField;
12+
import org.elasticsearch.common.collect.Tuple;
13+
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
14+
import org.elasticsearch.common.xcontent.ToXContentObject;
15+
import org.elasticsearch.common.xcontent.XContentBuilder;
16+
import org.elasticsearch.common.xcontent.XContentParser;
17+
18+
import java.io.IOException;
19+
import java.util.Collection;
20+
import java.util.List;
21+
import java.util.Map;
22+
import java.util.Objects;
23+
import java.util.function.Function;
24+
import java.util.stream.Collectors;
25+
26+
import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg;
27+
import static org.elasticsearch.common.xcontent.ConstructingObjectParser.optionalConstructorArg;
28+
29+
public class GeoIpStatsResponse implements ToXContentObject {
30+
31+
@SuppressWarnings("unchecked")
32+
private static final ConstructingObjectParser<GeoIpStatsResponse, Void> PARSER = new ConstructingObjectParser<>("geoip_stats", a -> {
33+
Map<String, Object> stats = (Map<String, Object>) a[0];
34+
List<Tuple<String, NodeInfo>> nodes = (List<Tuple<String, NodeInfo>>) a[1];
35+
36+
return new GeoIpStatsResponse((int) stats.get("successful_downloads"), (int) stats.get("failed_downloads"),
37+
((Number) stats.get("total_download_time")).longValue(), (int) stats.get("databases_count"), (int) stats.get("skipped_updates"),
38+
nodes.stream().collect(Collectors.toMap(Tuple::v1, Tuple::v2)));
39+
});
40+
41+
static {
42+
PARSER.declareObject(constructorArg(), (p, c) -> p.map(), new ParseField("stats"));
43+
PARSER.declareNamedObjects(constructorArg(), (p, c, name) -> Tuple.tuple(name, NodeInfo.PARSER.apply(p, c)),
44+
new ParseField("nodes"));
45+
}
46+
47+
private final int successfulDownloads;
48+
private final int failedDownloads;
49+
private final long totalDownloadTime;
50+
private final int databasesCount;
51+
private final int skippedDownloads;
52+
private final Map<String, NodeInfo> nodes;
53+
54+
public GeoIpStatsResponse(int successfulDownloads, int failedDownloads, long totalDownloadTime, int databasesCount,
55+
int skippedDownloads, Map<String, NodeInfo> nodes) {
56+
this.successfulDownloads = successfulDownloads;
57+
this.failedDownloads = failedDownloads;
58+
this.totalDownloadTime = totalDownloadTime;
59+
this.databasesCount = databasesCount;
60+
this.skippedDownloads = skippedDownloads;
61+
this.nodes = nodes;
62+
}
63+
64+
public int getSuccessfulDownloads() {
65+
return successfulDownloads;
66+
}
67+
68+
public int getFailedDownloads() {
69+
return failedDownloads;
70+
}
71+
72+
public long getTotalDownloadTime() {
73+
return totalDownloadTime;
74+
}
75+
76+
public int getDatabasesCount() {
77+
return databasesCount;
78+
}
79+
80+
public int getSkippedDownloads() {
81+
return skippedDownloads;
82+
}
83+
84+
public Map<String, NodeInfo> getNodes() {
85+
return nodes;
86+
}
87+
88+
public static GeoIpStatsResponse fromXContent(XContentParser parser) {
89+
return PARSER.apply(parser, null);
90+
}
91+
92+
@Override
93+
public boolean equals(Object o) {
94+
if (this == o) return true;
95+
if (o == null || getClass() != o.getClass()) return false;
96+
GeoIpStatsResponse that = (GeoIpStatsResponse) o;
97+
return successfulDownloads == that.successfulDownloads
98+
&& failedDownloads == that.failedDownloads
99+
&& totalDownloadTime == that.totalDownloadTime
100+
&& databasesCount == that.databasesCount
101+
&& skippedDownloads == that.skippedDownloads
102+
&& nodes.equals(that.nodes);
103+
}
104+
105+
@Override
106+
public int hashCode() {
107+
return Objects.hash(successfulDownloads, failedDownloads, totalDownloadTime, databasesCount, skippedDownloads, nodes);
108+
}
109+
110+
@Override
111+
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
112+
builder.startObject();
113+
builder.startObject("stats");
114+
{
115+
builder.field("successful_downloads", successfulDownloads);
116+
builder.field("failed_downloads", failedDownloads);
117+
builder.field("skipped_updates", skippedDownloads);
118+
builder.field("total_download_time", totalDownloadTime);
119+
builder.field("databases_count", databasesCount);
120+
}
121+
builder.endObject();
122+
builder.field("nodes", nodes);
123+
builder.endObject();
124+
return builder;
125+
}
126+
127+
public static final class NodeInfo implements ToXContentObject {
128+
@SuppressWarnings("unchecked")
129+
private static final ConstructingObjectParser<NodeInfo, Void> PARSER = new ConstructingObjectParser<>("node_info", a -> {
130+
List<DatabaseInfo> databases = (List<DatabaseInfo>) a[1];
131+
return new NodeInfo((Collection<String>) a[0], databases.stream().collect(Collectors.toMap(DatabaseInfo::getName,
132+
Function.identity())));
133+
});
134+
135+
static {
136+
PARSER.declareStringArray(optionalConstructorArg(), new ParseField("files_in_temp"));
137+
PARSER.declareObjectArray(optionalConstructorArg(), DatabaseInfo.PARSER, new ParseField("databases"));
138+
}
139+
140+
private final List<String> filesInTemp;
141+
private final Map<String, DatabaseInfo> databases;
142+
143+
public NodeInfo(Collection<String> filesInTemp, Map<String, DatabaseInfo> databases) {
144+
this.filesInTemp = List.copyOf(filesInTemp);
145+
this.databases = Map.copyOf(databases);
146+
}
147+
148+
public List<String> getFilesInTemp() {
149+
return filesInTemp;
150+
}
151+
152+
public Map<String, DatabaseInfo> getDatabases() {
153+
return databases;
154+
}
155+
156+
@Override
157+
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
158+
builder.startObject();
159+
builder.field("files_in_temp", filesInTemp);
160+
builder.field("databases", databases.entrySet().stream()
161+
.sorted(Map.Entry.comparingByKey())
162+
.map(Map.Entry::getValue)
163+
.collect(Collectors.toList()));
164+
builder.endObject();
165+
return builder;
166+
}
167+
168+
@Override
169+
public boolean equals(Object o) {
170+
if (this == o) return true;
171+
if (o == null || getClass() != o.getClass()) return false;
172+
NodeInfo nodeInfo = (NodeInfo) o;
173+
return filesInTemp.equals(nodeInfo.filesInTemp) && databases.equals(nodeInfo.databases);
174+
}
175+
176+
@Override
177+
public int hashCode() {
178+
return Objects.hash(filesInTemp, databases);
179+
}
180+
}
181+
182+
public static final class DatabaseInfo implements ToXContentObject {
183+
184+
private static final ConstructingObjectParser<DatabaseInfo, Void> PARSER = new ConstructingObjectParser<>("database_info",
185+
a -> new DatabaseInfo((String) a[0]));
186+
187+
static {
188+
PARSER.declareString(constructorArg(), new ParseField("name"));
189+
}
190+
191+
private final String name;
192+
193+
public DatabaseInfo(String name) {
194+
this.name = name;
195+
}
196+
197+
public String getName() {
198+
return name;
199+
}
200+
201+
@Override
202+
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
203+
builder.startObject();
204+
builder.field("name", name);
205+
builder.endObject();
206+
return builder;
207+
}
208+
209+
@Override
210+
public boolean equals(Object o) {
211+
if (this == o) return true;
212+
if (o == null || getClass() != o.getClass()) return false;
213+
DatabaseInfo that = (DatabaseInfo) o;
214+
return name.equals(that.name);
215+
}
216+
217+
@Override
218+
public int hashCode() {
219+
return Objects.hash(name);
220+
}
221+
}
222+
}

0 commit comments

Comments
 (0)