Skip to content

Commit 5723ced

Browse files
committed
Merge remote-tracking branch 'origin/main' into issues/4636
Signed-off-by: Yuanchun Shen <yuanchu@amazon.com>
2 parents f70bc97 + 8073b4e commit 5723ced

12 files changed

Lines changed: 220 additions & 186 deletions

File tree

common/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ dependencies {
4545
implementation "com.github.seancfoley:ipaddress:5.4.2"
4646

4747
testImplementation group: 'junit', name: 'junit', version: '4.13.2'
48-
testImplementation group: 'org.assertj', name: 'assertj-core', version: '3.9.1'
48+
testImplementation group: 'org.assertj', name: 'assertj-core', version: '3.27.7'
4949
testImplementation group: 'com.google.guava', name: 'guava', version: "${guava_version}"
5050
testImplementation group: 'org.hamcrest', name: 'hamcrest-library', version: "${hamcrest_version}"
5151
testImplementation('org.junit.jupiter:junit-jupiter:5.9.3')

direct-query-core/src/main/java/org/opensearch/sql/prometheus/client/PrometheusClientImpl.java

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import org.json.JSONArray;
2727
import org.json.JSONException;
2828
import org.json.JSONObject;
29+
import org.opensearch.secure_sm.AccessController;
2930
import org.opensearch.sql.prometheus.exception.PrometheusClientException;
3031
import org.opensearch.sql.prometheus.model.MetricMetadata;
3132

@@ -91,7 +92,7 @@ public JSONObject queryRange(
9192
Request request = new Request.Builder().url(queryUrl).build();
9293

9394
logger.debug("Executing Prometheus request with headers: {}", request.headers().toString());
94-
Response response = this.prometheusHttpClient.newCall(request).execute();
95+
Response response = AccessController.doPrivilegedChecked(() -> this.prometheusHttpClient.newCall(request).execute());
9596

9697
logger.debug("Received Prometheus response for query_range: code={}", response);
9798

@@ -126,7 +127,7 @@ public JSONObject query(String query, Long time, Integer limit, Integer timeout)
126127
Request request = new Request.Builder().url(queryUrl).build();
127128

128129
logger.info("Executing Prometheus request with headers: {}", request.headers().toString());
129-
Response response = this.prometheusHttpClient.newCall(request).execute();
130+
Response response = AccessController.doPrivilegedChecked(() -> this.prometheusHttpClient.newCall(request).execute());
130131

131132
logger.info("Received Prometheus response for instant query: code={}", response);
132133
// Return the full response object, not just the data field
@@ -146,7 +147,7 @@ public List<String> getLabels(Map<String, String> queryParams) throws IOExceptio
146147
"%s/api/v1/labels%s", prometheusUri.toString().replaceAll("/$", ""), queryString);
147148
logger.debug("queryUrl: " + queryUrl);
148149
Request request = new Request.Builder().url(queryUrl).build();
149-
Response response = this.prometheusHttpClient.newCall(request).execute();
150+
Response response = AccessController.doPrivilegedChecked(() -> this.prometheusHttpClient.newCall(request).execute());
150151
JSONObject jsonObject = readResponse(response);
151152
return toListOfLabels(jsonObject.getJSONArray("data"));
152153
}
@@ -161,7 +162,7 @@ public List<String> getLabel(String labelName, Map<String, String> queryParams)
161162
prometheusUri.toString().replaceAll("/$", ""), labelName, queryString);
162163
logger.debug("queryUrl: " + queryUrl);
163164
Request request = new Request.Builder().url(queryUrl).build();
164-
Response response = this.prometheusHttpClient.newCall(request).execute();
165+
Response response = AccessController.doPrivilegedChecked(() -> this.prometheusHttpClient.newCall(request).execute());
165166
JSONObject jsonObject = readResponse(response);
166167
return toListOfLabels(jsonObject.getJSONArray("data"));
167168
}
@@ -175,7 +176,7 @@ public Map<String, List<MetricMetadata>> getAllMetrics(Map<String, String> query
175176
"%s/api/v1/metadata%s", prometheusUri.toString().replaceAll("/$", ""), queryString);
176177
logger.debug("queryUrl: " + queryUrl);
177178
Request request = new Request.Builder().url(queryUrl).build();
178-
Response response = this.prometheusHttpClient.newCall(request).execute();
179+
Response response = AccessController.doPrivilegedChecked(() -> this.prometheusHttpClient.newCall(request).execute());
179180
JSONObject jsonObject = readResponse(response);
180181
TypeReference<HashMap<String, List<MetricMetadata>>> typeRef = new TypeReference<>() {};
181182
return new ObjectMapper().readValue(jsonObject.getJSONObject("data").toString(), typeRef);
@@ -194,7 +195,7 @@ public List<Map<String, String>> getSeries(Map<String, String> queryParams) thro
194195
"%s/api/v1/series%s", prometheusUri.toString().replaceAll("/$", ""), queryString);
195196
logger.debug("queryUrl: " + queryUrl);
196197
Request request = new Request.Builder().url(queryUrl).build();
197-
Response response = this.prometheusHttpClient.newCall(request).execute();
198+
Response response = AccessController.doPrivilegedChecked(() -> this.prometheusHttpClient.newCall(request).execute());
198199
JSONObject jsonObject = readResponse(response);
199200
JSONArray dataArray = jsonObject.getJSONArray("data");
200201
return toListOfSeries(dataArray);
@@ -211,7 +212,7 @@ public JSONArray queryExemplars(String query, Long start, Long end) throws IOExc
211212
end);
212213
logger.debug("queryUrl: " + queryUrl);
213214
Request request = new Request.Builder().url(queryUrl).build();
214-
Response response = this.prometheusHttpClient.newCall(request).execute();
215+
Response response = AccessController.doPrivilegedChecked(() -> this.prometheusHttpClient.newCall(request).execute());
215216
JSONObject jsonObject = readResponse(response);
216217
return jsonObject.getJSONArray("data");
217218
}
@@ -222,7 +223,7 @@ public JSONObject getAlerts() throws IOException {
222223
String.format("%s/api/v1/alerts", prometheusUri.toString().replaceAll("/$", ""));
223224
logger.debug("Making Prometheus alerts request: {}", queryUrl);
224225
Request request = new Request.Builder().url(queryUrl).build();
225-
Response response = this.prometheusHttpClient.newCall(request).execute();
226+
Response response = AccessController.doPrivilegedChecked(() -> this.prometheusHttpClient.newCall(request).execute());
226227
JSONObject jsonObject = readResponse(response);
227228
return jsonObject.getJSONObject("data");
228229
}
@@ -235,7 +236,7 @@ public JSONObject getRules(Map<String, String> queryParams) throws IOException {
235236
"%s/api/v1/rules%s", prometheusUri.toString().replaceAll("/$", ""), queryString);
236237
logger.debug("Making Prometheus rules request: {}", queryUrl);
237238
Request request = new Request.Builder().url(queryUrl).build();
238-
Response response = this.prometheusHttpClient.newCall(request).execute();
239+
Response response = AccessController.doPrivilegedChecked(() -> this.prometheusHttpClient.newCall(request).execute());
239240
JSONObject jsonObject = readResponse(response);
240241
return jsonObject.getJSONObject("data");
241242
}
@@ -248,7 +249,7 @@ public JSONArray getAlertmanagerAlerts(Map<String, String> queryParams) throws I
248249

249250
logger.debug("Making Alertmanager alerts request: {}", queryUrl);
250251
Request request = new Request.Builder().url(queryUrl).build();
251-
Response response = this.alertmanagerHttpClient.newCall(request).execute();
252+
Response response = AccessController.doPrivilegedChecked(() -> this.alertmanagerHttpClient.newCall(request).execute());
252253

253254
return readAlertmanagerResponse(response);
254255
}
@@ -261,7 +262,7 @@ public JSONArray getAlertmanagerAlertGroups(Map<String, String> queryParams) thr
261262

262263
logger.debug("Making Alertmanager alert groups request: {}", queryUrl);
263264
Request request = new Request.Builder().url(queryUrl).build();
264-
Response response = this.alertmanagerHttpClient.newCall(request).execute();
265+
Response response = AccessController.doPrivilegedChecked(() -> this.alertmanagerHttpClient.newCall(request).execute());
265266

266267
return readAlertmanagerResponse(response);
267268
}
@@ -273,7 +274,7 @@ public JSONArray getAlertmanagerReceivers() throws IOException {
273274

274275
logger.debug("Making Alertmanager receivers request: {}", queryUrl);
275276
Request request = new Request.Builder().url(queryUrl).build();
276-
Response response = this.alertmanagerHttpClient.newCall(request).execute();
277+
Response response = AccessController.doPrivilegedChecked(() -> this.alertmanagerHttpClient.newCall(request).execute());
277278

278279
return readAlertmanagerResponse(response);
279280
}
@@ -285,7 +286,7 @@ public JSONArray getAlertmanagerSilences() throws IOException {
285286

286287
logger.debug("Making Get Alertmanager silences request: {}", queryUrl);
287288
Request request = new Request.Builder().url(queryUrl).build();
288-
Response response = this.alertmanagerHttpClient.newCall(request).execute();
289+
Response response = AccessController.doPrivilegedChecked(() -> this.alertmanagerHttpClient.newCall(request).execute());
289290

290291
return readAlertmanagerResponse(response);
291292
}
@@ -301,7 +302,7 @@ public String createAlertmanagerSilences(String silenceJson) throws IOException
301302
.header("Content-Type", "application/json")
302303
.post(RequestBody.create(silenceJson.getBytes(StandardCharsets.UTF_8)))
303304
.build();
304-
Response response = this.alertmanagerHttpClient.newCall(request).execute();
305+
Response response = AccessController.doPrivilegedChecked(() -> this.alertmanagerHttpClient.newCall(request).execute());
305306

306307
if (response.isSuccessful()) {
307308
return Objects.requireNonNull(response.body()).string();

integ-test/build.gradle

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,6 @@ task integTestWithSecurity(type: RestIntegTestTask) {
406406
configureSecurityPlugin(cluster)
407407
}
408408

409-
useJUnitPlatform()
410409
dependsOn ':opensearch-sql-plugin:bundlePlugin'
411410
testLogging {
412411
events "passed", "skipped", "failed"
@@ -447,11 +446,8 @@ task integTestWithSecurity(type: RestIntegTestTask) {
447446
jvmArgs '-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:5005'
448447
}
449448

450-
// NOTE: this IT config discovers only junit5 (jupiter) tests.
451-
// https://github.com/opensearch-project/sql/issues/1974
452449
filter {
453-
includeTestsMatching 'org.opensearch.sql.security.CrossClusterSearchIT'
454-
includeTestsMatching 'org.opensearch.sql.security.PPLPermissionsIT'
450+
includeTestsMatching 'org.opensearch.sql.security.*'
455451
}
456452
}
457453

integ-test/src/test/java/org/opensearch/sql/legacy/OpenSearchSQLRestTestCase.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,9 @@ protected static void configureHttpsClient(
311311
* cluster.
312312
*/
313313
public void configureMultiClusters(String remote) throws IOException {
314-
initRemoteClient(remote);
314+
if (remoteClient == null) {
315+
initRemoteClient(remote);
316+
}
315317

316318
Request connectionRequest = new Request("PUT", "_cluster/settings");
317319
String connectionSetting =

integ-test/src/test/java/org/opensearch/sql/legacy/SQLIntegTestCase.java

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -210,19 +210,6 @@ protected synchronized void loadIndex(Index index, RestClient client) throws IOE
210210
createIndexByRestClient(client, indexName, mapping);
211211
loadDataByRestClient(client, indexName, dataSet);
212212
}
213-
// loadIndex() could directly return when isIndexExist()=true,
214-
// e.g. the index is created in the cluster but data hasn't been flushed.
215-
// We block loadIndex() until data loaded to resolve
216-
// https://github.com/opensearch-project/sql/issues/4261
217-
int countDown = 3; // 1500ms timeout
218-
while (countDown != 0 && getDocCount(client, indexName) == 0) {
219-
try {
220-
Thread.sleep(500);
221-
countDown--;
222-
} catch (InterruptedException e) {
223-
throw new IOException(e);
224-
}
225-
}
226213
}
227214

228215
protected synchronized void loadIndex(Index index) throws IOException {

integ-test/src/test/java/org/opensearch/sql/legacy/TestUtils.java

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,29 @@ public class TestUtils {
4646
*/
4747
public static void createIndexByRestClient(RestClient client, String indexName, String mapping) {
4848
Request request = new Request("PUT", "/" + indexName);
49-
if (!isNullOrEmpty(mapping)) {
50-
request.setJsonEntity(mapping);
51-
}
49+
JSONObject jsonObject = isNullOrEmpty(mapping) ? new JSONObject() : new JSONObject(mapping);
50+
setZeroReplicas(jsonObject);
51+
request.setJsonEntity(jsonObject.toString());
5252
performRequest(client, request);
5353
}
5454

55+
/**
56+
* Sets number_of_replicas to 0 in the index settings. This makes multi-node behavior consistent
57+
* (<a href="https://github.com/opensearch-project/sql/issues/4261">4261</a>) and prevents tests
58+
* from hanging on single-node clusters when using wait_for_active_shards=all.
59+
*
60+
* @param jsonObject the index creation JSON object to modify
61+
*/
62+
private static void setZeroReplicas(JSONObject jsonObject) {
63+
JSONObject settings =
64+
jsonObject.has("settings") ? jsonObject.getJSONObject("settings") : new JSONObject();
65+
JSONObject indexSettings =
66+
settings.has("index") ? settings.getJSONObject("index") : new JSONObject();
67+
indexSettings.put("number_of_replicas", 0);
68+
settings.put("index", indexSettings);
69+
jsonObject.put("settings", settings);
70+
}
71+
5572
/**
5673
* https://github.com/elastic/elasticsearch/pull/49959<br>
5774
* Deprecate creation of dot-prefixed index names except for hidden and system indices. Create
@@ -99,7 +116,8 @@ public static boolean isIndexExist(RestClient client, String indexName) {
99116
public static void loadDataByRestClient(
100117
RestClient client, String indexName, String dataSetFilePath) throws IOException {
101118
Path path = Paths.get(getResourceFilePath(dataSetFilePath));
102-
Request request = new Request("POST", "/" + indexName + "/_bulk?refresh=true");
119+
Request request =
120+
new Request("POST", "/" + indexName + "/_bulk?refresh=wait_for&wait_for_active_shards=all");
103121
request.setJsonEntity(new String(Files.readAllBytes(path)));
104122
performRequest(client, request);
105123
}

integ-test/src/test/java/org/opensearch/sql/security/CalciteCrossClusterSearchIT.java

Lines changed: 30 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,6 @@
55

66
package org.opensearch.sql.security;
77

8-
import static org.opensearch.sql.legacy.TestsConstants.TEST_INDEX_ACCOUNT;
9-
import static org.opensearch.sql.legacy.TestsConstants.TEST_INDEX_BANK;
10-
import static org.opensearch.sql.legacy.TestsConstants.TEST_INDEX_DOG;
118
import static org.opensearch.sql.util.MatcherUtils.columnName;
129
import static org.opensearch.sql.util.MatcherUtils.rows;
1310
import static org.opensearch.sql.util.MatcherUtils.schema;
@@ -16,51 +13,21 @@
1613
import static org.opensearch.sql.util.MatcherUtils.verifySchema;
1714

1815
import java.io.IOException;
19-
import lombok.SneakyThrows;
2016
import org.json.JSONObject;
21-
import org.junit.jupiter.api.BeforeEach;
22-
import org.junit.jupiter.api.Test;
23-
import org.opensearch.sql.ppl.PPLIntegTestCase;
17+
import org.junit.Test;
2418

2519
/** Cross Cluster Search tests with Calcite enabled for enhanced fields features. */
26-
public class CalciteCrossClusterSearchIT extends PPLIntegTestCase {
27-
28-
static {
29-
String[] clusterNames = System.getProperty("cluster.names").split(",");
30-
var remote = "remoteCluster";
31-
for (var cluster : clusterNames) {
32-
if (cluster.startsWith("remote")) {
33-
remote = cluster;
34-
break;
35-
}
36-
}
37-
REMOTE_CLUSTER = remote;
38-
}
39-
40-
public static final String REMOTE_CLUSTER;
41-
private static final String TEST_INDEX_ACCOUNT_REMOTE = REMOTE_CLUSTER + ":" + TEST_INDEX_ACCOUNT;
42-
private static final String TEST_INDEX_DOG_REMOTE = REMOTE_CLUSTER + ":" + TEST_INDEX_DOG;
43-
private static final String TEST_INDEX_BANK_REMOTE = REMOTE_CLUSTER + ":" + TEST_INDEX_BANK;
44-
private static boolean initialized = false;
45-
46-
@SneakyThrows
47-
@BeforeEach
48-
public void initialize() {
49-
if (!initialized) {
50-
setUpIndices();
51-
initialized = true;
52-
}
53-
}
20+
public class CalciteCrossClusterSearchIT extends CrossClusterTestBase {
5421

5522
@Override
5623
protected void init() throws Exception {
57-
configureMultiClusters(REMOTE_CLUSTER);
24+
super.init();
5825
loadIndex(Index.BANK);
5926
loadIndex(Index.BANK, remoteClient());
60-
loadIndex(Index.ACCOUNT);
61-
loadIndex(Index.ACCOUNT, remoteClient());
6227
loadIndex(Index.DOG);
6328
loadIndex(Index.DOG, remoteClient());
29+
loadIndex(Index.ACCOUNT);
30+
loadIndex(Index.ACCOUNT, remoteClient());
6431
loadIndex(Index.TIME_TEST_DATA);
6532
loadIndex(Index.TIME_TEST_DATA, remoteClient());
6633
enableCalcite();
@@ -87,8 +54,8 @@ public void testCrossClusterFieldsWildcardPrefix() throws IOException {
8754
public void testCrossClusterFieldsWildcardSuffix() throws IOException {
8855
JSONObject result =
8956
executeQuery(String.format("search source=%s | fields *Name", TEST_INDEX_DOG_REMOTE));
90-
verifyColumn(result, columnName("dog_name"), columnName("holdersName"));
91-
verifySchema(result, schema("dog_name", "string"), schema("holdersName", "string"));
57+
verifyColumn(result, columnName("holdersName"));
58+
verifySchema(result, schema("holdersName", "string"));
9259
}
9360

9461
@Test
@@ -165,7 +132,7 @@ public void testDefaultBinCrossCluster() throws IOException {
165132
TEST_INDEX_ACCOUNT_REMOTE));
166133
verifySchema(result, schema("count()", null, "bigint"), schema("age", null, "string"));
167134

168-
verifyDataRows(result, rows(451L, "20-30"), rows(504L, "30-40"), rows(45L, "40-50"));
135+
verifyDataRows(result, rows(451, "20.0-30.0"), rows(504L, "30.0-40.0"), rows(45L, "40.0-50.0"));
169136
}
170137

171138
@Test
@@ -218,18 +185,18 @@ public void testRangeBinCrossCluster() throws IOException {
218185
TEST_INDEX_ACCOUNT_REMOTE));
219186
verifySchema(result, schema("count()", null, "bigint"), schema("age", null, "string"));
220187

221-
verifyDataRows(result, rows(1000L, "0-100"));
188+
verifyDataRows(result, rows(451, "20-30"), rows(504L, "30-40"), rows(45L, "40-50"));
222189
}
223190

224191
@Test
225192
public void testTimeBinCrossCluster() throws IOException {
226193
// Time-based binning with span
227194
JSONObject result =
228195
executeQuery(
229-
REMOTE_CLUSTER
230-
+ ":opensearch-sql_test_index_time_data"
231-
+ " | bin @timestamp span=1h"
232-
+ " | fields `@timestamp`, value | sort `@timestamp` | head 3");
196+
String.format(
197+
"source=%s | bin @timestamp span=1h | fields `@timestamp`, value | sort"
198+
+ " `@timestamp` | head 3",
199+
TEST_INDEX_TIME_DATA_REMOTE));
233200
verifySchema(result, schema("@timestamp", null, "timestamp"), schema("value", null, "int"));
234201

235202
// With 1-hour spans
@@ -285,12 +252,27 @@ public void testCrossClusterRenameFullWildcard() throws IOException {
285252
JSONObject result =
286253
executeQuery(String.format("search source=%s | rename * as old_*", TEST_INDEX_DOG_REMOTE));
287254
verifyColumn(
288-
result, columnName("old_dog_name"), columnName("old_holdersName"), columnName("old_age"));
255+
result,
256+
columnName("old_dog_name"),
257+
columnName("old_holdersName"),
258+
columnName("old_age"),
259+
columnName("old__id"),
260+
columnName("old__index"),
261+
columnName("old__score"),
262+
columnName("old__maxscore"),
263+
columnName("old__sort"),
264+
columnName("old__routing"));
289265
verifySchema(
290266
result,
291267
schema("old_dog_name", "string"),
292268
schema("old_holdersName", "string"),
293-
schema("old_age", "bigint"));
269+
schema("old_age", "bigint"),
270+
schema("old__id", "string"),
271+
schema("old__index", "string"),
272+
schema("old__score", "float"),
273+
schema("old__maxscore", "float"),
274+
schema("old__sort", "bigint"),
275+
schema("old__routing", "string"));
294276
}
295277

296278
@Test

0 commit comments

Comments
 (0)