From d41d94e3d196e174db1d63321108f138a029b972 Mon Sep 17 00:00:00 2001 From: Surya Sashank Nistala Date: Wed, 12 Apr 2023 10:43:56 -0700 Subject: [PATCH] handle index not exists for detector search and delete Signed-off-by: Surya Sashank Nistala --- .../TransportDeleteDetectorAction.java | 27 ++++++++++++++--- .../TransportSearchDetectorAction.java | 19 +++++++++++- .../securityanalytics/util/DetectorUtils.java | 29 +++++++++++++++---- .../resthandler/DetectorRestApiIT.java | 24 +++++++++++++++ 4 files changed, 89 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/opensearch/securityanalytics/transport/TransportDeleteDetectorAction.java b/src/main/java/org/opensearch/securityanalytics/transport/TransportDeleteDetectorAction.java index 5e7d91d6f..454dd2208 100644 --- a/src/main/java/org/opensearch/securityanalytics/transport/TransportDeleteDetectorAction.java +++ b/src/main/java/org/opensearch/securityanalytics/transport/TransportDeleteDetectorAction.java @@ -40,6 +40,7 @@ import org.opensearch.securityanalytics.action.DeleteDetectorResponse; import org.opensearch.securityanalytics.mapper.IndexTemplateManager; import org.opensearch.securityanalytics.model.Detector; +import org.opensearch.securityanalytics.util.DetectorIndices; import org.opensearch.securityanalytics.util.RuleTopicIndices; import org.opensearch.securityanalytics.util.SecurityAnalyticsException; import org.opensearch.tasks.Task; @@ -63,19 +64,22 @@ public class TransportDeleteDetectorAction extends HandledTransportAction listener) { - AsyncDeleteDetectorAction asyncAction = new AsyncDeleteDetectorAction(task, request, listener); + AsyncDeleteDetectorAction asyncAction = new AsyncDeleteDetectorAction(task, request, listener, detectorIndices); asyncAction.start(); } @@ -96,17 +100,31 @@ class AsyncDeleteDetectorAction { private final ActionListener listener; private final AtomicReference response; private final AtomicBoolean counter = new AtomicBoolean(); + private final DetectorIndices detectorIndices; private final Task task; - AsyncDeleteDetectorAction(Task task, DeleteDetectorRequest request, ActionListener listener) { + AsyncDeleteDetectorAction( + Task task, + DeleteDetectorRequest request, + ActionListener listener, + DetectorIndices detectorIndices) { this.task = task; this.request = request; this.listener = listener; - this.response = new AtomicReference<>(); + this.detectorIndices = detectorIndices; } void start() { + if (!detectorIndices.detectorIndexExists()) { + onFailures(new OpenSearchStatusException( + String.format(Locale.getDefault(), + "Detector with %s is not found", + request.getDetectorId()), + RestStatus.NOT_FOUND)); + return; + + } TransportDeleteDetectorAction.this.threadPool.getThreadContext().stashContext(); String detectorId = request.getDetectorId(); GetRequest getRequest = new GetRequest(Detector.DETECTORS_INDEX, detectorId); @@ -204,6 +222,7 @@ private void onOperation(DeleteResponse response) { } private void onFailures(Exception t) { + log.error(String.format(Locale.ROOT, "Failed to delete detector")); if (counter.compareAndSet(false, true)) { finishHim(null, t); } diff --git a/src/main/java/org/opensearch/securityanalytics/transport/TransportSearchDetectorAction.java b/src/main/java/org/opensearch/securityanalytics/transport/TransportSearchDetectorAction.java index 41f7917af..a46952cc6 100644 --- a/src/main/java/org/opensearch/securityanalytics/transport/TransportSearchDetectorAction.java +++ b/src/main/java/org/opensearch/securityanalytics/transport/TransportSearchDetectorAction.java @@ -7,9 +7,13 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.apache.lucene.search.TotalHits; +import org.opensearch.OpenSearchStatusException; import org.opensearch.action.ActionListener; import org.opensearch.action.search.SearchResponse; +import org.opensearch.action.search.SearchResponseSections; +import org.opensearch.action.search.ShardSearchFailure; import org.opensearch.action.support.ActionFilters; import org.opensearch.action.support.HandledTransportAction; import org.opensearch.commons.authuser.User; @@ -20,6 +24,12 @@ import org.opensearch.cluster.service.ClusterService; import org.opensearch.core.xcontent.NamedXContentRegistry; import org.opensearch.rest.RestStatus; +import org.opensearch.search.SearchHit; +import org.opensearch.search.SearchHits; +import org.opensearch.search.aggregations.InternalAggregations; +import org.opensearch.search.internal.InternalSearchResponse; +import org.opensearch.search.profile.SearchProfileShardResults; +import org.opensearch.search.suggest.Suggest; import org.opensearch.securityanalytics.action.SearchDetectorAction; import org.opensearch.securityanalytics.action.SearchDetectorRequest; import org.opensearch.securityanalytics.settings.SecurityAnalyticsSettings; @@ -30,7 +40,11 @@ import org.opensearch.transport.TransportService; +import java.util.Collections; +import java.util.Locale; + import static org.opensearch.rest.RestStatus.OK; +import static org.opensearch.securityanalytics.util.DetectorUtils.getEmptySearchResponse; public class TransportSearchDetectorAction extends HandledTransportAction implements SecureTransportAction { @@ -78,7 +92,10 @@ protected void doExecute(Task task, SearchDetectorRequest searchDetectorRequest, } this.threadPool.getThreadContext().stashContext(); - + if (!detectorIndices.detectorIndexExists()) { + actionListener.onResponse(getEmptySearchResponse()); + return; + } client.search(searchDetectorRequest.searchRequest(), new ActionListener<>() { @Override public void onResponse(SearchResponse response) { diff --git a/src/main/java/org/opensearch/securityanalytics/util/DetectorUtils.java b/src/main/java/org/opensearch/securityanalytics/util/DetectorUtils.java index 49864e6cf..4a60a8fcb 100644 --- a/src/main/java/org/opensearch/securityanalytics/util/DetectorUtils.java +++ b/src/main/java/org/opensearch/securityanalytics/util/DetectorUtils.java @@ -4,30 +4,49 @@ */ package org.opensearch.securityanalytics.util; -import java.io.IOException; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Set; +import org.apache.lucene.search.TotalHits; import org.opensearch.action.ActionListener; import org.opensearch.action.search.SearchRequest; import org.opensearch.action.search.SearchResponse; +import org.opensearch.action.search.ShardSearchFailure; import org.opensearch.client.Client; import org.opensearch.common.xcontent.LoggingDeprecationHandler; import org.opensearch.common.xcontent.XContentType; import org.opensearch.core.xcontent.NamedXContentRegistry; import org.opensearch.core.xcontent.XContentParser; import org.opensearch.search.SearchHit; +import org.opensearch.search.SearchHits; +import org.opensearch.search.aggregations.InternalAggregations; import org.opensearch.search.builder.SearchSourceBuilder; import org.opensearch.search.fetch.subphase.FetchSourceContext; +import org.opensearch.search.internal.InternalSearchResponse; +import org.opensearch.search.profile.SearchProfileShardResults; +import org.opensearch.search.suggest.Suggest; import org.opensearch.securityanalytics.model.Detector; import org.opensearch.securityanalytics.model.DetectorInput; +import java.io.IOException; +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + public class DetectorUtils { public static final String DETECTOR_TYPE_PATH = "detector.detector_type"; public static final String DETECTOR_ID_FIELD = "detector_id"; + public static SearchResponse getEmptySearchResponse() { + return new SearchResponse(new InternalSearchResponse( + new SearchHits(new SearchHit[0], new TotalHits(0L, TotalHits.Relation.EQUAL_TO), 0.0f), + InternalAggregations.from(Collections.emptyList()), + new Suggest(Collections.emptyList()), + new SearchProfileShardResults(Collections.emptyMap()), false, false, 0), + "", 0, 0, 0, 0, + ShardSearchFailure.EMPTY_ARRAY, SearchResponse.Clusters.EMPTY); + } + public static List getDetectors(SearchResponse response, NamedXContentRegistry xContentRegistry) throws IOException { List detectors = new LinkedList<>(); for (SearchHit hit : response.getHits()) { diff --git a/src/test/java/org/opensearch/securityanalytics/resthandler/DetectorRestApiIT.java b/src/test/java/org/opensearch/securityanalytics/resthandler/DetectorRestApiIT.java index 2a54d2e80..5c16c5d8f 100644 --- a/src/test/java/org/opensearch/securityanalytics/resthandler/DetectorRestApiIT.java +++ b/src/test/java/org/opensearch/securityanalytics/resthandler/DetectorRestApiIT.java @@ -122,6 +122,30 @@ public void testCreatingADetector() throws IOException { Assert.assertEquals(5, noOfSigmaRuleMatches); } + @SuppressWarnings("unchecked") + public void test_searchDetectors_detectorsIndexNotExists() throws IOException { + try { + makeRequest(client(), "DELETE", SecurityAnalyticsPlugin.DETECTOR_BASE_URI + "/" + "d1", Collections.emptyMap(), null); + fail("delete detector call should have failed"); + } catch (IOException e) { + assertTrue(e.getMessage().contains("not found")); + } + String request = "{\n" + + " \"query\" : {\n" + + " \"match_all\":{\n" + + " }\n" + + " }\n" + + "}"; + HttpEntity requestEntity = new StringEntity(request, ContentType.APPLICATION_JSON); + Response searchResponse = makeRequest(client(), "POST", SecurityAnalyticsPlugin.DETECTOR_BASE_URI + "/" + "_search", Collections.emptyMap(), requestEntity); + Map searchResponseBody = asMap(searchResponse); + Assert.assertNotNull("response is not null", searchResponseBody); + Map searchResponseHits = (Map) searchResponseBody.get("hits"); + Map searchResponseTotal = (Map) searchResponseHits.get("total"); + Assert.assertEquals(0, searchResponseTotal.get("value")); + } + + public void testCreatingADetectorWithMultipleIndices() throws IOException { String index1 = createTestIndex("windows-1", windowsIndexMapping()); String index2 = createTestIndex("windows-2", windowsIndexMapping());