Skip to content

Commit fef5680

Browse files
committed
loadtest-controller: update deprecated kibana dashboard & importing/exporting
1 parent 4d61ea3 commit fef5680

3 files changed

Lines changed: 62 additions & 33 deletions

File tree

loadtest-controller/src/main/java/io/openvidu/loadtest/monitoring/ElasticSearchClient.java

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import jakarta.annotation.PostConstruct;
88

99
import co.elastic.clients.elasticsearch.ElasticsearchClient;
10+
import co.elastic.clients.elasticsearch._types.ElasticsearchException;
1011
import co.elastic.clients.elasticsearch._types.SortOrder;
1112
import co.elastic.clients.elasticsearch.core.SearchResponse;
1213
import co.elastic.clients.elasticsearch.core.search.Hit;
@@ -90,19 +91,9 @@ public void init() {
9091
}
9192
}
9293

93-
private boolean doPing() {
94-
boolean pingSuccess = false;
95-
try {
96-
BooleanResponse response = this.client.ping();
97-
pingSuccess = response.value();
98-
} catch (IOException e) {
99-
throw new LoadTestInitializationException(
100-
"Connection to Elasticsearch failed at " + loadTestConfig.getElasticsearchHost()
101-
+ " (" + e.getMessage()
102-
+ "). If property 'ELASTICSEARCH_HOST' is defined, then it is mandatory that OpenVidu Load Test is able to connect to it",
103-
e);
104-
}
105-
return pingSuccess;
94+
private boolean doPing() throws ElasticsearchException, IOException {
95+
BooleanResponse response = this.client.ping();
96+
return response.value();
10697
}
10798

10899
public boolean isInitialized() {

loadtest-controller/src/main/java/io/openvidu/loadtest/monitoring/KibanaClient.java

Lines changed: 53 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,28 +10,34 @@
1010
import org.slf4j.Logger;
1111
import org.slf4j.LoggerFactory;
1212
import org.springframework.core.io.Resource;
13+
import java.nio.file.StandardCopyOption;
14+
import java.io.InputStream;
15+
import java.nio.file.Files;
1316
import org.springframework.core.io.ResourceLoader;
1417
import org.springframework.stereotype.Service;
1518

1619
import com.google.gson.JsonObject;
20+
import com.google.gson.JsonArray;
1721

1822
import io.openvidu.loadtest.config.LoadTestConfig;
1923
import io.openvidu.loadtest.utils.CustomHttpClient;
2024
import io.openvidu.loadtest.utils.JsonUtils;
2125

2226
/**
23-
* @author Carlos Santos
27+
* @author Carlos Santos & Iván Chicano
2428
*
2529
*/
2630

2731
@Service
2832
public class KibanaClient {
2933

3034
private static final String API_IMPORT_OBJECTS = "/api/saved_objects/_import?overwrite=true";
31-
private static final String API_FIND_DASHBOARD = "/api/saved_objects/_find?type=dashboard&search_fields=title&search=";
35+
private static final String API_EXPORT_SAVED_OBJECTS = "/api/saved_objects/_export";
3236
private static final String KIBANA_DASHBOARD_URL = "/app/kibana#/dashboard/";
3337
private static final String LOAD_TEST_DASHBOARD = "Load Test";
3438

39+
private static final String DASHBOARD_NOT_FOUND = "Kibana Load Test Dashboard is not found. You can import it manually to see the results.";
40+
3541
private static final int HTTP_STATUS_OK = 200;
3642

3743
private static final Logger log = LoggerFactory.getLogger(KibanaClient.class);
@@ -58,7 +64,8 @@ public void importDashboards() {
5864
this.kibanaHost = loadTestConfig.getKibanaHost().replaceAll("/$", "");
5965
log.info("Importing Kibana JSON file with saved objects from resources directory");
6066
Resource resource = resourceLoader.getResource("classpath:loadtest.ndjson");
61-
importSavedObjects(resource.getFile());
67+
File file = resourceToFile(resource);
68+
importSavedObjects(file);
6269
} catch (Exception e) {
6370
log.warn("Can't import dashboard to Kibana at {}", this.kibanaHost);
6471
log.error(e.getMessage());
@@ -68,11 +75,23 @@ public void importDashboards() {
6875
log.warn("Kibana Host parameter is empty. Dashboard won't be imported.");
6976
}
7077

78+
private File resourceToFile(Resource resource) throws IOException {
79+
try {
80+
return resource.getFile();
81+
} catch (Exception ex) {
82+
try (InputStream is = resource.getInputStream()) {
83+
File file = File.createTempFile("loadtest", ".ndjson");
84+
Files.copy(is, file.toPath(), StandardCopyOption.REPLACE_EXISTING);
85+
file.deleteOnExit();
86+
return file;
87+
}
88+
}
89+
}
90+
7191
public String getDashboardUrl(String startTime, String endTime) {
7292
if (this.loadTestConfig.isKibanaEstablished()) {
73-
74-
final String URL = this.loadTestConfig.getKibanaHost() + API_FIND_DASHBOARD
75-
+ LOAD_TEST_DASHBOARD.replaceAll("\\s+", "%20");
93+
// Use the Export API instead of the deprecated _find endpoint.
94+
final String URL = this.loadTestConfig.getKibanaHost() + API_EXPORT_SAVED_OBJECTS;
7695
Map<String, String> headers = new HashMap<>();
7796

7897
String esUserName = loadTestConfig.getElasticsearchUserName();
@@ -81,18 +100,20 @@ public String getDashboardUrl(String startTime, String endTime) {
81100
if (securityEnabled) {
82101
headers.put("Authorization", getBasicAuth(esUserName, esPassword));
83102
}
103+
headers.put("kbn-xsrf", "true");
84104

85105
try {
86-
HttpResponse<String> response = this.httpClient.sendGet(URL, headers);
106+
JsonObject body = new JsonObject();
107+
body.addProperty("type", "dashboard");
108+
body.addProperty("search", LOAD_TEST_DASHBOARD);
109+
JsonArray searchFields = new JsonArray();
110+
searchFields.add("title");
111+
body.add("search_fields", searchFields);
87112

88-
if (response.statusCode() == HTTP_STATUS_OK) {
113+
HttpResponse<String> response = this.httpClient.sendPost(URL, body, null, headers);
89114

90-
JsonObject jsonResponse = this.jsonUtils.getJson(response.body());
91-
JsonObject dashboard = jsonResponse.get("saved_objects").getAsJsonArray().get(0).getAsJsonObject();
92-
String dashboardId = dashboard.get("id").getAsString();
93-
94-
return this.loadTestConfig.getKibanaHost() + KIBANA_DASHBOARD_URL + dashboardId
95-
+ "?_g=(time:(from:'" + startTime + "',to:'" + endTime + "'))";
115+
if (response.statusCode() == HTTP_STATUS_OK) {
116+
return extractDashboardUrlFromResponse(response, startTime, endTime);
96117
}
97118
} catch (InterruptedException e) {
98119
Thread.currentThread().interrupt();
@@ -104,8 +125,25 @@ public String getDashboardUrl(String startTime, String endTime) {
104125
}
105126
}
106127

107-
return "Kibana Load Test Dashboard is not found. You can import it manually to see the results.";
128+
return DASHBOARD_NOT_FOUND;
129+
130+
}
108131

132+
private String extractDashboardUrlFromResponse(HttpResponse<String> response, String startTime, String endTime) {
133+
// response is NDJSON (one JSON object per line). Parse first dashboard object.
134+
String[] lines = response.body().split("\\r?\\n");
135+
for (String line : lines) {
136+
if (line == null || line.trim().isEmpty()) {
137+
continue;
138+
}
139+
JsonObject obj = this.jsonUtils.getJson(line);
140+
if (obj.has("type") && "dashboard".equals(obj.get("type").getAsString()) && obj.has("id")) {
141+
String dashboardId = obj.get("id").getAsString();
142+
return this.loadTestConfig.getKibanaHost() + KIBANA_DASHBOARD_URL + dashboardId
143+
+ "?_g=(time:(from:'" + startTime + "',to:'" + endTime + "'))";
144+
}
145+
}
146+
return DASHBOARD_NOT_FOUND;
109147
}
110148

111149
private void importSavedObjects(File file) throws IOException {

0 commit comments

Comments
 (0)