Skip to content

Commit 9b371ba

Browse files
committed
add more IT
Signed-off-by: Jackie Han <hnyng@amazon.com>
1 parent edee31c commit 9b371ba

File tree

4 files changed

+147
-39
lines changed

4 files changed

+147
-39
lines changed

src/main/java/org/opensearch/timeseries/indices/IndexManagement.java

+28-25
Original file line numberDiff line numberDiff line change
@@ -1020,36 +1020,39 @@ public <T> void initCustomResultIndexAndExecute(String resultIndexOrAlias, Execu
10201020
* creates flattened result index
10211021
* @param flattenedResultIndexAlias the flattened result index alias
10221022
* @param actionListener the action listener
1023-
* @throws IOException
10241023
*/
1025-
public void initFlattenedResultIndex(String flattenedResultIndexAlias, ActionListener<CreateIndexResponse> actionListener)
1026-
throws IOException {
1027-
String indexName = getCustomResultIndexPattern(flattenedResultIndexAlias);
1028-
logger.info("Initializing flattened result index: {}", indexName);
1024+
public void initFlattenedResultIndex(String flattenedResultIndexAlias, ActionListener<CreateIndexResponse> actionListener) {
1025+
try {
1026+
String indexName = getCustomResultIndexPattern(flattenedResultIndexAlias);
1027+
logger.info("Initializing flattened result index: {}", indexName);
10291028

1030-
CreateIndexRequest request = new CreateIndexRequest(indexName)
1031-
.mapping(getFlattenedResultMappings(), XContentType.JSON)
1032-
.settings(settings);
1029+
CreateIndexRequest request = new CreateIndexRequest(indexName)
1030+
.mapping(getFlattenedResultMappings(), XContentType.JSON)
1031+
.settings(settings);
10331032

1034-
if (flattenedResultIndexAlias != null) {
1035-
request.alias(new Alias(flattenedResultIndexAlias));
1036-
}
1033+
if (flattenedResultIndexAlias != null) {
1034+
request.alias(new Alias(flattenedResultIndexAlias));
1035+
}
10371036

1038-
choosePrimaryShards(request, false);
1037+
choosePrimaryShards(request, false);
10391038

1040-
adminClient.indices().create(request, ActionListener.wrap(response -> {
1041-
if (response.isAcknowledged()) {
1042-
logger.info("Successfully created flattened result index: {} with alias: {}", indexName, flattenedResultIndexAlias);
1043-
actionListener.onResponse(response);
1044-
} else {
1045-
String errorMsg = "Index creation not acknowledged for index: " + indexName;
1046-
logger.error(errorMsg);
1047-
actionListener.onFailure(new IllegalStateException(errorMsg));
1048-
}
1049-
}, exception -> {
1050-
logger.error("Failed to create flattened result index: {}", indexName, exception);
1051-
actionListener.onFailure(exception);
1052-
}));
1039+
adminClient.indices().create(request, ActionListener.wrap(response -> {
1040+
if (response.isAcknowledged()) {
1041+
logger.info("Successfully created flattened result index: {} with alias: {}", indexName, flattenedResultIndexAlias);
1042+
actionListener.onResponse(response);
1043+
} else {
1044+
String errorMsg = "Index creation not acknowledged for index: " + indexName;
1045+
logger.error(errorMsg);
1046+
actionListener.onFailure(new IllegalStateException(errorMsg));
1047+
}
1048+
}, exception -> {
1049+
logger.error("Failed to create flattened result index: {}", indexName, exception);
1050+
actionListener.onFailure(exception);
1051+
}));
1052+
} catch (Exception e) {
1053+
logger.error("Error while initializing flattened result index: {}", flattenedResultIndexAlias, e);
1054+
actionListener.onFailure(e);
1055+
}
10531056
}
10541057

10551058
public String getFlattenedResultIndexAlias(String indexOrAliasName, String configId) {

src/main/java/org/opensearch/timeseries/rest/handler/AbstractTimeSeriesActionHandler.java

+27-14
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@
3939
import org.opensearch.action.support.WriteRequest;
4040
import org.opensearch.action.support.master.AcknowledgedResponse;
4141
import org.opensearch.action.support.replication.ReplicationResponse;
42-
import org.opensearch.ad.transport.IndexAnomalyDetectorResponse;
4342
import org.opensearch.client.Client;
4443
import org.opensearch.cluster.service.ClusterService;
4544
import org.opensearch.common.settings.Settings;
@@ -456,16 +455,14 @@ protected void prepareConfigIndexing(boolean indexingDryRun, ActionListener<T> l
456455

457456
private void handlePutRequest(boolean indexingDryRun, ActionListener<T> listener) {
458457
handler.confirmJobRunning(clusterService, client, id, listener, () -> {
459-
handleFlattenResultIndexMappingUpdate(listener);
460458
updateConfig(id, indexingDryRun, listener);
461459
}, xContentRegistry);
462460
}
463461

464462
private void handlePostRequest(boolean indexingDryRun, ActionListener<T> listener) {
465463
createConfig(indexingDryRun, ActionListener.wrap(createConfigResponse -> {
466-
if (shouldHandleFlattening(indexingDryRun, createConfigResponse)) {
467-
IndexAnomalyDetectorResponse response = (IndexAnomalyDetectorResponse) createConfigResponse;
468-
String configId = response.getId();
464+
if (shouldHandleFlattening(indexingDryRun)) {
465+
String configId = RestHandlerUtils.getConfigIdFromIndexResponse(createConfigResponse);
469466
String flattenedResultIndexAlias = timeSeriesIndices
470467
.getFlattenedResultIndexAlias(config.getCustomResultIndexOrAlias(), configId);
471468
String pipelineId = timeSeriesIndices.getFlattenResultIndexIngestPipelineId(configId);
@@ -487,13 +484,10 @@ private void handlePostRequest(boolean indexingDryRun, ActionListener<T> listene
487484
}, listener::onFailure));
488485
}
489486

490-
private boolean shouldHandleFlattening(boolean indexingDryRun, Object createConfigResponse) {
487+
private boolean shouldHandleFlattening(boolean indexingDryRun) {
491488
Boolean flattenResultIndexMapping = config.getFlattenResultIndexMapping();
492489

493-
return !indexingDryRun
494-
&& config.getCustomResultIndexOrAlias() != null
495-
&& Boolean.TRUE.equals(flattenResultIndexMapping)
496-
&& createConfigResponse instanceof IndexAnomalyDetectorResponse;
490+
return !indexingDryRun && config.getCustomResultIndexOrAlias() != null && Boolean.TRUE.equals(flattenResultIndexMapping);
497491
}
498492

499493
protected void setupIngestPipeline(String configId, ActionListener<T> listener) {
@@ -574,13 +568,13 @@ protected void updateResultIndexSetting(String pipelineId, String flattenedResul
574568
}));
575569
}
576570

577-
private void handleFlattenResultIndexMappingUpdate(ActionListener<T> listener) {
571+
private void handleFlattenResultIndexMappingUpdate(Config existingConfig, ActionListener<T> listener) {
578572
if (config.getCustomResultIndexOrAlias() == null) {
579573
return;
580574
}
581-
if (config.getFlattenResultIndexMapping() != null && config.getFlattenResultIndexMapping()) {
582-
setupIngestPipeline(id, listener);
583-
} else {
575+
if (Boolean.TRUE.equals(existingConfig.getFlattenResultIndexMapping())
576+
&& Boolean.FALSE.equals(config.getFlattenResultIndexMapping())
577+
&& existingConfig.getCustomResultIndexOrAlias() != null) {
584578
String pipelineId = timeSeriesIndices.getFlattenResultIndexIngestPipelineId(config.getId());
585579
client.admin().cluster().deletePipeline(new DeletePipelineRequest(pipelineId), new ActionListener<AcknowledgedResponse>() {
586580

@@ -611,6 +605,24 @@ public void onFailure(Exception e) {
611605
}
612606
}
613607
});
608+
} else if (Boolean.FALSE.equals(existingConfig.getFlattenResultIndexMapping())
609+
&& Boolean.TRUE.equals(config.getFlattenResultIndexMapping())
610+
&& existingConfig.getCustomResultIndexOrAlias() != null
611+
) {
612+
String flattenedResultIndexAlias = timeSeriesIndices
613+
.getFlattenedResultIndexAlias(config.getCustomResultIndexOrAlias(), config.getId());
614+
String pipelineId = timeSeriesIndices.getFlattenResultIndexIngestPipelineId(config.getId());
615+
timeSeriesIndices
616+
.initFlattenedResultIndex(
617+
flattenedResultIndexAlias,
618+
ActionListener.wrap(initResponse -> setupIngestPipeline(config.getId(), ActionListener.wrap(pipelineResponse -> {
619+
updateResultIndexSetting(
620+
pipelineId,
621+
flattenedResultIndexAlias,
622+
ActionListener.wrap(updateResponse -> listener.onResponse(updateResponse), listener::onFailure)
623+
);
624+
}, listener::onFailure)), listener::onFailure)
625+
);
614626
}
615627
}
616628

@@ -661,6 +673,7 @@ private void onGetConfigResponse(GetResponse response, boolean indexingDryRun, S
661673
breakingUIChange = true;
662674
}
663675
}
676+
handleFlattenResultIndexMappingUpdate(existingConfig, listener);
664677

665678
ActionListener<Void> confirmBatchRunningListener = ActionListener
666679
.wrap(

src/main/java/org/opensearch/timeseries/util/RestHandlerUtils.java

+20
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,20 @@
2626
import org.opensearch.OpenSearchStatusException;
2727
import org.opensearch.action.search.SearchPhaseExecutionException;
2828
import org.opensearch.action.search.ShardSearchFailure;
29+
import org.opensearch.ad.transport.IndexAnomalyDetectorResponse;
2930
import org.opensearch.common.Nullable;
3031
import org.opensearch.common.xcontent.LoggingDeprecationHandler;
3132
import org.opensearch.common.xcontent.XContentHelper;
3233
import org.opensearch.common.xcontent.XContentType;
3334
import org.opensearch.core.action.ActionListener;
35+
import org.opensearch.core.action.ActionResponse;
3436
import org.opensearch.core.common.Strings;
3537
import org.opensearch.core.common.bytes.BytesReference;
3638
import org.opensearch.core.rest.RestStatus;
3739
import org.opensearch.core.xcontent.NamedXContentRegistry;
3840
import org.opensearch.core.xcontent.ToXContent;
3941
import org.opensearch.core.xcontent.XContentParser;
42+
import org.opensearch.forecast.transport.IndexForecasterResponse;
4043
import org.opensearch.index.IndexNotFoundException;
4144
import org.opensearch.indices.InvalidIndexNameException;
4245
import org.opensearch.rest.RestChannel;
@@ -290,4 +293,21 @@ public static Entity buildEntity(RestRequest request, String detectorId) throws
290293
// not a valid profile request with correct entity information
291294
return null;
292295
}
296+
297+
public static String getConfigIdFromIndexResponse(ActionResponse actionResponse) {
298+
String configId;
299+
if (actionResponse instanceof IndexAnomalyDetectorResponse) {
300+
IndexAnomalyDetectorResponse response = (IndexAnomalyDetectorResponse) actionResponse;
301+
configId = response.getId();
302+
logger.info("Handling IndexAnomalyDetectorResponse for configId: {}", configId);
303+
} else if (actionResponse instanceof IndexForecasterResponse) {
304+
IndexForecasterResponse response = (IndexForecasterResponse) actionResponse;
305+
configId = response.getId();
306+
logger.info("Handling IndexForecasterResponse for configId: {}", configId);
307+
} else {
308+
throw new IllegalStateException("Unexpected response type: " + actionResponse.getClass().getName());
309+
}
310+
return configId;
311+
}
312+
293313
}

src/test/java/org/opensearch/ad/rest/AnomalyDetectorRestApiIT.java

+72
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,78 @@ public void testUpdateAnomalyDetector_disableFlattenResultIndex_shouldDeletePipe
331331
assertEquals("Expected 404 response but got: " + statusCode, 404, statusCode);
332332
}
333333

334+
public void testUpdateAnomalyDetector_enableFlattenResultIndex_shouldCreatePipeline() throws Exception {
335+
AnomalyDetector detector = createIndexAndGetAnomalyDetector(
336+
INDEX_NAME,
337+
ImmutableList.of(TestHelpers.randomFeature("feature_bytes", "agg", true)),
338+
false,
339+
false
340+
);
341+
// test behavior when AD is enabled
342+
updateClusterSettings(ADEnabledSetting.AD_ENABLED, true);
343+
// create a detector with flatten result index disabled, shouldn't find related ingest pipeline
344+
Response response = TestHelpers
345+
.makeRequest(client(), "POST", TestHelpers.AD_BASE_DETECTORS_URI, ImmutableMap.of(), TestHelpers.toHttpEntity(detector), null);
346+
assertEquals("Create anomaly detector without flattened result index failed", RestStatus.CREATED, TestHelpers.restStatus(response));
347+
Map<String, Object> responseMap = entityAsMap(response);
348+
String id = (String) responseMap.get("_id");
349+
String expectedPipelineId = String.format(Locale.ROOT, "flatten_result_index_ingest_pipeline%s", id.toLowerCase(Locale.ROOT));
350+
String getIngestPipelineEndpoint = String.format(Locale.ROOT, "_ingest/pipeline/%s", expectedPipelineId);
351+
ResponseException responseException = expectThrows(
352+
ResponseException.class,
353+
() -> TestHelpers.makeRequest(client(), "GET", getIngestPipelineEndpoint, ImmutableMap.of(), "", null)
354+
);
355+
int statusCode = responseException.getResponse().getStatusLine().getStatusCode();
356+
assertEquals("Expected 404 response but got: " + statusCode, 404, statusCode);
357+
// update the detector with flatten result index enabled, should be able to find ingest pipeline
358+
List<Feature> features = detector.getFeatureAttributes();
359+
AnomalyDetector newDetector = new AnomalyDetector(
360+
id,
361+
detector.getVersion(),
362+
detector.getName(),
363+
detector.getDescription(),
364+
detector.getTimeField(),
365+
detector.getIndices(),
366+
features,
367+
detector.getFilterQuery(),
368+
detector.getInterval(),
369+
detector.getWindowDelay(),
370+
detector.getShingleSize(),
371+
detector.getUiMetadata(),
372+
detector.getSchemaVersion(),
373+
detector.getLastUpdateTime(),
374+
null,
375+
detector.getUser(),
376+
detector.getCustomResultIndexOrAlias(),
377+
TestHelpers.randomImputationOption(features),
378+
randomIntBetween(1, 10000),
379+
randomInt(TimeSeriesSettings.MAX_SHINGLE_SIZE / 2),
380+
randomIntBetween(1, 1000),
381+
null,
382+
null,
383+
null,
384+
null,
385+
true,
386+
detector.getLastBreakingUIChangeTime()
387+
);
388+
Response updateResponse = TestHelpers
389+
.makeRequest(
390+
client(),
391+
"PUT",
392+
TestHelpers.AD_BASE_DETECTORS_URI + "/" + id + "?refresh=true",
393+
ImmutableMap.of(),
394+
TestHelpers.toHttpEntity(newDetector),
395+
null
396+
);
397+
assertEquals("Update anomaly detector failed", RestStatus.OK, TestHelpers.restStatus(updateResponse));
398+
Response getPipelineResponse = TestHelpers.makeRequest(client(), "GET", getIngestPipelineEndpoint, ImmutableMap.of(), "", null);
399+
assertEquals(
400+
"Expected 200 response but got: " + getPipelineResponse.getStatusLine().getStatusCode(),
401+
200,
402+
getPipelineResponse.getStatusLine().getStatusCode()
403+
);
404+
}
405+
334406
public void testCreateAnomalyDetector() throws Exception {
335407
AnomalyDetector detector = createIndexAndGetAnomalyDetector(INDEX_NAME);
336408
updateClusterSettings(ADEnabledSetting.AD_ENABLED, false);

0 commit comments

Comments
 (0)